From e071a3f6c06f41068ad17134189a4ac3073ef76b Mon Sep 17 00:00:00 2001 From: sirius-m Date: Sun, 30 Aug 2009 03:46:39 +0000 Subject: [PATCH] First commit git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@1 1a98c847-1fd6-4fd8-948a-caf3550aa51b --- base58.h | 201 + bignum.h | 498 ++ db.cpp | 614 ++ db.h | 420 ++ headers.h | 71 + irc.cpp | 314 + irc.h | 10 + key.h | 156 + libeay32.dll | Bin 0 -> 1306630 bytes license.txt | 19 + main.cpp | 2692 ++++++++ main.h | 1329 ++++ makefile | 83 + makefile.vc | 77 + market.cpp | 264 + market.h | 182 + mingwm10.dll | Bin 0 -> 11673 bytes net.cpp | 1100 ++++ net.h | 856 +++ rc/addressbook16.bmp | Bin 0 -> 1334 bytes rc/addressbook16mask.bmp | Bin 0 -> 126 bytes rc/addressbook20.bmp | Bin 0 -> 1478 bytes rc/addressbook20mask.bmp | Bin 0 -> 142 bytes rc/bitcoin.ico | Bin 0 -> 22486 bytes rc/check.ico | Bin 0 -> 766 bytes rc/send16.bmp | Bin 0 -> 1334 bytes rc/send16mask.bmp | Bin 0 -> 126 bytes rc/send16masknoshadow.bmp | Bin 0 -> 126 bytes rc/send20.bmp | Bin 0 -> 1478 bytes rc/send20mask.bmp | Bin 0 -> 142 bytes readme.txt | 76 + script.cpp | 1127 ++++ script.h | 597 ++ serialize.h | 1158 ++++ sha.cpp | 554 ++ sha.h | 177 + ui.cpp | 3290 ++++++++++ ui.h | 420 ++ ui.rc | 14 + uibase.cpp | 1825 ++++++ uibase.h | 723 +++ uint256.h | 750 +++ uiproject.fbp | 11860 ++++++++++++++++++++++++++++++++++++ util.cpp | 383 ++ util.h | 399 ++ 45 files changed, 32239 insertions(+) create mode 100644 base58.h create mode 100644 bignum.h create mode 100644 db.cpp create mode 100644 db.h create mode 100644 headers.h create mode 100644 irc.cpp create mode 100644 irc.h create mode 100644 key.h create mode 100644 libeay32.dll create mode 100644 license.txt create mode 100644 main.cpp create mode 100644 main.h create mode 100644 makefile create mode 100644 makefile.vc create mode 100644 market.cpp create mode 100644 market.h create mode 100644 mingwm10.dll create mode 100644 net.cpp create mode 100644 net.h create mode 100644 rc/addressbook16.bmp create mode 100644 rc/addressbook16mask.bmp create mode 100644 rc/addressbook20.bmp create mode 100644 rc/addressbook20mask.bmp create mode 100644 rc/bitcoin.ico create mode 100644 rc/check.ico create mode 100644 rc/send16.bmp create mode 100644 rc/send16mask.bmp create mode 100644 rc/send16masknoshadow.bmp create mode 100644 rc/send20.bmp create mode 100644 rc/send20mask.bmp create mode 100644 readme.txt create mode 100644 script.cpp create mode 100644 script.h create mode 100644 serialize.h create mode 100644 sha.cpp create mode 100644 sha.h create mode 100644 ui.cpp create mode 100644 ui.h create mode 100644 ui.rc create mode 100644 uibase.cpp create mode 100644 uibase.h create mode 100644 uint256.h create mode 100644 uiproject.fbp create mode 100644 util.cpp create mode 100644 util.h diff --git a/base58.h b/base58.h new file mode 100644 index 000000000..69f40bd20 --- /dev/null +++ b/base58.h @@ -0,0 +1,201 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + + +// +// Why base-58 instead of standard base-64 encoding? +// - Don't want 0OIl characters that look the same in some fonts and +// could be used to create visually identical looking account numbers. +// - A string with non-alphanumeric characters is not as easily accepted as an account number. +// - E-mail usually won't line-break if there's no punctuation to break at. +// - Doubleclicking selects the whole number as one word if it's all alphanumeric. +// + + +static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + + +inline string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) +{ + CAutoBN_CTX pctx; + CBigNum bn58 = 58; + CBigNum bn0 = 0; + + // Convert big endian data to little endian + // Extra zero at the end make sure bignum will interpret as a positive number + vector vchTmp(pend-pbegin+1, 0); + reverse_copy(pbegin, pend, vchTmp.begin()); + + // Convert little endian data to bignum + CBigNum bn; + bn.setvch(vchTmp); + + // Convert bignum to string + string str; + str.reserve((pend - pbegin) * 138 / 100 + 1); + CBigNum dv; + CBigNum rem; + while (bn > bn0) + { + if (!BN_div(&dv, &rem, &bn, &bn58, pctx)) + throw bignum_error("EncodeBase58 : BN_div failed"); + bn = dv; + unsigned int c = rem.getulong(); + str += pszBase58[c]; + } + + // Leading zeroes encoded as base58 zeros + for (const unsigned char* p = pbegin; p < pend && *p == 0; p++) + str += pszBase58[0]; + + // Convert little endian string to big endian + reverse(str.begin(), str.end()); + return str; +} + +inline string EncodeBase58(const vector& vch) +{ + return EncodeBase58(&vch[0], &vch[0] + vch.size()); +} + +inline bool DecodeBase58(const char* psz, vector& vchRet) +{ + CAutoBN_CTX pctx; + vchRet.clear(); + CBigNum bn58 = 58; + CBigNum bn = 0; + CBigNum bnChar; + while (isspace(*psz)) + psz++; + + // Convert big endian string to bignum + for (const char* p = psz; *p; p++) + { + const char* p1 = strchr(pszBase58, *p); + if (p1 == NULL) + { + while (isspace(*p)) + p++; + if (*p != '\0') + return false; + break; + } + bnChar.setulong(p1 - pszBase58); + if (!BN_mul(&bn, &bn, &bn58, pctx)) + throw bignum_error("DecodeBase58 : BN_mul failed"); + bn += bnChar; + } + + // Get bignum as little endian data + vector vchTmp = bn.getvch(); + + // Trim off sign byte if present + if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80) + vchTmp.erase(vchTmp.end()-1); + + // Restore leading zeros + int nLeadingZeros = 0; + for (const char* p = psz; *p == pszBase58[0]; p++) + nLeadingZeros++; + vchRet.assign(nLeadingZeros + vchTmp.size(), 0); + + // Convert little endian data to big endian + reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); + return true; +} + +inline bool DecodeBase58(const string& str, vector& vchRet) +{ + return DecodeBase58(str.c_str(), vchRet); +} + + + + + +inline string EncodeBase58Check(const vector& vchIn) +{ + // add 4-byte hash check to the end + vector vch(vchIn); + uint256 hash = Hash(vch.begin(), vch.end()); + vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); + return EncodeBase58(vch); +} + +inline bool DecodeBase58Check(const char* psz, vector& vchRet) +{ + if (!DecodeBase58(psz, vchRet)) + return false; + if (vchRet.size() < 4) + { + vchRet.clear(); + return false; + } + uint256 hash = Hash(vchRet.begin(), vchRet.end()-4); + if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) + { + vchRet.clear(); + return false; + } + vchRet.resize(vchRet.size()-4); + return true; +} + +inline bool DecodeBase58Check(const string& str, vector& vchRet) +{ + return DecodeBase58Check(str.c_str(), vchRet); +} + + + + + + +static const unsigned char ADDRESSVERSION = 0; + +inline string Hash160ToAddress(uint160 hash160) +{ + // add 1-byte version number to the front + vector vch(1, ADDRESSVERSION); + vch.insert(vch.end(), UBEGIN(hash160), UEND(hash160)); + return EncodeBase58Check(vch); +} + +inline bool AddressToHash160(const char* psz, uint160& hash160Ret) +{ + vector vch; + if (!DecodeBase58Check(psz, vch)) + return false; + if (vch.empty()) + return false; + unsigned char nVersion = vch[0]; + if (vch.size() != sizeof(hash160Ret) + 1) + return false; + memcpy(&hash160Ret, &vch[1], sizeof(hash160Ret)); + return (nVersion <= ADDRESSVERSION); +} + +inline bool AddressToHash160(const string& str, uint160& hash160Ret) +{ + return AddressToHash160(str.c_str(), hash160Ret); +} + +inline bool IsValidBitcoinAddress(const char* psz) +{ + uint160 hash160; + return AddressToHash160(psz, hash160); +} + +inline bool IsValidBitcoinAddress(const string& str) +{ + return IsValidBitcoinAddress(str.c_str()); +} + + + + +inline string PubKeyToAddress(const vector& vchPubKey) +{ + return Hash160ToAddress(Hash160(vchPubKey)); +} diff --git a/bignum.h b/bignum.h new file mode 100644 index 000000000..8aa4e9c4f --- /dev/null +++ b/bignum.h @@ -0,0 +1,498 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + + + + + +class bignum_error : public std::runtime_error +{ +public: + explicit bignum_error(const std::string& str) : std::runtime_error(str) {} +}; + + + +class CAutoBN_CTX +{ +protected: + BN_CTX* pctx; + BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } + +public: + CAutoBN_CTX() + { + pctx = BN_CTX_new(); + if (pctx == NULL) + throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); + } + + ~CAutoBN_CTX() + { + if (pctx != NULL) + BN_CTX_free(pctx); + } + + operator BN_CTX*() { return pctx; } + BN_CTX& operator*() { return *pctx; } + BN_CTX** operator&() { return &pctx; } + bool operator!() { return (pctx == NULL); } +}; + + + +class CBigNum : public BIGNUM +{ +public: + CBigNum() + { + BN_init(this); + } + + CBigNum(const CBigNum& b) + { + BN_init(this); + if (!BN_copy(this, &b)) + { + BN_clear_free(this); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } + } + + explicit CBigNum(const std::string& str) + { + BN_init(this); + SetHex(str); + } + + CBigNum& operator=(const CBigNum& b) + { + if (!BN_copy(this, &b)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); + } + + ~CBigNum() + { + BN_clear_free(this); + } + + CBigNum(char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int64 n) { BN_init(this); setint64(n); } + CBigNum(unsigned char n) { BN_init(this); setulong(n); } + CBigNum(unsigned short n) { BN_init(this); setulong(n); } + CBigNum(unsigned int n) { BN_init(this); setulong(n); } + CBigNum(unsigned long n) { BN_init(this); setulong(n); } + CBigNum(uint64 n) { BN_init(this); setuint64(n); } + explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); } + + explicit CBigNum(const std::vector& vch) + { + BN_init(this); + setvch(vch); + } + + void setulong(unsigned long n) + { + if (!BN_set_word(this, n)) + throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); + } + + unsigned long getulong() const + { + return BN_get_word(this); + } + + unsigned int getuint() const + { + return BN_get_word(this); + } + + int getint() const + { + unsigned long n = BN_get_word(this); + if (!BN_is_negative(this)) + return (n > INT_MAX ? INT_MAX : n); + else + return (n > INT_MAX ? INT_MIN : -(int)n); + } + + void setint64(int64 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fNegative = false; + if (n < (int64)0) + { + n = -n; + fNegative = true; + } + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = (fNegative ? 0x80 : 0); + else if (fNegative) + c |= 0x80; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } + + void setuint64(uint64 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } + + void setuint256(uint256 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + unsigned char* pbegin = (unsigned char*)&n; + unsigned char* psrc = pbegin + sizeof(n); + while (psrc != pbegin) + { + unsigned char c = *(--psrc); + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize >> 0) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } + + uint256 getuint256() + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint256 n = 0; + for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((unsigned char*)&n)[i] = vch[j]; + return n; + } + + void setvch(const std::vector& vch) + { + std::vector vch2(vch.size() + 4); + unsigned int nSize = vch.size(); + vch2[0] = (nSize >> 24) & 0xff; + vch2[1] = (nSize >> 16) & 0xff; + vch2[2] = (nSize >> 8) & 0xff; + vch2[3] = (nSize >> 0) & 0xff; + reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); + BN_mpi2bn(&vch2[0], vch2.size(), this); + } + + std::vector getvch() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize < 4) + return std::vector(); + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + reverse(vch.begin(), vch.end()); + return vch; + } + + CBigNum& SetCompact(unsigned int nCompact) + { + unsigned int nSize = nCompact >> 24; + std::vector vch(4 + nSize); + vch[3] = nSize; + if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; + if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; + if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; + BN_mpi2bn(&vch[0], vch.size(), this); + return *this; + } + + unsigned int GetCompact() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + std::vector vch(nSize); + nSize -= 4; + BN_bn2mpi(this, &vch[0]); + unsigned int nCompact = nSize << 24; + if (nSize >= 1) nCompact |= (vch[4] << 16); + if (nSize >= 2) nCompact |= (vch[5] << 8); + if (nSize >= 3) nCompact |= (vch[6] << 0); + return nCompact; + } + + void SetHex(const std::string& str) + { + // skip 0x + const char* psz = str.c_str(); + while (isspace(*psz)) + psz++; + bool fNegative = false; + if (*psz == '-') + { + fNegative = true; + psz++; + } + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + while (isspace(*psz)) + psz++; + + // hex string to bignum + static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + *this = 0; + while (isxdigit(*psz)) + { + *this <<= 4; + int n = phexdigit[*psz++]; + *this += n; + } + if (fNegative) + *this = 0 - *this; + } + + unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const + { + return ::GetSerializeSize(getvch(), nType, nVersion); + } + + template + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const + { + ::Serialize(s, getvch(), nType, nVersion); + } + + template + void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) + { + vector vch; + ::Unserialize(s, vch, nType, nVersion); + setvch(vch); + } + + + bool operator!() const + { + return BN_is_zero(this); + } + + CBigNum& operator+=(const CBigNum& b) + { + if (!BN_add(this, this, &b)) + throw bignum_error("CBigNum::operator+= : BN_add failed"); + return *this; + } + + CBigNum& operator-=(const CBigNum& b) + { + *this = *this - b; + return *this; + } + + CBigNum& operator*=(const CBigNum& b) + { + CAutoBN_CTX pctx; + if (!BN_mul(this, this, &b, pctx)) + throw bignum_error("CBigNum::operator*= : BN_mul failed"); + return *this; + } + + CBigNum& operator/=(const CBigNum& b) + { + *this = *this / b; + return *this; + } + + CBigNum& operator%=(const CBigNum& b) + { + *this = *this % b; + return *this; + } + + CBigNum& operator<<=(unsigned int shift) + { + if (!BN_lshift(this, this, shift)) + throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); + return *this; + } + + CBigNum& operator>>=(unsigned int shift) + { + if (!BN_rshift(this, this, shift)) + throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); + return *this; + } + + + CBigNum& operator++() + { + // prefix operator + if (!BN_add(this, this, BN_value_one())) + throw bignum_error("CBigNum::operator++ : BN_add failed"); + return *this; + } + + const CBigNum operator++(int) + { + // postfix operator + const CBigNum ret = *this; + ++(*this); + return ret; + } + + CBigNum& operator--() + { + // prefix operator + CBigNum r; + if (!BN_sub(&r, this, BN_value_one())) + throw bignum_error("CBigNum::operator-- : BN_sub failed"); + *this = r; + return *this; + } + + const CBigNum operator--(int) + { + // postfix operator + const CBigNum ret = *this; + --(*this); + return ret; + } + + + friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); +}; + + + +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_add(&r, &a, &b)) + throw bignum_error("CBigNum::operator+ : BN_add failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_sub(&r, &a, &b)) + throw bignum_error("CBigNum::operator- : BN_sub failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a) +{ + CBigNum r(a); + BN_set_negative(&r, !BN_is_negative(&r)); + return r; +} + +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mul(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator* : BN_mul failed"); + return r; +} + +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_div(&r, NULL, &a, &b, pctx)) + throw bignum_error("CBigNum::operator/ : BN_div failed"); + return r; +} + +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mod(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator% : BN_div failed"); + return r; +} + +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) +{ + CBigNum r; + if (!BN_lshift(&r, &a, shift)) + throw bignum_error("CBigNum:operator<< : BN_lshift failed"); + return r; +} + +inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) +{ + CBigNum r; + if (!BN_rshift(&r, &a, shift)) + throw bignum_error("CBigNum:operator>> : BN_rshift failed"); + return r; +} + +inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); } +inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); } +inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); } +inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); } +inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); } +inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } diff --git a/db.cpp b/db.cpp new file mode 100644 index 000000000..f38f3ffad --- /dev/null +++ b/db.cpp @@ -0,0 +1,614 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" + + + + + + +// +// CDB +// + +static CCriticalSection cs_db; +static bool fDbEnvInit = false; +DbEnv dbenv(0); +static map mapFileUseCount; + +class CDBInit +{ +public: + CDBInit() + { + } + ~CDBInit() + { + if (fDbEnvInit) + { + dbenv.close(0); + fDbEnvInit = false; + } + } +} +instance_of_cdbinit; + + +CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) +{ + int ret; + if (pszFile == NULL) + return; + + bool fCreate = strchr(pszMode, 'c'); + bool fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); + unsigned int nFlags = DB_THREAD; + if (fCreate) + nFlags |= DB_CREATE; + else if (fReadOnly) + nFlags |= DB_RDONLY; + if (!fReadOnly || fTxn) + nFlags |= DB_AUTO_COMMIT; + + CRITICAL_BLOCK(cs_db) + { + if (!fDbEnvInit) + { + string strAppDir = GetAppDir(); + string strLogDir = strAppDir + "\\database"; + _mkdir(strLogDir.c_str()); + printf("dbenv.open strAppDir=%s\n", strAppDir.c_str()); + + dbenv.set_lg_dir(strLogDir.c_str()); + dbenv.set_lg_max(10000000); + dbenv.set_lk_max_locks(10000); + dbenv.set_lk_max_objects(10000); + dbenv.set_errfile(fopen("db.log", "a")); /// debug + ///dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); /// causes corruption + ret = dbenv.open(strAppDir.c_str(), + DB_CREATE | + DB_INIT_LOCK | + DB_INIT_LOG | + DB_INIT_MPOOL | + DB_INIT_TXN | + DB_THREAD | + DB_PRIVATE | + DB_RECOVER, + 0); + if (ret > 0) + throw runtime_error(strprintf("CDB() : error %d opening database environment\n", ret)); + fDbEnvInit = true; + } + + strFile = pszFile; + ++mapFileUseCount[strFile]; + } + + pdb = new Db(&dbenv, 0); + + ret = pdb->open(NULL, // Txn pointer + pszFile, // Filename + "main", // Logical db name + DB_BTREE, // Database type + nFlags, // Flags + 0); + + if (ret > 0) + { + delete pdb; + pdb = NULL; + CRITICAL_BLOCK(cs_db) + --mapFileUseCount[strFile]; + strFile = ""; + throw runtime_error(strprintf("CDB() : can't open database file %s, error %d\n", pszFile, ret)); + } + + if (fCreate && !Exists(string("version"))) + WriteVersion(VERSION); + + RandAddSeed(); +} + +void CDB::Close() +{ + if (!pdb) + return; + if (!vTxn.empty()) + vTxn.front()->abort(); + vTxn.clear(); + pdb->close(0); + delete pdb; + pdb = NULL; + dbenv.txn_checkpoint(0, 0, 0); + + CRITICAL_BLOCK(cs_db) + --mapFileUseCount[strFile]; + + RandAddSeed(); +} + +void DBFlush(bool fShutdown) +{ + // Flush log data to the actual data file + // on all files that are not in use + printf("DBFlush(%s)\n", fShutdown ? "true" : "false"); + CRITICAL_BLOCK(cs_db) + { + dbenv.txn_checkpoint(0, 0, 0); + map::iterator mi = mapFileUseCount.begin(); + while (mi != mapFileUseCount.end()) + { + string strFile = (*mi).first; + int nRefCount = (*mi).second; + if (nRefCount == 0) + { + dbenv.lsn_reset(strFile.c_str(), 0); + mapFileUseCount.erase(mi++); + } + else + mi++; + } + if (fShutdown) + { + char** listp; + if (mapFileUseCount.empty()) + dbenv.log_archive(&listp, DB_ARCH_REMOVE); + dbenv.close(0); + fDbEnvInit = false; + } + } +} + + + + + + +// +// CTxDB +// + +bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) +{ + assert(!fClient); + txindex.SetNull(); + return Read(make_pair(string("tx"), hash), txindex); +} + +bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex) +{ + assert(!fClient); + return Write(make_pair(string("tx"), hash), txindex); +} + +bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight) +{ + assert(!fClient); + + // Add to tx index + uint256 hash = tx.GetHash(); + CTxIndex txindex(pos, tx.vout.size()); + return Write(make_pair(string("tx"), hash), txindex); +} + +bool CTxDB::EraseTxIndex(const CTransaction& tx) +{ + assert(!fClient); + uint256 hash = tx.GetHash(); + + return Erase(make_pair(string("tx"), hash)); +} + +bool CTxDB::ContainsTx(uint256 hash) +{ + assert(!fClient); + return Exists(make_pair(string("tx"), hash)); +} + +bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector& vtx) +{ + assert(!fClient); + vtx.clear(); + + // Get cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + return false; + + unsigned int fFlags = DB_SET_RANGE; + loop + { + // Read next record + CDataStream ssKey; + if (fFlags == DB_SET_RANGE) + ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0); + CDataStream ssValue; + int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); + fFlags = DB_NEXT; + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + return false; + + // Unserialize + string strType; + uint160 hashItem; + CDiskTxPos pos; + ssKey >> strType >> hashItem >> pos; + int nItemHeight; + ssValue >> nItemHeight; + + // Read transaction + if (strType != "owner" || hashItem != hash160) + break; + if (nItemHeight >= nMinHeight) + { + vtx.resize(vtx.size()+1); + if (!vtx.back().ReadFromDisk(pos)) + return false; + } + } + return true; +} + +bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex) +{ + assert(!fClient); + tx.SetNull(); + if (!ReadTxIndex(hash, txindex)) + return false; + return (tx.ReadFromDisk(txindex.pos)); +} + +bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx) +{ + CTxIndex txindex; + return ReadDiskTx(hash, tx, txindex); +} + +bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex) +{ + return ReadDiskTx(outpoint.hash, tx, txindex); +} + +bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx) +{ + CTxIndex txindex; + return ReadDiskTx(outpoint.hash, tx, txindex); +} + +bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) +{ + return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex); +} + +bool CTxDB::EraseBlockIndex(uint256 hash) +{ + return Erase(make_pair(string("blockindex"), hash)); +} + +bool CTxDB::ReadHashBestChain(uint256& hashBestChain) +{ + return Read(string("hashBestChain"), hashBestChain); +} + +bool CTxDB::WriteHashBestChain(uint256 hashBestChain) +{ + return Write(string("hashBestChain"), hashBestChain); +} + +CBlockIndex* InsertBlockIndex(uint256 hash) +{ + if (hash == 0) + return NULL; + + // Return existing + map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + return (*mi).second; + + // Create new + CBlockIndex* pindexNew = new CBlockIndex(); + if (!pindexNew) + throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); + mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + + return pindexNew; +} + +bool CTxDB::LoadBlockIndex() +{ + // Get cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + return false; + + unsigned int fFlags = DB_SET_RANGE; + loop + { + // Read next record + CDataStream ssKey; + if (fFlags == DB_SET_RANGE) + ssKey << make_pair(string("blockindex"), uint256(0)); + CDataStream ssValue; + int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); + fFlags = DB_NEXT; + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + return false; + + // Unserialize + string strType; + ssKey >> strType; + if (strType == "blockindex") + { + CDiskBlockIndex diskindex; + ssValue >> diskindex; + + // Construct block index object + CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); + pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); + pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); + pindexNew->nFile = diskindex.nFile; + pindexNew->nBlockPos = diskindex.nBlockPos; + pindexNew->nHeight = diskindex.nHeight; + pindexNew->nVersion = diskindex.nVersion; + pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; + pindexNew->nTime = diskindex.nTime; + pindexNew->nBits = diskindex.nBits; + pindexNew->nNonce = diskindex.nNonce; + + // Watch for genesis block and best block + if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) + pindexGenesisBlock = pindexNew; + } + else + { + break; + } + } + + if (!ReadHashBestChain(hashBestChain)) + { + if (pindexGenesisBlock == NULL) + return true; + return error("CTxDB::LoadBlockIndex() : hashBestChain not found\n"); + } + + if (!mapBlockIndex.count(hashBestChain)) + return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found\n"); + pindexBest = mapBlockIndex[hashBestChain]; + nBestHeight = pindexBest->nHeight; + printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,14).c_str(), nBestHeight); + + return true; +} + + + + + +// +// CAddrDB +// + +bool CAddrDB::WriteAddress(const CAddress& addr) +{ + return Write(make_pair(string("addr"), addr.GetKey()), addr); +} + +bool CAddrDB::LoadAddresses() +{ + CRITICAL_BLOCK(cs_mapIRCAddresses) + CRITICAL_BLOCK(cs_mapAddresses) + { + // Load user provided addresses + CAutoFile filein = fopen("addr.txt", "rt"); + if (filein) + { + try + { + char psz[1000]; + while (fgets(psz, sizeof(psz), filein)) + { + CAddress addr(psz, NODE_NETWORK); + if (addr.ip != 0) + { + AddAddress(*this, addr); + mapIRCAddresses.insert(make_pair(addr.GetKey(), addr)); + } + } + } + catch (...) { } + } + + // Get cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + return false; + + loop + { + // Read next record + CDataStream ssKey; + CDataStream ssValue; + int ret = ReadAtCursor(pcursor, ssKey, ssValue); + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + return false; + + // Unserialize + string strType; + ssKey >> strType; + if (strType == "addr") + { + CAddress addr; + ssValue >> addr; + mapAddresses.insert(make_pair(addr.GetKey(), addr)); + } + } + + //// debug print + printf("mapAddresses:\n"); + foreach(const PAIRTYPE(vector, CAddress)& item, mapAddresses) + item.second.print(); + printf("-----\n"); + + // Fix for possible bug that manifests in mapAddresses.count in irc.cpp, + // just need to call count here and it doesn't happen there. The bug was the + // pack pragma in irc.cpp and has been fixed, but I'm not in a hurry to delete this. + mapAddresses.count(vector(18)); + } + + return true; +} + +bool LoadAddresses() +{ + return CAddrDB("cr+").LoadAddresses(); +} + + + + +// +// CReviewDB +// + +bool CReviewDB::ReadReviews(uint256 hash, vector& vReviews) +{ + vReviews.size(); // msvc workaround, just need to do anything with vReviews + return Read(make_pair(string("reviews"), hash), vReviews); +} + +bool CReviewDB::WriteReviews(uint256 hash, const vector& vReviews) +{ + return Write(make_pair(string("reviews"), hash), vReviews); +} + + + + + + + +// +// CWalletDB +// + +bool CWalletDB::LoadWallet(vector& vchDefaultKeyRet) +{ + vchDefaultKeyRet.clear(); + + //// todo: shouldn't we catch exceptions and try to recover and continue? + CRITICAL_BLOCK(cs_mapKeys) + CRITICAL_BLOCK(cs_mapWallet) + { + // Get cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + return false; + + loop + { + // Read next record + CDataStream ssKey; + CDataStream ssValue; + int ret = ReadAtCursor(pcursor, ssKey, ssValue); + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + return false; + + // Unserialize + // Taking advantage of the fact that pair serialization + // is just the two items serialized one after the other + string strType; + ssKey >> strType; + if (strType == "name") + { + string strAddress; + ssKey >> strAddress; + ssValue >> mapAddressBook[strAddress]; + } + else if (strType == "tx") + { + uint256 hash; + ssKey >> hash; + CWalletTx& wtx = mapWallet[hash]; + ssValue >> wtx; + + if (wtx.GetHash() != hash) + printf("Error in wallet.dat, hash mismatch\n"); + + //// debug print + //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); + //printf(" %12I64d %s %s %s\n", + // wtx.vout[0].nValue, + // DateTimeStr(wtx.nTime).c_str(), + // wtx.hashBlock.ToString().substr(0,14).c_str(), + // wtx.mapValue["message"].c_str()); + } + else if (strType == "key") + { + vector vchPubKey; + ssKey >> vchPubKey; + CPrivKey vchPrivKey; + ssValue >> vchPrivKey; + + mapKeys[vchPubKey] = vchPrivKey; + mapPubKeys[Hash160(vchPubKey)] = vchPubKey; + } + else if (strType == "defaultkey") + { + ssValue >> vchDefaultKeyRet; + } + else if (strType == "setting") /// or settings or option or options or config? + { + string strKey; + ssKey >> strKey; + if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins; + if (strKey == "nTransactionFee") ssValue >> nTransactionFee; + if (strKey == "addrIncoming") ssValue >> addrIncoming; + } + } + } + + printf("fGenerateBitcoins = %d\n", fGenerateBitcoins); + printf("nTransactionFee = %I64d\n", nTransactionFee); + printf("addrIncoming = %s\n", addrIncoming.ToString().c_str()); + + return true; +} + +bool LoadWallet() +{ + vector vchDefaultKey; + if (!CWalletDB("cr").LoadWallet(vchDefaultKey)) + return false; + + if (mapKeys.count(vchDefaultKey)) + { + // Set keyUser + keyUser.SetPubKey(vchDefaultKey); + keyUser.SetPrivKey(mapKeys[vchDefaultKey]); + } + else + { + // Create new keyUser and set as default key + RandAddSeed(true); + keyUser.MakeNewKey(); + if (!AddKey(keyUser)) + return false; + if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), "Your Address")) + return false; + CWalletDB().WriteDefaultKey(keyUser.GetPubKey()); + } + + return true; +} diff --git a/db.h b/db.h new file mode 100644 index 000000000..1139f7686 --- /dev/null +++ b/db.h @@ -0,0 +1,420 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include +class CTransaction; +class CTxIndex; +class CDiskBlockIndex; +class CDiskTxPos; +class COutPoint; +class CUser; +class CReview; +class CAddress; +class CWalletTx; + +extern map mapAddressBook; +extern bool fClient; + + +extern DbEnv dbenv; +extern void DBFlush(bool fShutdown); + + + + +class CDB +{ +protected: + Db* pdb; + string strFile; + vector vTxn; + + explicit CDB(const char* pszFile, const char* pszMode="r+", bool fTxn=false); + ~CDB() { Close(); } +public: + void Close(); +private: + CDB(const CDB&); + void operator=(const CDB&); + +protected: + template + bool Read(const K& key, T& value) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Read + Dbt datValue; + datValue.set_flags(DB_DBT_MALLOC); + int ret = pdb->get(GetTxn(), &datKey, &datValue, 0); + memset(datKey.get_data(), 0, datKey.get_size()); + if (datValue.get_data() == NULL) + return false; + + // Unserialize value + CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK); + ssValue >> value; + + // Clear and free memory + memset(datValue.get_data(), 0, datValue.get_size()); + free(datValue.get_data()); + return (ret == 0); + } + + template + bool Write(const K& key, const T& value, bool fOverwrite=true) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Value + CDataStream ssValue(SER_DISK); + ssValue.reserve(10000); + ssValue << value; + Dbt datValue(&ssValue[0], ssValue.size()); + + // Write + int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); + + // Clear memory in case it was a private key + memset(datKey.get_data(), 0, datKey.get_size()); + memset(datValue.get_data(), 0, datValue.get_size()); + return (ret == 0); + } + + template + bool Erase(const K& key) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Erase + int ret = pdb->del(GetTxn(), &datKey, 0); + + // Clear memory + memset(datKey.get_data(), 0, datKey.get_size()); + return (ret == 0 || ret == DB_NOTFOUND); + } + + template + bool Exists(const K& key) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Exists + int ret = pdb->exists(GetTxn(), &datKey, 0); + + // Clear memory + memset(datKey.get_data(), 0, datKey.get_size()); + return (ret == 0); + } + + Dbc* GetCursor() + { + if (!pdb) + return NULL; + Dbc* pcursor = NULL; + int ret = pdb->cursor(NULL, &pcursor, 0); + if (ret != 0) + return NULL; + return pcursor; + } + + int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT) + { + // Read at cursor + Dbt datKey; + if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) + { + datKey.set_data(&ssKey[0]); + datKey.set_size(ssKey.size()); + } + Dbt datValue; + if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) + { + datValue.set_data(&ssValue[0]); + datValue.set_size(ssValue.size()); + } + datKey.set_flags(DB_DBT_MALLOC); + datValue.set_flags(DB_DBT_MALLOC); + int ret = pcursor->get(&datKey, &datValue, fFlags); + if (ret != 0) + return ret; + else if (datKey.get_data() == NULL || datValue.get_data() == NULL) + return 99999; + + // Convert to streams + ssKey.SetType(SER_DISK); + ssKey.clear(); + ssKey.write((char*)datKey.get_data(), datKey.get_size()); + ssValue.SetType(SER_DISK); + ssValue.clear(); + ssValue.write((char*)datValue.get_data(), datValue.get_size()); + + // Clear and free memory + memset(datKey.get_data(), 0, datKey.get_size()); + memset(datValue.get_data(), 0, datValue.get_size()); + free(datKey.get_data()); + free(datValue.get_data()); + return 0; + } + + DbTxn* GetTxn() + { + if (!vTxn.empty()) + return vTxn.back(); + else + return NULL; + } + +public: + bool TxnBegin() + { + if (!pdb) + return false; + DbTxn* ptxn = NULL; + int ret = dbenv.txn_begin(GetTxn(), &ptxn, 0); + if (!ptxn || ret != 0) + return false; + vTxn.push_back(ptxn); + return true; + } + + bool TxnCommit() + { + if (!pdb) + return false; + if (vTxn.empty()) + return false; + int ret = vTxn.back()->commit(0); + vTxn.pop_back(); + return (ret == 0); + } + + bool TxnAbort() + { + if (!pdb) + return false; + if (vTxn.empty()) + return false; + int ret = vTxn.back()->abort(); + vTxn.pop_back(); + return (ret == 0); + } + + bool ReadVersion(int& nVersion) + { + nVersion = 0; + return Read(string("version"), nVersion); + } + + bool WriteVersion(int nVersion) + { + return Write(string("version"), nVersion); + } +}; + + + + + + + + +class CTxDB : public CDB +{ +public: + CTxDB(const char* pszMode="r+", bool fTxn=false) : CDB(!fClient ? "blkindex.dat" : NULL, pszMode, fTxn) { } +private: + CTxDB(const CTxDB&); + void operator=(const CTxDB&); +public: + bool ReadTxIndex(uint256 hash, CTxIndex& txindex); + bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex); + bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight); + bool EraseTxIndex(const CTransaction& tx); + bool ContainsTx(uint256 hash); + bool ReadOwnerTxes(uint160 hash160, int nHeight, vector& vtx); + bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex); + bool ReadDiskTx(uint256 hash, CTransaction& tx); + bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex); + bool ReadDiskTx(COutPoint outpoint, CTransaction& tx); + bool WriteBlockIndex(const CDiskBlockIndex& blockindex); + bool EraseBlockIndex(uint256 hash); + bool ReadHashBestChain(uint256& hashBestChain); + bool WriteHashBestChain(uint256 hashBestChain); + bool LoadBlockIndex(); +}; + + + + + +class CReviewDB : public CDB +{ +public: + CReviewDB(const char* pszMode="r+", bool fTxn=false) : CDB("reviews.dat", pszMode, fTxn) { } +private: + CReviewDB(const CReviewDB&); + void operator=(const CReviewDB&); +public: + bool ReadUser(uint256 hash, CUser& user) + { + return Read(make_pair(string("user"), hash), user); + } + + bool WriteUser(uint256 hash, const CUser& user) + { + return Write(make_pair(string("user"), hash), user); + } + + bool ReadReviews(uint256 hash, vector& vReviews); + bool WriteReviews(uint256 hash, const vector& vReviews); +}; + + + + + +class CMarketDB : public CDB +{ +public: + CMarketDB(const char* pszMode="r+", bool fTxn=false) : CDB("market.dat", pszMode, fTxn) { } +private: + CMarketDB(const CMarketDB&); + void operator=(const CMarketDB&); +}; + + + + + +class CAddrDB : public CDB +{ +public: + CAddrDB(const char* pszMode="r+", bool fTxn=false) : CDB("addr.dat", pszMode, fTxn) { } +private: + CAddrDB(const CAddrDB&); + void operator=(const CAddrDB&); +public: + bool WriteAddress(const CAddress& addr); + bool LoadAddresses(); +}; + +bool LoadAddresses(); + + + + + +class CWalletDB : public CDB +{ +public: + CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { } +private: + CWalletDB(const CWalletDB&); + void operator=(const CWalletDB&); +public: + bool ReadName(const string& strAddress, string& strName) + { + strName = ""; + return Read(make_pair(string("name"), strAddress), strName); + } + + bool WriteName(const string& strAddress, const string& strName) + { + mapAddressBook[strAddress] = strName; + return Write(make_pair(string("name"), strAddress), strName); + } + + bool EraseName(const string& strAddress) + { + mapAddressBook.erase(strAddress); + return Erase(make_pair(string("name"), strAddress)); + } + + bool ReadTx(uint256 hash, CWalletTx& wtx) + { + return Read(make_pair(string("tx"), hash), wtx); + } + + bool WriteTx(uint256 hash, const CWalletTx& wtx) + { + return Write(make_pair(string("tx"), hash), wtx); + } + + bool EraseTx(uint256 hash) + { + return Erase(make_pair(string("tx"), hash)); + } + + bool ReadKey(const vector& vchPubKey, CPrivKey& vchPrivKey) + { + vchPrivKey.clear(); + return Read(make_pair(string("key"), vchPubKey), vchPrivKey); + } + + bool WriteKey(const vector& vchPubKey, const CPrivKey& vchPrivKey) + { + return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false); + } + + bool ReadDefaultKey(vector& vchPubKey) + { + vchPubKey.clear(); + return Read(string("defaultkey"), vchPubKey); + } + + bool WriteDefaultKey(const vector& vchPubKey) + { + return Write(string("defaultkey"), vchPubKey); + } + + template + bool ReadSetting(const string& strKey, T& value) + { + return Read(make_pair(string("setting"), strKey), value); + } + + template + bool WriteSetting(const string& strKey, const T& value) + { + return Write(make_pair(string("setting"), strKey), value); + } + + bool LoadWallet(vector& vchDefaultKeyRet); +}; + +bool LoadWallet(); + +inline bool SetAddressBookName(const string& strAddress, const string& strName) +{ + return CWalletDB().WriteName(strAddress, strName); +} diff --git a/headers.h b/headers.h new file mode 100644 index 000000000..7bd68a199 --- /dev/null +++ b/headers.h @@ -0,0 +1,71 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#ifdef _MSC_VER +#pragma warning(disable:4786) +#pragma warning(disable:4804) +#pragma warning(disable:4717) +#endif +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0400 +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define BOUNDSCHECK 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma hdrstop +using namespace std; +using namespace boost; + + + +#include "serialize.h" +#include "uint256.h" +#include "util.h" +#include "key.h" +#include "bignum.h" +#include "base58.h" +#include "script.h" +#include "db.h" +#include "net.h" +#include "irc.h" +#include "main.h" +#include "market.h" +#include "uibase.h" +#include "ui.h" diff --git a/irc.cpp b/irc.cpp new file mode 100644 index 000000000..3518df249 --- /dev/null +++ b/irc.cpp @@ -0,0 +1,314 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" + + +map, CAddress> mapIRCAddresses; +CCriticalSection cs_mapIRCAddresses; + + + + +#pragma pack(push, 1) +struct ircaddr +{ + int ip; + short port; +}; +#pragma pack(pop) + +string EncodeAddress(const CAddress& addr) +{ + struct ircaddr tmp; + tmp.ip = addr.ip; + tmp.port = addr.port; + + vector vch(UBEGIN(tmp), UEND(tmp)); + return string("u") + EncodeBase58Check(vch); +} + +bool DecodeAddress(string str, CAddress& addr) +{ + vector vch; + if (!DecodeBase58Check(str.substr(1), vch)) + return false; + + struct ircaddr tmp; + if (vch.size() != sizeof(tmp)) + return false; + memcpy(&tmp, &vch[0], sizeof(tmp)); + + addr = CAddress(tmp.ip, tmp.port); + return true; +} + + + + + + +static bool Send(SOCKET hSocket, const char* pszSend) +{ + if (strstr(pszSend, "PONG") != pszSend) + printf("SENDING: %s\n", pszSend); + const char* psz = pszSend; + const char* pszEnd = psz + strlen(psz); + while (psz < pszEnd) + { + int ret = send(hSocket, psz, pszEnd - psz, 0); + if (ret < 0) + return false; + psz += ret; + } + return true; +} + +bool RecvLine(SOCKET hSocket, string& strLine) +{ + strLine = ""; + loop + { + char c; + int nBytes = recv(hSocket, &c, 1, 0); + if (nBytes > 0) + { + if (c == '\n') + continue; + if (c == '\r') + return true; + strLine += c; + } + else if (nBytes <= 0) + { + if (!strLine.empty()) + return true; + // socket closed + printf("IRC socket closed\n"); + return false; + } + else + { + // socket error + int nErr = WSAGetLastError(); + if (nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + { + printf("IRC recv failed: %d\n", nErr); + return false; + } + } + } +} + +bool RecvLineIRC(SOCKET hSocket, string& strLine) +{ + loop + { + bool fRet = RecvLine(hSocket, strLine); + if (fRet) + { + if (fShutdown) + return false; + vector vWords; + ParseString(strLine, ' ', vWords); + if (vWords[0] == "PING") + { + strLine[1] = 'O'; + strLine += '\r'; + Send(hSocket, strLine.c_str()); + continue; + } + } + return fRet; + } +} + +bool RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL) +{ + loop + { + string strLine; + if (!RecvLineIRC(hSocket, strLine)) + return false; + printf("IRC %s\n", strLine.c_str()); + if (psz1 && strLine.find(psz1) != -1) + return true; + if (psz2 && strLine.find(psz2) != -1) + return true; + if (psz3 && strLine.find(psz3) != -1) + return true; + } +} + +bool Wait(int nSeconds) +{ + if (fShutdown) + return false; + printf("Waiting %d seconds to reconnect to IRC\n", nSeconds); + for (int i = 0; i < nSeconds; i++) + { + if (fShutdown) + return false; + Sleep(1000); + } + return true; +} + + + +void ThreadIRCSeed(void* parg) +{ + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + int nErrorWait = 10; + int nRetryWait = 10; + + while (!fShutdown) + { + CAddress addrConnect("216.155.130.130:6667"); + struct hostent* phostent = gethostbyname("chat.freenode.net"); + if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) + addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(6667)); + + SOCKET hSocket; + if (!ConnectSocket(addrConnect, hSocket)) + { + printf("IRC connect failed\n"); + nErrorWait = nErrorWait * 11 / 10; + if (Wait(nErrorWait += 60)) + continue; + else + return; + } + + if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname")) + { + closesocket(hSocket); + nErrorWait = nErrorWait * 11 / 10; + if (Wait(nErrorWait += 60)) + continue; + else + return; + } + + string strMyName = EncodeAddress(addrLocalHost); + + if (!addrLocalHost.IsRoutable()) + strMyName = strprintf("x%u", GetRand(1000000000)); + + + Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str()); + Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str()); + + if (!RecvUntil(hSocket, " 004 ")) + { + closesocket(hSocket); + nErrorWait = nErrorWait * 11 / 10; + if (Wait(nErrorWait += 60)) + continue; + else + return; + } + Sleep(500); + + Send(hSocket, "JOIN #bitcoin\r"); + Send(hSocket, "WHO #bitcoin\r"); + + int64 nStart = GetTime(); + string strLine; + while (!fShutdown && RecvLineIRC(hSocket, strLine)) + { + if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':') + continue; + printf("IRC %s\n", strLine.c_str()); + + vector vWords; + ParseString(strLine, ' ', vWords); + if (vWords.size() < 2) + continue; + + char pszName[10000]; + pszName[0] = '\0'; + + if (vWords[1] == "352" && vWords.size() >= 8) + { + // index 7 is limited to 16 characters + // could get full length name at index 10, but would be different from join messages + strcpy(pszName, vWords[7].c_str()); + printf("GOT WHO: [%s] ", pszName); + } + + if (vWords[1] == "JOIN" && vWords[0].size() > 1) + { + // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname + strcpy(pszName, vWords[0].c_str() + 1); + if (strchr(pszName, '!')) + *strchr(pszName, '!') = '\0'; + printf("GOT JOIN: [%s] ", pszName); + } + + if (pszName[0] == 'u') + { + CAddress addr; + if (DecodeAddress(pszName, addr)) + { + CAddrDB addrdb; + if (AddAddress(addrdb, addr)) + printf("new "); + else + { + // make it try connecting again + CRITICAL_BLOCK(cs_mapAddresses) + if (mapAddresses.count(addr.GetKey())) + mapAddresses[addr.GetKey()].nLastFailed = 0; + } + addr.print(); + + CRITICAL_BLOCK(cs_mapIRCAddresses) + mapIRCAddresses.insert(make_pair(addr.GetKey(), addr)); + } + else + { + printf("decode failed\n"); + } + } + } + closesocket(hSocket); + + if (GetTime() - nStart > 20 * 60) + { + nErrorWait /= 3; + nRetryWait /= 3; + } + + nRetryWait = nRetryWait * 11 / 10; + if (!Wait(nRetryWait += 60)) + return; + } +} + + + + + + + + + + +#ifdef TEST +int main(int argc, char *argv[]) +{ + WSADATA wsadata; + if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR) + { + printf("Error at WSAStartup()\n"); + return false; + } + + ThreadIRCSeed(NULL); + + WSACleanup(); + return 0; +} +#endif diff --git a/irc.h b/irc.h new file mode 100644 index 000000000..91c3ffe68 --- /dev/null +++ b/irc.h @@ -0,0 +1,10 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +extern bool RecvLine(SOCKET hSocket, string& strLine); +extern void ThreadIRCSeed(void* parg); +extern bool fRestartIRCSeed; + +extern map, CAddress> mapIRCAddresses; +extern CCriticalSection cs_mapIRCAddresses; diff --git a/key.h b/key.h new file mode 100644 index 000000000..8b0b54e4b --- /dev/null +++ b/key.h @@ -0,0 +1,156 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + + +// secp160k1 +// const unsigned int PRIVATE_KEY_SIZE = 192; +// const unsigned int PUBLIC_KEY_SIZE = 41; +// const unsigned int SIGNATURE_SIZE = 48; +// +// secp192k1 +// const unsigned int PRIVATE_KEY_SIZE = 222; +// const unsigned int PUBLIC_KEY_SIZE = 49; +// const unsigned int SIGNATURE_SIZE = 57; +// +// secp224k1 +// const unsigned int PRIVATE_KEY_SIZE = 250; +// const unsigned int PUBLIC_KEY_SIZE = 57; +// const unsigned int SIGNATURE_SIZE = 66; +// +// secp256k1: +// const unsigned int PRIVATE_KEY_SIZE = 279; +// const unsigned int PUBLIC_KEY_SIZE = 65; +// const unsigned int SIGNATURE_SIZE = 72; +// +// see www.keylength.com +// script supports up to 75 for single byte push + + + +class key_error : public std::runtime_error +{ +public: + explicit key_error(const std::string& str) : std::runtime_error(str) {} +}; + + +// secure_allocator is defined is serialize.h +typedef vector > CPrivKey; + + + +class CKey +{ +protected: + EC_KEY* pkey; + +public: + CKey() + { + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (pkey == NULL) + throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); + } + + CKey(const CKey& b) + { + pkey = EC_KEY_dup(b.pkey); + if (pkey == NULL) + throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); + } + + CKey& operator=(const CKey& b) + { + if (!EC_KEY_copy(pkey, b.pkey)) + throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); + return (*this); + } + + ~CKey() + { + EC_KEY_free(pkey); + } + + void MakeNewKey() + { + if (!EC_KEY_generate_key(pkey)) + throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); + } + + bool SetPrivKey(const CPrivKey& vchPrivKey) + { + const unsigned char* pbegin = &vchPrivKey[0]; + if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) + return false; + return true; + } + + CPrivKey GetPrivKey() const + { + unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); + CPrivKey vchPrivKey(nSize, 0); + unsigned char* pbegin = &vchPrivKey[0]; + if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); + return vchPrivKey; + } + + bool SetPubKey(const vector& vchPubKey) + { + const unsigned char* pbegin = &vchPubKey[0]; + if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) + return false; + return true; + } + + vector GetPubKey() const + { + unsigned int nSize = i2o_ECPublicKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); + vector vchPubKey(nSize, 0); + unsigned char* pbegin = &vchPubKey[0]; + if (i2o_ECPublicKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); + return vchPubKey; + } + + bool Sign(uint256 hash, vector& vchSig) + { + vchSig.clear(); + unsigned char pchSig[10000]; + unsigned int nSize = 0; + if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey)) + return false; + vchSig.resize(nSize); + memcpy(&vchSig[0], pchSig, nSize); + return true; + } + + bool Verify(uint256 hash, const vector& vchSig) + { + // -1 = error, 0 = bad sig, 1 = good + if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + return false; + return true; + } + + static bool Sign(const CPrivKey& vchPrivKey, uint256 hash, vector& vchSig) + { + CKey key; + if (!key.SetPrivKey(vchPrivKey)) + return false; + return key.Sign(hash, vchSig); + } + + static bool Verify(const vector& vchPubKey, uint256 hash, const vector& vchSig) + { + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + return key.Verify(hash, vchSig); + } +}; diff --git a/libeay32.dll b/libeay32.dll new file mode 100644 index 0000000000000000000000000000000000000000..3bc745c4c0f4751cab5195d9fbdf19ea42113016 GIT binary patch literal 1306630 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

v_FCS|;eZTiM@xO9LEn)+yikJAf}4kzOb< zk!)E!k;jM0&m%s615!k!ZdqtGzsl`ghBqDAktgm)hB;;+bMjP8{83+?ry!y7Tw$)a zyYoC92^~lu@~+I@zeY-|QcrvcRoNf$X1d!xZw8dxuc|U$D=*mVcy_6@13c5#y|ksa zRLB~BvdqOQ%$(eldvnewtg;3QobcnF(VDXX+uCQNGVkL8GgVK<9C;&MZxDN%Nr_bTTw{n^2 zq){GQ{+#mxmG-MFloigx(^&}Rp&!JC41$e)YOlm-tY8Qm`l zA(a1sKtNX8$cNfJVtUW6wLlKD-zV#&r=aV$hOO@9y;!@qf(;psW)$*)J*_|hz`&Aq z!qM3D-}CpU4BwtZg~^HPH$RJdHPL>%U?Z($U5~t(TL>nat(3BL8u^`-I`aqs;9z!hgp$R&tkBS zD7Uw$C-`;yI|+V$PFL{wwaR`r`RzWwwdut@rm{3Y2y6qZaAA2BOTKqb6;z|@!V3UO z1fEEZ#$7OA2;#NZb7T?CM0B3;xnz?u8h^?FgoTDy(vZlAtUO25*bNDOI3s!!gw7@% zD3QB_W4n}&Q_-b#-PMq}Q>!9#3Vk_trs#XOLT061i1!EL4gta+qOZTE+U|lVYYaC% zb%jdPjYod@{GUjC+{agOtf%zv6S$u^N;b>+Hpqv22P zPjuij3OJd|Mj#EEwVI?jn8Ys{kep!mFd*2v$}UNKJ(pj?V)B_N z6NN@sS8|0tx4EFn-cx=iCG0BD6LB=-<~NAwV0{J?77)&m)5;}foQ1!9IFWN_0WE{8 zs#$uFvwyf9U9 zzYeXi|1FH7=iQHKS}@9G30NulUdIa_(#p$irk8F;82g`8AWa~snJJs0r-h@q*Bt=P^CiHTu)SzW^dq}zc$qo(eLBgq|&|&Ux71G zzJ}pH621?Ic1}MHlpuC3zCUnWQH=@FpdoSGrCsTm7 zDy!@(J+6pI3dkYW7{L+>DI>dAD`)^H8Bo=78fpjKh5h zsdE({QtVS2gWp!0m`~ejoED2NKdk{1P zPzDns?F&Js3^?8gWBbjoB+-ID#?J3Xe)YYDLQx`v2MRSp_!icWRnQCrkPebp2 zu{+aU7N`0pd*}Z~HR6wdU5%6@ejnI><~Ma)BfsJCwGQ@_B0 zs6Z$?P{83l=_{QDkb$ZD_d4Hf0VSnA`@6J(hg^*iNTedzck$#7%kGLuMb{0L%zAo# zC4TQv5oC5xL5>t(XV4tZEb8Ov9QA|6<^Dxi$`8&X%?0~G4zMY_PROu+?z8$8a+o0c zpN#q;>HGawubA)XZu>`>Z^)_KPGnHxv{BJFi#}#6uqQ+f>XW$bl1feX)!jWA2trbx zcV6?jF?CaKq)%nY7FY-mD!~iCs3%^$V1^DRi_0b1tbFhHD#t%g;U{mr%y{~YpBi)% z{7@7(8rJZ)cqB0flIc-$1KcHyLcAf&A%P&^g;5XUz)RsSvnAe-c)FbB=H@MS^u5e( z+ll4wvuocr)3;*D`_x-}@%8TlB-?5A{bG|=xaTR{{7Kp5PeS%1k~=BhapISVMOC;gb$fp z&}?!rw4lwmoHCH-7XCH2T)aT`0dg~6isk%mB{g!aye3o7a`E+FQZcvX{j72_*i_ri zANwW9OA_^t=oImB99C4*R!;YAaStB>n$!j9W43MkVksvI*lu2Ur_c1=Iqv#5omt>hn5xE}u+78$(K`G~ z?Vp$Scb-Hk0q0=GTjc{u<}O~u_^?erO!HDgRQgn)RQmp=$S~T8-E$~mZZ?{Z1Hoon zOM7Q?f6MO9=9c^xOyZm%*u!AUCpw_$AYvX^C>zmd0+_mH9uwxQH{08l0D&hjI<14g zDGK9URtK8Q?fLuZwxGniI$Pp;>#~g%f0QnSKXCFt%|FCLh7#a- z+b&ooTX@ZAlpPE6lg7_D9wqoB9$KQxB-zq>pPXAC8;J{5+2C5yDgOsY=A3sysgR?>UbDp`2Z=|WZo>8?IqC-s7OB$!l3Bn%F|tDnZHrUSPnhEb+93@$M9APWAUbot79!5@ zIVuGpjYDZS$4A8H)KI*Gze-MV4p2M4s24^Xf_|7MA_G%IcvwY>t!U3!rQk36kI~SZ z_iU;SFhA$sK(~xC8m9cs9it?;BHl-AM{yX$g@;eW^m?0N$^wgPL|$aqz9+n@0R#n{^AJluu!4#QBy^SMjFk?U_4 z&(SgkPq{sDI|+rhr}`Ud3(E!Dp!5P7sUj?1LdZ^n1lVF{ZFb=cFLQmFWi{0?!FU{H zRuvP=!rn+lsnu*OmzyeTWX&qNUe3VHuCj|6yZ+oTg3s{5Woi%9Xm}KCEIIgl{slt; zb_j{39Y;kO9-UyhD0k27&;mdS50hrp>hC`yOvu~CRFi$jjBQth@>Glw{GWHzMG8Gv zJS=EirO?)FG;B~J@3zZAYgL%+7Qtkjf9Cs0slHHDrGT%NSeXQhKrMN$w0r6Ggsj(Y zP|dNKx=K;9${va4RHKZX0o2M_aW|DD%nI{InbhtZcZQM5Uw?BxgIYnL44@UucMrZ$V9 z`vmTTmk7Q^o%}!E-UU9+qWb^OwrLwmV1uL(B$Y)XCK92ApbZ2}NhpOD*kqfeTm?Z~ z0wT(W%hz5_f_+%F6hQ$+p`u?=QBmM4SLuxg#0wYYTUy}@Dlkg`D`;CNH2?SK%=2tE zY0HoQ@ArHC%8TstJTr6V%$YN1&YU@OCVtH_`>?k@p!)M+As_Sx{1Q7)J&NBUZh9+e z(Eypx0NL`(;Q^BW53R>EDKdp0V@83po@U~MliNfJS(2y&4WOJ03kG`9BfPC z!HK?Ms*S5b$YU^(!`e-;;RsGjZ7bkXQUKb27^U-lR!Xy__s8jU+fb#bqE-SHQ{d}{H+duP1LZ^?cv0JdAgm^<-6*B(X-cAvthH_3jGtScE3+VV zb9KEJ%R$yUJ^)y4k`e1(zz}olDQL`}wrSRck9N5m=M$J{7WhfSpC$OmmNssgU(1#x zi=C1EA3V{xWuW!ichx(&_Sn3C1gwavAJXg8r#L*lwS>MdyYzr){=@r}5cZ&xSW>#r zF=LUnjGVH|996IeT)ChIyQHG27V;O?1B!PGaNI`*)v4AgXa1*kYW-ZAJh#oA>|Zre zK*wr1kX=nTh)jL_(*8NwB=(9P?O9@(_)@e4iZA&A%@kO{QE1F`5>}qV#R2XFvoAp$ zKyn)7NB~6{$=9rWwVfhxL(09u^cG6-JuRPk(94=%+wN8tES!Ct=v9HU=);GqYV_-p zc;EB-uJyrm5qxrX7wEkmg_QyK`vR4r@qJ>UOB0|{l^uUo=@=fM?^I9Ur!RX&b(y9E zg%u^a%7?6t76XM~!h&o5IVhm9_)<;#FsN*0LRVeY8qYn$Tdu*nIO+%zo5R(()FW!Z zn)4zvcu0)#zP;7f-hD(FT&QU88{kcIs@X(se8<{L?3Y!I?+mmq_8ip=M=1mG;HPfr z-KNZ~w3E)wj=8FIEDyAEj~3&j=V|BZB&6^hT<}o?8_UgJ_U;MU&?j|w+>FV9oBj#? zD;DO5Xj!3ES5MXC&2|XonscpFhi=-uE&hwOGZ|3R;!E}g&ye1*bH&t6^n7{aT4>V% zF-qo3Wuf3)86%q8JFxxy{q{oRiNP)hhz5Ahk|}$7(!GVCiEW5!jo3N^hGi>!8gYxu z=iN;vPpH38FeKC?)Pf%f0WA1XQ8KuHVSJz?sJF8fSCvj(Qo5%n1vp;zl6+r-x8qAS z2MZ<ey4HAHa~iGMJ!%#H>EO#UDA>r%0rc6rajgLhGA;#O zZu}2I37LsQqb3k23B?A&c&5Y(E)?oaSxXY0Fc@(%iV1Mlx5gv1STJ|FhcAWzjAd5C z_()U;rPi7n?z8cFr8*Ofl6{xRa}WFP%Ev_0<*vB}+}I)lhMy6b4-mwsfKxex4s~EY zwlIC#JO16(i~lwxJX`nG&R}`|b0oRf5%q{2m^$8fA{?R)PPQXD`iv5i!2P?Eky@rm z%+!&`Q?4oHDtw-NrF|^J%6;&fkS=y5IqfC}^M?!HWQ6zM#uvV=W5$Ip)%a28&-bLB zlb`2pmlS?(bp-HXzA>M8ef>dE_l}x%{A@bb{A>TDFE`ixML!SLyuc4ch~`>TA$nS~ z7S4J?*0#H)ucrfgE}CAy$n^Tg?f%#UzAvgmGiGGy8$RE{bT7ftjtx`}BzjJ|KW#=c zUu*jj_$SCO0luJLn2Xi_=3m4pKWoz{OS^u2SbILzA zi(k-T_s(zHUWb$#O-YNLjy@iiLlS28dP&{N{ReE}~B;rC1CJm8sGPp_654}Q8BG;#)T$%Nz z)B`a=wbE6EN)10H+?X>}di~|Zxt15rm_nI7O_{IJvW6>)tEJG_ND)p9{+>E(7}ix@ zvo7s9%rxt&`HGdTHTLkPcWshamS&6HsHUcdqSVSPfh;t^%R+V(m8EO@ScNVu7 zrq<@Oj8%DeI?`#Hs-g6D~+PQA)=>ng~k47 zd5CMg{{aBze+Owt%|CwqP!FkRvVN$cNjlEnOoL|wLw!7lBgQh6nVAz-Ngz3@8C-Ji zwq+&16=Jw}|DKEyN+s-IMttcL;F>LAA8RH1+^cyxA>OAm!lE`7$CSI}!LUnpH2Enq zXl8nqU*(Wm=bpPsE(u~C_a>dI%LGlAdr2>ArFJsytkVnKCrTp>?hD6@*8igXkNKrO zEPP;(^NV~{!Pyq!!C>z{#uTqN;!6%Dndni!czo(p!K0hs;Jux?of*ZOfzs>0T1ie z+d8iX?37J&kECWpr`v;1_xe1j3zkj(=OXv`UliK1K|mmw*uc0*d(sJ(TW){TKCC4& zO$8ePTLxd0<*y!YM&PDCwfUdHpYysI*#rM^WWbE~EeL^&twP{TChY)UW0aSeI|HZT zd;#<`fbQKI%cL1KiZt7&iQdDV{z!;)hWLyYDp?B=_ydykK2oa9#iPHcEI{pPi1agL z9(K5lN|3L^&H9$fw1md|%TyND)BhOt&~lqys_cjs_RrnF9aZ^j2yRA}!JoO?sl}vV zW#)FFkkC@0mRoi|V|{PZa8P;<1DXc*sc!bG@c%RPDlBe?Z`1srg%!m6s5)Um&@k!}|Bo5)0bgT_bkr zbpQ2h0f*2SVu_E9Z%XMmky$u~R^K2&rl$|-i77_;ydk#5a-ML#^^CW^s$$dnirXjM z?RO-k+#gnf>NCaiOy2gwO;#u6VZzx($O)OuEp%RjqfX*mT|6+_TH3*A6b@*tnu8^T z8l-_w!z=YIWPK>wI_NEuMjA{bqkZ-KlZx@NCVd>94q6|yrXrvxc}^0lss=`y^I!vr zE*q}mO*mf`{pxwYfyySjjc2_5)HnXg!cKkPYO<3q^;aE0JjqC2V?PZC>NjYd)T+7G zNZC)L%HOQgMDhaM7z^diw&hjU(}KbVf#&O?6j{neP@OdpV&VZU zNpyI{zPp2s6-;CIk_H0+BfSzOW?aF|M_B2IAsf?dMy@1&&Zag|<=D<>lc z(Rm(YQ-$+~nzSuXUq*$I7+8Q9n0#}QX?L>EG>rDmhPFKERJqU>+U@SLLgoEOP)q(# z2(OSH;tJVM#S+A~dw8V%^rvJjY=zl_ytlPrsfCDI$k(*X`c#`_gV#M_-I%Ztyr1TN zs{Y4*70VoKzJm9iwfD1U_l&#m)=AHvjozeKmzDfq!SU6h7mNAbhu$6DPgQ*~Lukj_ z{66FXQH{&oZ8qndhkwt+u$0Y@GHlcnDP0&HU4#+AP?2|F^b}6D%>DOzl&x09Zh~8;XwHhnLzg?` z8b$(Z;p46y7WaoYvSF%y>#h#W7N6wS9WQ(F4zm?ilU=(sjQ|?%ET%rM4eX;tmt1O+ zAH6mVFaQ5yd;T9?|BV}l zS%3Tb#sA}xBSy#V`TwWii}?Q$@xSK})1PQ%P2&J<)XJ&e>NxapYZv$}(R$Zy7Vt z(i=V9I@~p=xwx~!LH%Cgty>*m5|G;X7B|?w#Y#1q)VYj-zl7*y4yYrvUKw{CpZl8# z!=EKP$WjSfhH=k#xylyABKweeF%93cL1}V-YkdUpsgnkOUM#(5xlU>T5z6qU(aWJ zMEkU&UU>amCtj<&*x~;rqFqhcgwj+lzH$paRf=y_Z!?$E;sHR>km-AFQ+)fWD@N&i zUGCSvg3j8jC#b=u%&)?|=ltd9A;FgXSNSPS5>bC**U`wLClfL-VJy`OyTiRk=q(|+ zK}%Tfr7p>pvYpRQW}MV>yHqH)GWG}=*kSz?8Ki7oqa3z>o{hz}G;WE1V^!{gAs^0$ zD7OC{jE^r}MIQDcVowm`PRZMfl4q30mww;U%L?i56{izQ{%cA-qEMKsXhm}hWW$SQ&I(Xru1^ra~6DSN`-8y0vW~$@YoB|Pu z_jDRRvjiImG-tNGo?pi6MPPpvuPF4hf*IxcsXSv$=i&nSX^kAugqeuF)A$Z844$$z}221SOwX9$VSC61sb$vYe+= zPAZQFGSNV~M?C3z7GZD*s`$qB(;p3E`K=x zZ9Wd`7ZxbY)L-k}{3li9?XmHGaW&0qp%p$3EjTILRi=blWo_^|d&tA6$sHHA zx}B~lsxddKysh^irEV$N)Ow;tl`l9rdm=W_0#-(dFB+T*&jcdJagZZ^&3SZNL=q}3 zlbMbQzaIQcAVMu$<27M={#8-GFyH(Bt%pjjm}w-gW(TiAyE!Xg-H$dj14+|#GI#o< zk|(zUd#=IDFoCn$h1@e^>wsQKoOcqdp|Pl5k!#vD-nWr)+xuR8;VguA;KtHLlI>Hv zf;Yx$Z1)+7^@k$%QqZ0%jS^6y&Hu*+%dQI_H< z+;4ur#5zC{b?aog#MC0!EPViK6L?i8-7GTYDlf%_v^1g+zqS(t2EAL#;#b;=aBFG2 zZ@sYCS{CoivTOl$HL+4`laKf7@NgH_4(tTE%A4BTa-}~`x}W=Ygx{&SK`q9|+`Qk- z8DzYr2Vf|6uX?KS_(NWUHR~ zat#O3Ew#DIyRx5%{k}0Dd?J2jhVO;>fQ^;x5y!!xM`Zq$Kb4eG;{!8k|89H+Lv3F4 z$9N7qGGB61Sqay$Cs7>=@Tjdi*Kh$0Q6-AxD*M&gT>URMub0^{bW&;6#|X^v50;e_ z%3Gt7!JA`QQgJ@u3^8}Zg#2z2YIIh3uT-w7Od;yJ+-{VmxrRCEgzSm;A5etu-g>5^ zHA#n?=9RgopS*it83;hX>bHKXQH=!^5hz6fquUj2f+?l4rgue!I;b95WyX?R!;d@N zDVAQ5myZvuW?Hx%NeL7dxo%r$uEDsVE7%MJOcS%<2ygb@H|V|IHM)hjS}e`rQffoH z@xrvE{jeu7VA&G+y+PY5*1gU~B#g*)&4n zb8txHUuEqayd#X)qteM`GQ`^oGzk!>G=&(W!`1zdkTqjtLz~BVa5-@afv_$)5`r3T zqXhKcF|MxM33~Yn>RF)EL;dH264mN1>i#qIjIhMJ@B)5)uW4U`3_I$zOJ)`IS|aQ< z$cu@~dM#z?75VwVRhM%kMMbjBl9rt8ndnW(?USxZbor#ozSQ8dXnyzdH37X^!Mb(j z8~epJKRFcoG9YcWdaMRZ?x*dNkP1iA>=+&&f;g+RwaFI)+1x|p4-{u<}+LxhkT zv9;RmIm?Pc2^~z)nFrFGTwl}w>W4NI^(z(I624EbZ}coN3hyG#T(-$ zwi>iBtH=AK#&+2_n3=?v<8y+zS{;c&vLtixed2=nQc#z-NO`E{W;3~x*fRltr#HSC zzhTAHrJ}@@>ilno z9>XH`4#zV&6_~$|VVLVlpew3HDRV_>WH)JI zvG^qeugYdiTqg6~fZV)cg#JuV2XEG`59X)`-%^inShAXP6fZ|TNVk-4em;^f*;ewe zs(aJtUmL$6T(PhUd#2~F`9F&`#rjhukMM_L%*zVX9Q+Tsv~uzZ1*tOEaHI&PUV3sH z@@blOdSUwtcGx)c(ysZoA?Y6Zw<&C5-TmTA7s0uRbqZBWuK;MZtN;m4${0avB{;rj zI;x~Yxjc<3J55d{*af?NZ=&5G27@M35No@TQ^4Z#l9R$R7s6MRLnD|5E)D!Y1-$TI zF{aLcK>*N#1UA>SG&_OH5!Sk8vbsI^gWFtb%s2SC^OkXmj8+>dF2LD;&mF8!TFR2H z%n}Ogldf`GxS*l4K6&j!2Flha$5n7-*VOW7^tE_>f~*%d6!;a8_?=wABF*so)OPrR zh$81zcG1U`D_Y85a^Q!&{ilK*QG$gxa})(`Lz?a~}KnZ-4RIrK(wV~Z> z0?o{yOJ&r-m)o51ItgbNP}GcwUPo;at-&w zFM|x0;8~`z*h=Dm!%Vr-L#P@}zBhYB?2nCa2S;4`;oxYTcsdr-LU*eyzs|)cu zQD|-)u|5Ez{4c88tRV?>{3|p(tHDkSa4WV zU&v=*P03A91of7}Dio6DPDr##$x6AO{lg}gh9W{k=7zkMZuHl49d$H~R@Qdxu*ZN+ zb*;Jjr5*138)3Q9eSzOlw~7ukIJ1F+q%@7Icc;s@gSo;|06&4atH;ekoKM&IW&^G|;L#G`4Fx z-Fn;yl+aJ{p&t=Be{p=t5n+td>yHNn#CWfqKWD% z+iT5!rIdqPgq6jZ&*rB%$gMH2GKo=%oRVQT(aOUlb=4&o*32aSX-4%`Ah#RP@9?s{ zQBsg6YMj=HO<{@NdCsO~&2KoYyPPZ7g6Hb~-Ls3CMwGvID^y=aHND$-kRqEqHl`bC zzAn>6|Ld2_ML6Y>w(V~k^s({2J^b>Z{CJvSYhwHnxr<0z#LPBVdMWa*6-UlB6*{7` za3a3hn1wGCHW${Et$b-LNL3K9G=9y0@$JYj@$elUH0M_mLhm3Z-_Ceu!xHG$7${iD~R>-3`%}st5R`Et|V!iqfVLp_(gd(CAH_M58XJ%tbiTv4ALC8Kg zf6%(iuBKa1>+hu-p>IVl{^f+=#EQjg?TaX&0xZZs4^RM7-erL+=q zCx6A*9@h_>5A86GQRijfYXBUG_n(PO8GIaQ#P&E5ClVkLvFsSBP7BN83qC&V+yoh1Q2Mw@IuY(l@Ozd&Kep< zU>Q?IZ-gs!{x&4aUuSYp8&yAr3BWL)3cn=XP2rbmUN*8G!Q+L#*GenD-lUrfe#K`S z><3FC%bgRJx(K`ryERd~0E=0`B-4rlgQO6Lfp|&0?~~9sc$5(B@g=(QBN)iF4Xqp+ zi?+ zKPf{==D*UEJLeNI$xsN+fybVi>TJ$)*+)5CEfsWxR)bt`cqCtg7R|_3WWz#F{bBNcz$5H8nr%~{~dK|EZ16dK+?r2c2#T5 z$0^!JG?0H&wy7@ub)3pe)|MVt($ctf@QHzOi5ap7k8+#;{abX3|B`&&$SN zh4=5~rxPE62c~gcVBDhFM-RokMV+SK=1b#sq#JE)z_a(JgFqzib>8@rfG9pEH5+NE zugq7oUA(HMRQ&66=yLGIRd#E>n&)EuIX8WLUW^pcD>r@j{9e50P8_-yt*a#8P63_u z9?S1lvp+Jlr2H_!`4f5Q$Fz1^t)IE(cOjdb^R5s^31MWB8gFI}EiBrV_0OS=Dqc3yvZ!H2Wl3eN4q4^ z`zU-eQ%=n2pb!u~RDiI-APlbIJJx=8KJLaK??3*6bN%7r-}Ge0tf%Rh^FIptNde6U zUoFyqi52Pjr&?Tdl(NA!1$(w)Nk-|OOFkTC@j?#w3Hf_fqyNzm^%ooYl_Q*1$*K(1vFmZ5!jnrrYMf23K375yn4)E(u7uUsrd&<8#Mn9%yISK zurlWRv1jNdQf#j z9sMgF9^xO~1V;eX#%;>|<-1{;;;ynJ)~*qrD~wXi4}XmOuru0Ntg`ir0ROt%3fac? zsPi{|Jl2wZHe<0yD0aEMLF7z&Z8q%%7pA3}Q>bZnyPND^6SM%aIYs{OQ>7O%F=z{- zNzWO~hgeA8q%$bQY!dH#nP=sFUccmfhF{;NRP$Q zrd(8Q=0KHDHr1whDG(el{&}~kjQps_vEt``XmZIy?apCaUQ|GUQBhOSQqSzR4Ma49 zG-u~>reTgh${lp%&bS(3>V$CQ#`#yf+9n z4pvRs%f$)P4&$b_`O?Lz;MS7-N8zgIzB}(v#{ht|MgDaEL+t_HP@6q(Fv-DaXbmS2 z#iO&U6D{yLOfFzeAMA&miahGH{+h-W#O@+iQH(Z-mQbSG#zr|96+G&opBsF%c>Znc z0_u;@6b5fMf$PV!JVR|o1kcL#yg`~JZ8E=4-YbGZabcIJ6A3e(hbFs7UGM zk=C7@(5 zIG2=i(xFsp&I6y1t={F*^1VAVr0P^bw00M$Z@`2)uVYKcWcYSDbP{?H-Qc|F0Z zAXr4L1B?4ls9g%)60*|GxC4prV^wG;BwWsbMP#~>?PMX)BS5`o$Ws%sH|@~ zt;@tw72t$NXRi9mc>fEKAl1Rf;9!YbqSi-d?x{72JQCHvgrYMeG_DU?W=sZ?7he=t%c$XL;q8Y`BnTg!S-eELst z$HXW1fQnq}WKByr6I>a&30(T2P+k?;_d;5%7AJ~|*pVBc;*^L+i@4)On1M*ST_Trj zs?a8V`sT8dd>rvGZ=$xhO7gngPixkywp9LcH5$bx^al}tE`Ci)Waxd*NfE`phLP&y zOLe|ovg|=SC)ni_L56nV&He->8ohrxomm_2o6VS4R)3_h-SvLnvIg3|tCi_ip(=E| z%uEnKXS`#LYP1_?YvNby`~+-XkK4%K!bh0@Ktbgz%&*f`f<-&(vsJOj23oUTNIVY$ zgqZ^&@moE}%2|I__7EEx5UrYVRTcch%Z_j~)Vy0X8WMgq)Jt~MhKhUS?^!e+ro6L* z@xbLGvINE2QCd6(?L)<*6+ ziT`?)05`4*BbKwpEGkf;Xh#$+$Zb8rn;Ar`(ssAk5+lC#zB=V*>%Wvc`fU3io=pxm zZh!unvjPG*FrBj_9B7G-Nt-I|qmeKZwYx`p;i8%TxY^S$fO@0&rSF@<4k6l@!UEJ8 zcDQ-Y`A*61Ydu(-{j|iKdJBml{;dx-&kEj%JrxSGZ~C5v?-7e-1IG%NP?{l}B+bsH zFR0c_vHzk>YVvV;CZo=Jpwp?0AHVV+_gC3!|191R+9X8C^TR^LY^0vW_bMe;{# zP?_3|0z=%g@%=_;vHg6K@&}+a00r~cJi3h-_^o`EuHz2|VdkNt1}sYMFNZRA{~4+t zcUZR(-{f-!jxkxAzmX}KlEeaD-WOJq*KL1-=FfLz57mBYLzcsDXC4AHMIz=yJtE@B zma>HhX%H#`Zgy9-j9rZoi9^JZ4cWsw-EnV&v%fOXM8v)PHlE5sQDGP!ln@cE~Af4+NyyWo74;SNEiazDKAhMKI0DlK4R z&tzD`FL@RnqO2@~isV&$77s|phUvYbtmITmB;6^NO%tatc0BKe^`QKz#bQ_~vwJnJ zpBE2461qS8^;qMXW%Dn{%^Dj#dOsmWJAyxMes$&0egvbgdxs0_o21v4WRB>**qT6C zwt0mnw*(8ya5g;}m&Lkw+S+3S61}f~3*V}bh%wipV$!~3_eH*_`~E>FMQe!4_r%yv z_E53C4?ZF4ToO^|T&Qzm8Z*KM>4TlfZ>Ggj_|IR+UFMC?&QIsQIyTs1C~tn1J+m$Q z)vdA!+9Aq4Ur45}1NE@(1F1V$sjhk~bAEPwu)c0pa8fA^h&|fH-dEBcJ`(TY`FI4r z>(KYs)vX^pqZFmj(~lOUMI>JlJA7Y-K&mP+c%9O;Hx@PUd>VM+7s3V(e$(RjaV~*@ zR>jo*4i|XQQ7jNH{lswnSH=2PWIlYt^d)0wumFf%_K#8aHQbfPt{tnHr_G)9O_^dV zPm66FzQ5G#U($78Ijm}PI@7YV7)mh4lo{L);ZI}87@RpOc#~Q89Z0hE29>r-1FE-{D4QlVY&MJbw&XlU{PnUiE?86`vPrW=wYAg?~pb5D1Jtq zatExY|BB3hqxy5v5ha;jk2_{&&nDkWf`P8`%pu0uf7$;Zen@)k#1FA8pH(#6WhQTy zU)=H1+0+laW%dK_)KF69j2bTf?Oh|gk2jz^OlwNqhR=)_ccpGqq0t$MZ-}AWl5B=t z?d2H_gHI~Ci+5(F1lZ7v1$iVgeUynYJyRm|e2#$Z?&e}$>|ImKZJ}1aD#S1NTV{HQ z9SkM}865RY0_A=yQG~1*N>YPgb!vA@4G5k%ZP*^>_62`KaPThipUw|eV@x<*@dNhz zSU7{QF8oSV>&uzbsI`-(s#Yd*t5y4joRao6hKhI(VFIpFce%alfd`>i0?vCt>hHv_8h(+D_N6tH7809Ywqdd0= zWfmo%U9ZJsyM;cf80s`4q1N_Tf4eKWtEm`e2vdyjh9Z1792Mbvv+zC7<2$DNT=2c+ za}mD3j_{>sU8-58zONX1aoK2lHsmkr-~B~EC@q6fy;gu>pF+x7Kkd2Gs9(7v{@ZcZ zV*Ub_*l&_hV5MHpfy&|b0V@3;Mf`U@%~*G~Z$`bJkBjh|8sT>;Oi&wAwZcx^!Fd1| zmUo+BGo+vUY11ft->;~*XNn)KbFaas0UsfW*Jj$I&ixzb(>;|=vEUVusltSaFhD9| z(){%kbmzKZ4lEwO`+|?>|NGSTKS)H`*qhLurtN<@E9ydj|0#LIhki!p9f?uX*5jWpTB=Z!_}FSvGp7*n_G2uJfjy`VW+mhKjnHkEJM>yJ&jes z$n*T$$)|fiYi-jV*X8L+1!N|4e+6W|;}gA%_xCkebD&~n=1?eCfy9y;4^NlpkE&zB z0EzTWCAW9JcfgzW8S8a)h{osKKwH_dNS zW3X5u`l^zh?1WUQ(Z)r4SnWQ$_s>M{#q?XAKEBZ83%kDvL0YYj%Fgt;h`z4$1)42N z-O&-Z3XX~$TPW6T#df2Z=$IIM&d*}Q`bK^K>tL10oS)P(|0>qiH+6fV$!A}&=?_v80a=$n23%Z8dt$nm5P!rYqy|VkY zk7yrEEg^x$(YqD6S57n2#PEmz{B$UE@~2CUpI1{(C^4D;v8ifDei*I03TW*gq7u(e zqFp7)Tz$}8B6MDl$sQdX;;}h6J6XwCXA2}>o5!{tu0K8fv^z8f`eA0E&!=S$A08qf zfnwq04#mnjRqbYKr5Ckj@Kceze1;Ih-6agbVty@_H!_F04b`LM4b8}om$0cC7B+if zb)pTSuqlQoCLTQ>&4ip{VKxlQ(_btw(1h-880a9M=;h5a&R1*WqT;;xZ}x2GPfP57 zN^64B8vbSvUxLQgyQcK{$ND!tH@U3yrL%i>ckklK*}vj8C1uV5e#&)6+Y{QGoeybg zKr*|Va!j-z$q!M}{dYnLv*tVXw80lg$}2VDX@I6rKamlv zC2-uOPqp^>CXC{Lz!+eemPe&fh@EAR6Rm-l&m`A2t<-+!}o+P7S z)%7c1FDqH}J82TP3B16#)d$+Q!iSJ;I)ayMiYs^D56Vhhjz3~P4&8C#a~;^^=5Op0 z)b24!_gPW_1}!JLUOjL5kIY9bYwq*9y~>Cxf#h?QuzE_rKh(Q5!4{X3`BtRrSotb)dkf zhoEWho-GLTPInQ|*B-mM#N89o`0`zx+y@}RvE3Ev9|#9z?59Z1eSXVnXKvU2+==Dw zZK>rC{_W+n2{)W{^&a0av-Fp;^j$y!$VxB^?)jH0#yvQC=q9p}{TEAeNJagVa+mow zgg`=e^7Fg+2m6Mm+bU^dRc+}90q+FXT?4I0^-nZk;}2!>JAwR`?_~Yuhi7-Y9p>qO ztVg=2O|T3T?5FkY3DhFXYcO>u!X$Klua+;@SZBie9XEwP#av@%T^Uu=GS7OcG`V{h zhly`!`4(eN&EhTTGm4TYI*j=e;Gs4vmA;g-^}s#3vn$y#G)c99!jx!hLPv&ZdeY=A z1#t*1Tkz9xEF)c26ZcVv&i2}ED9v0wR5G|E{U+2&zYtaKi8WvoRE7I&-_Gb|V#=2E z7BK*#)kCx?ip^Ty>CY-P5z9lq8}(+Ii{kH-Nb40Yh#s0UwkoL7mxnA406<^nYhc{=hPyf=zbPIx^xex6520oBb+ny0lF`>SoI=*F0xylBWLlR8 z7;LVhX&*9NVP9AlvqAp4eb9Mu56Xs(9qTI@{K?4qRP+7ePOUV5T>_&a9z4S5Vnc|# zT~ju>o@O?u^OmLGETmiev7Y-Hpsx(!zf3xbIOmu(QYAnQcVm{hOOR#S9I-({;%W${vL{o6YG4X!+2&6X^+A$f% z{tf^JN^3UraqvU7Uh8ywSFz($T4U=>uczei6sw|(Ncs-GN^3i_lLV9dB+A*Zoja62 z%lg!Owp0doPKJHTiu{qiu>xyFzIk2#OfnYi6OrWg);MpEV~?=8awfEGsaz1(`nPEQ z&$dV$?Exw&cQHT#X*t|#pbk3pKWzb5q>b2#lMvjM-MeHDZ)P%fcfJ$SDwdfRU-~Or z(z|s`=8WF0W8-~hs(enA2@6ehi!D1BeX$@e;5#r*ptQM|9+7)s+^u})bBQ~?sNAyb zB<0_s#)h3-Vd%#7t#^ zJ7|p9NUQO(?5?@W$2dY#_gi$F$5*~kwsLUyx+ij_({q*T)RL9?(z^Am{$fw$D!;=j zH&=N|OnN0|GiEyJpQYJ78Y|-8Twx(niuKk1Q~2A{PiEj@{dW}op4)7+3F+r=bK4OO z@A3JV7JkOi!Och^-Xzp)*0=tyaus_-LXD`3%aaflZoSZ*!h(oqR|d1V&<#q;)kOYP zn8$-u`9O;<<0u(usSxF|yQx^J&E0LA-i+1E*q{ZwKza8Vcb3&zk^eZX>Ba)pcVoQ& z1U}^T2dL@f%4g3`U(6p@;rDbIEdmohLLv-+VA5W`hnBfoxHJZ;0=buK= z>t`^lS*s(CJK6TcM{%64a+loRl)2MW>pu~aMi9Qr8=~jq%wpeMY0ct1>Eo{7i{ZgV z?x44#cJ=&V@JFti*Pyh9hULt+Xp)-J?k4%of1A4R&d$|*E!XX#mP)Gz2bW7i7l6*n z6Y!?*tX!DG4{C-HIWu->md;S1|9;2_k(blHS2Jy~keE6YjX>mQBJ``Y_0}kQe3!wb z{l#bm;!r>@?udgfu@kC7G~}Rfco{Xg*9iSqv%7r0kIPz1u{$qtRXCLu(ZE`mbRXJk z`{zc2Q#}dx@+9y@Q|<0cp^L-}n+;}EE?m9?8gzTE9qe~^{xc$dyuVQ_r9ak3?jzsn|ohaI1|}0h3l-=)C|v`wD%uVH-*&9{CyPp&h)l|!thfluN^Ve zr+hvb>ieFdIt(8+_$c7zf5KfGU9B#i;xrPnlcs14;-C6QC>neO^qPV*Wonwncx>1- zPO^?jM`i5Y#``r4Lk7uCT13i`lP>0OyiaEXawo)m_E@l+(qO1~|L=i1FoU_CNh`CF zK^}G)eKjznTA$TF`3ybo8(3kc<}`BV$%IJZoKH}-Q#7psSU0Q z*wIjb9z7zjKLAaaXsB0csDErz$PBlsns~pwm4K9TR|7R@s2RMK{2U4?gDY+#jJ!rC z&J_4Ta1n83Fr(UTWmDZHuJLkPat1T1^6X~~xtsn0`_1sterb1pqgQ2!{{ZZ{`IE>q zEMGl8;Ok}kol|<^Fu<+_2I!G|5pxvgmr)FHqW7OHFvQm&-;NmKW1*krrp(W?yIC(k zmid9uAM1`lRI_xdn0soDS*v}yQj_lQQKQ)k`ABxI?upnnJF8N<_N>YUxY#2N&f2}G z2j22BEI&&m_|_Z4Js{mXuRmUu+TF*Y2y78yqa?JE8p*pQ|}BR#46GpbjO^ z%7CM2SY|SSMqX(&eQ=RrV+&8u57W@Sz@+ALCy15-i^$iuAo6QKaWNnsBtm z`@hW#yh}*Yc3d^uvKLiyQ1qb^iqvfhUQHi{idwe{@1462Q*D(g_mfN+VHu1%HooKi z*8?JpY!n3Unry4vlAfhvk8tRHUR3N7ik&gH3#^)j&crtN;=N{M#o0@E4sns`MWxwG zt78|GO?_Qm^lvrzBQp9H*)NZ6>*zkZ%N-81xu<4lK;|<`Q`x=R?-R!9w5rV$o9U3G z8)G#mg11M=|Li`w>xQ;%+qU`X{nrOia0l$i7V$6R7XNk8B96?AU+F4{&Q`J_c)WMR z*z8G)L)hkieMuQtPu@QtgzDDQa^lS89^)m~T3ylBF4E!OLmrYWQ=4H^_hfo0__XD! z_fEOYp}M-hE8FLrPgJzO{(9R`_EH9{=5ZNa${Y8J_f^xGi`S_C%wj_IxfwWf_0Zl^ zPr*fsL!qhc%(AxhwSZ2m(Os?z*mO;oi-UumMX$)$Aw;q>DuVUNx_5$n`Zf{fN$$9Q zZ7R%CUE}`#m9Q7{$B^@W>+ki+c7oj|bLIQBxyt8k1O#u7viE#o`u(*W z10IHAI-gQyBEyUyiJpm(P|tMHR>aE&B#)n1BxD9q)k4!T%=&)bd zT2r1(-$@Ho?m3nftPC+2mbh!Z48y~q$iE=Hj{+y^g`D94aK4RBrFBVnQ6vj`e!;tM zdb`^~;54!gj7w6xS~+;F<$fXhE@`3fCKgA^GuczZX&B*9(G!>LqiDQ%qF#xtaxadd z>p4AiJb^ZY)e)602*ucj%p;0&(4BHWhB3t=Z7>FXknr}7vA^1;X~>^fs@B=snMB4* zGUnmNY|>n*8-`$Ku7mapjP*D5huz(SJ-K{!x{9@FxT0iP_Yj9g`3%u2+tPRbp5trQ zn0D9t&sa%Xx4}etC%S7bFX)sEN!rqV_^51fG&ETU2{Fke1 z27gz0A6?(>%T?J?Vx!CfR@?5&Rn<{qq|E-K>N;=P)D`%_74Zx2BjXF1e~)#Xp&fBw zW-kLiVY!$fh!xhO%f%#ve=FbzIq(m%^1Clr;iJU6nW~YchxJYB|9de$@-JXXZXk4! z(T-N2pe3M~ddc9FWhbe#f;}K)S#~$;p(jPh-Hbn8SX{7eCq#MCZUbaiYeT_5>4y*P18UeqHIeH00OS_k)p zc}hPwV!qQ+H&||3JKK(7hFgpIlZt=7J#!F04;-eXx`s@Ijv&xyWO(n9Vm2fui7!<| z;gB)%XZX3@SK6dXM>E0?jb|(d18TcR`Dc;8%4qs1*bGrQeh3>GjoKm_U210(8zKaa zIBfDCDD|fnGrSvfzNy4I$lB@dInWN+4^5I(B5wp`JN`C)6Fr-T>A7J?^t7gVdgi}O zo5S&7NZzqCdKS>#o}QN!(UW6;1$v%VOwZ=`r)Tr_^xVmK6B+)mjJI$<&3t_-Gy8=@ zyXSI0tVdPTE|Iig=JwRNB9;DH4Bh4llvbF2yCK<#NQ!%rv|vKWX~8;ezZJ`e!CP(r zH}1)54$h-DRTCo=)Peo2@k8F@30=gM7PPdf~(<2V+RyL2IT%i^1%X< zW!*!$7CgK^@q%#Tg!=;gZL}A7cd>u5bp(vub9PAV2LO3z}EO{TWhK@tKjaU<(<1GEsIilcSUSPvODHBvV!eh(-bkV ztw(do-3NbF#IIT(au`wmF2rX8v{s7YD;@OvW^HQM53gtB%v)GbQmDFj1>rIGI#Suh zFNO7Hl(cW7PYR`?pYNN{gp%3gka6`0!hIoXSE%tdMUFBd{b;F41a}>~Qiz~dqGI*^ zSd7wzbvt+_-gi4M!}^V+m*POW-UqDr0e>1MGT8T}>~RvGT%rC=N^Cl=c1-Y3Y=Jye zJuM-=4UsR~vL{y(7`5jcDh<13b`LJA4!)$zAIl}GFn8{n{VaDYdMr@VCuF}=&DX;b znq|CJ2pZnR#7n3%3;+#-`*yic(xo7=Hr}6tRTRYvk$EFFV6p8(Zg-#jNWA}aB`>%A ze$48GKY7|`!WDxn6wWMz6LbMnRkqWdt9$;3Dt?D$=thC&s+kB`TY#Z$HH7Zx*! ziaOjO9!7o!z{CDvd{?;%h!q7wK%Z&>-3F#NivvrX`NC_; zJ@WVj7yx<&>obHxu`?}HnQ{*@Fm+i<#bDlQjPyP5;^vEIf`R)5J2TTRcX}wnjFXw2 zOfTXa;HMB+=b#^&mDJ)ieAI3X?m05qnf@p_yWAVqVJF9LvBETxC6~0no zv;cnBY*{}81$23*?{7T27JZeItB=H&{F!!O5@$jg{8Ts%ToP-1!{7n-2!Yk0o4Vqv z(p{73CWF6E)Tjlm!CQ@k^N$VI-E<#YAtjsN##KljM(GyIcdx2yGoP=us zzAa4ZA(nCe6=oO&LRjp+?3-E7I{@n}t`}@e0zlJ{}@zH>Ch+qBwU8(%u9RAJ`_Pm$# z3oX;G&@a>T=O_*Sl)hf+#=nNi8q@YgT#jSpVi)poM7gRVsT(DY6G zQY!VQvFZpyPN7rHFGKaLEYvfB6OZ&ir;+LZ9s0j({4aj(FO*;(>tFm#-86LwF|dIN zb2hKqxo8c4n-l(hTKL`&{!R&hYxNuNJD(u}8Y#DIezcV6{~>G(BvbhsKn(nu?=tAXB_gd8qTwQyXy77{43!-@mMHvKk~1r0J7-N$TTES{Zu~vM?}WjSjh8wMefQ2WRu8z$MpoMQ zOwHU*_YJn~sUO<3E?y%BFwHHTyRWa&Osb1F-z6pKKL6d2G2?w7M#vexuKjA%y?x{T zx1@WWh;}e)GCj!f$zE-x+uVdnzNtuyzt~vtGawu%=qdL~Wg-1R(xGK5wU^{MW;j|N ziq6xOcAW;$rAGG_z4sR0P1~_3`=A;2^-J_tK28?Hd~Yy^>879=QB+3;pu!v?FKla@ zpoF=`7V*B1`vRTrKbskB(&Xby4k$H+1J!D7K&Ypyhf`vtM4}!4>zS990*XMIC~oHs z=XzR`XgC3l$VG3pw!5a`oXdBbldxcI?nA>lzqHew774|DrhxrXJIk4Jzw#rIAoU1E zB3cc@@B|HK$tV_rr{ z+O9`%K@_P?ZSJ8ZA-`-9zg%y*+ueVEsK5_*kUJW_cOnWH3I`=4#sS8hw$A&@l9cr| zy3<29Dk}OiMHyWO=^j>LA=P&d7rFSH_s1#aJ~^EI7-fHbG<03=s-bZIBxTz%{U9$})PTm$6}8QDC_ zHESFi68j2?LVP#wm-EG@s94+R>IhRE7CS)2jv214%NJwq#?^iza9_<92!uk$c6Fw? zcg3OwipN>Ch>sc?)yeKe?(~||Q*M4rUIOa8YA)r7`s?F2MABjDyBM3=(g#yvx`981 zETwxCx>Wa5qfj54OU1+ljlb1eXtYW_rAVcY8s;9ZC;+)0Ac(X|f-Tp^d*uj!zf|nt z$zYu>Oh?habuBkmOtk3|H;Fb{&{}gw(ml}bTfl<5ch$Id7Upx?XulXF>CXIC)R1e= zM5N^prk3sJ`v)MI=Jg=_?FxTC7XEIAyh{Hwzb0?KuwcBOK&0@l$2BdKvR7NL7WmT* z73kP^w;b3siGBwUF_WmD7C9q{c@GX;e$*|!ikxyc*#oUZS2_=~dguMeQ6~Q)XnCF_ zTDE1{0beeHFZ1UpHC$&zklYF1+%}XyQ{*56pyZf7!;et zRZv=D+nWYkYbp}{-OL2sL`YZC@J{!&pGHK}l0W)7`;PH)ofnL5@|AURC}?tt=AMtQ5Yk`?t?q z)}H2=K+#&J=_M0^wV?>SmQ3mlnJ5a&V8*Y-I8PL~t52?h?u8>w$!S#px(E57$S@u5 zCzlka)gSQ@v>-e#G#>>uV+7N}aaByYU+h-kf_Y@sP9=k0$3zu5qS>q9C*U1u*kw** zzCbBa6CcUXz1+^a7e{-8uq z2?dhmC=rTtXkTLOb3W6K(2)9-&oFE?_Nw@(-y_1r=}PP(an$)%(t;Pvk}mWJcs z^lwF#^ZIuuV*uJiUn1a19(Fo~nDYAfkFT*prxf(>eW8(Ge;Js3-!B2e1(?|rwZF}7 zf!6*QwusqRGl4fS~e3d1%@#g|AmBu*?4=zZYxc`gfaJkpR#LT|f9YC;u>u}8qEMynn7i<8( z`MYKJ4%yLqnDPIqLR(b4XjESbK9Dh7{~x|Re;6%(G+bVL4aMd0NuqpyD{L0km;Pr& z3)bJ~vi@?Dt@Axr?X=N1@M1Oaj@QBl#`~uNDz87q{UaV;WWet>vwT~j_$4a-#o^*I z66N3I4=AVKE1)pl?BD{!D&B^~d*msM-;n>G3;91=%>Rrj);rzZov!m6+lEe?%dpnU z^RWWw|Ke)P?m5q6t;(M(R6YR;(Ee&`|4!GRl%dCKWPEy9gV;OC8|CN!Fq#Blq+3aI zKcz2FRB++GpI7i>C3o3H(E_cRQk`ydgNVv1FcQlggaQ#_3FK4Vysw_J=#tj-*iF3Vwd#gBB?RhUl42l(Gj z=Lrg)R@mzlyn*o`RN^7Zin+_%OATIoQI=iYvt(J`TmZMCXO_URYsZ>EJujy|&_g@%=r?9}M5y$Vm?wE#D8{QS_A! zFk*&X+?fC=(097%d(&{b;oJ27_)h-7_`db5DZU&eC}JE;8{pm36m08ba~oAs&v0p>b14WmNn;f`puy=sFBL8>S=I zqw0Sok@ok;XUDR=zPmA6VSa~&)AtpD8cGYkJKTB)+vmb3yhDeT8pZ#Yc>X7f6}q== z0y5}NN93R%6n4)rxXwOSUxbETx9~#x36A)o(EhQtioJe~fA=m#- zdvcWfVC^}_YS>|W(z1z1*zDpO$(i0Q`jnl#jAb}C=(NB$x9Qnc8K_#5@x=cO#T&OV zAp45Cn7%-&_ms-nCe3lEqAH$w(1;QS)i%gP3Tr4{KULTsYDRi$he z^-UgXGmoB4neSr$+1tynfxhppkqqWv3)gZjJSyAwy*^&xw7+liX|c?DuuQra*Rjs? zsmea0B#g8*zCcbgo$fyJ(G+XONNF1fp$|s=m(Ub|;icEQZQ)SW0;vktGITx%Ul_&W z{iXg}cCtox$~hJ#qzsJHt5D7V4G6xyT?VqVe?`jsVnM-9ylx-R-^@M$PGt|b>0ou) zP-l5|SJm)X&nvx0Rdgtu{^}f7x$nhZawW^NM=IA4m*yUIC;eUWfc{#f&BeP?`xp-~ zrObfD%LjMno)^=#MV&Ryy@gIhsH-k>x8(lThvKaz+COYq^A^p-Njw1%6E$@=Pu*_0dG6k_iz##4t}U0&t~)vBzm_kTsS9J z`EQXn_w9SZ#3C67ztUsRbH)U%L`GIaS7c6X?@kbS?EpTkJ#IgJ47LPc<>*b%T_G@h z*Xoeg3+@;gClmxWoh-s{Vt!kp|EOtj%_t#t?|ooz3YRDC&b7Fu$@QhG-sweb^7|Dti5qG&rKegjL-hs~S z4Pli<>{}6`^QWDs^*lQGU%pl33FQ~@UT4Y$6OYa!_@laJ^1TdQ8&Bee_ffC@_3Pn` z1-P`|=2z=mjsP&vW)5EbH~2#bj6enJae139RD4L-v025h^g*)jw)Ofbd~!wAye~fI zk`YevY&DoI@c$0+VHx|siO+lgHQem?#ph3C+z~#uehqsB`Xn+(2hT75+fW<|ahg~p zf_oHlb@9u542R@7MkXSEJh5Foo>BBVd{_aobV##J5rR52aX4S|9cF z4)%$$L;IoM|9+P)B`kXdlV0%7;=c;h;JuZvbMGm86JaN;bXALAQVMQs=nwI}CzX5K z;+KsbGTez`jcrJIe&FZ^>qpW`@Gwi30*CW*LPh7zXQ=2_I7vMR)jTWJhpc2p%fg}; z>$VaOm_$V%;Cry;V@6@t9lp{URVrKxG>-Sl(yc2vVNu-g6+ufOj2}2EHTS60U%AM3` zQWsKI@qTjSmU!P*@Ljw{1UA#{sQ#UQ_Xic7DRLGVF#iq$)a-4e;C+%@A85RnjsSOY zLB5ZI_uO5Ym?8o4e(STl$T^IkTtU1&(37Gxe&uHBfPgZfXYVljh4W;>tp!$ld*e?F8}#FzBTd#(Hn@^y6o|MCO!)7@mG`wgU3prfQ%ulO*k zJ_QgbAza3ds_%;*w7%Bu>ho|#udqU!uHuN73X4mvFvr{3AKtt31Geu^WTbt9X5b4T zNAVBGA9VCE7OY&EubR4Yr7M@HDw(?Seqze7ix51@_Uv1^Qtl`J+No0?J#BP6Hdu2+ zJRzVF3&`h}eP(nz&PzAK6j76JuDO*r&UbFe^n_C)M_!5XWs^W#&Ehq3)+su#I*R_U z{{r6pK&sqoazYR^mGq_2Lzy2I@LJb}4iEgNn@=4f}kASk4bS1-Kw9;_bf z^bvpAnmRq$xOj~UnYQN@jc`62)t<>8xIJ(E+}bm^D4G7Z?8j!*yP7)ODOf5jv~2&T zd#9vP`+I|r3|!eqlKu@`DHD?ZO9_zz{cfLMciSdyhDOw^9u2hxocAsF#=T{@sbOqsk z{8C+F6#owN-4Y>f>rv{vWq3VmY0-MLEvnBlsKr)amz(Aj@|{%S_rJ@7M}q%$6{`Am z%;jYu(0@8)%VtHq>~$jM)D?|S`q)0i!^SWE8vs-Y>APC-VZTfH23qfGRW-=91m}eh zlBpV3uLH7uca@SXv2XskBr{BE2F83I`8uEya$2jE7GUXpclj3eD3qJxHrC?qH$F{f zeB(LZIB=|$8NO$uNFL|fV*c`B?Qr+LurYY1Zf(9p<`&O};8q*x{$(8ucqn_vU7{wn z*P}|+4gP$Ya2MX>>AR~HtOIib0k{5hfwBw_oUfA-l6?P7eFh+w*_)o^{tH-fz^4jD z38XE&s}B9MU@W=m6=rV)2kcv!iK=m6j9M4cYa*?#@m4Qu`zG?>^E@!Y^3Z;8n5Y(b z(%suC$p578LN88nJInN7o+W7?4rT;8tcA+xgpK9+8>$3xF zZgQBtFn>n%6)0o*ratA~vT6AJ+B@|r5A(4wr?pp(n(N*{01f1B6ubO}$)sfPfI@u( zEsOZTxw94aGZr2i>RnxW(&clqz0EwMOZTpzQ!KT&gfDu^Ji4i6Q7p3xY?Cfn3sYHU zB}szp1m+cY417Hjb^~A6nAJa%!G(B5;dqC!5-?Sbs|NS%66N(HXSFWw{t?9(J9Vp$ zyiV|NS~3Zc`O4x~G+7R`URNr}EVNg?Qoi`ynp%C`Wg8taWmiUP(083kk?p%q!z9RD z*J=k1>w~+mE9HA;;-^4BV>Gq#8tE%Wv93pGR91~Ld7Bj)`nRLnx+?~MP$WMnU(koLGjW@F|MmMBw|_wW zq@gHd0WRZ}{Xci(7SO#>=yGIbZO@py;=_{&v@!!^tmk8l(F#ah8C-7`$iOFTACH9n zq%|67a*5nofl>URI51^ND3m^^G_sJkxe~vn<9D;ARj*|hcpVMBX6n$9#1>|mSvLQR zQAc=vfjY~wAMPbZXQGaWoQ#iy%1UCoEcM8FHKhw`a>vQQU79{Jsw#K#B)07jjcUtu z2Wyjpa}3wDxD7X0TaHzQ^Om~{Hy6=rz|$(40HKwi0DC?h+-)Dj*-|T*h`o$KKE)O! z_zbS&t<%-|whvrv91wSmQErAZL(fFDs4xG8Q~asbYU0>9=lx0yu3f zQPym)3O26HoU^I5w=~wXAbWkU__6<~0p59FIQ6#bSL3304G*!ND+c_NKJ!=#gz&MI zN7#L6CP88|9}Nt6R7KBsd)Jg%fD;%iI^SkFB$V=B(J%p#^}XlzmTn`fi8BsVjygZu z?)GMn(gPJ2nGOIJ!dn0GpB13+pW?ghw(Qiu61_P_kTLRWPBWqySjdr9vf^hC%1EEC zz=X-$UA&Q7IU`v5HF#4#D|o*w_|}Yqr(_^}*~6Q1roEl>KJYf4C3t7=44#sKx4(y% z^ly8<54_~(1aFU>!BaBuo_y8XyW)#4>1{P{J8N&nIfAz`@|77)KP3ZUv4^+JL%-zx z;GHXYU*0J^l7TnX!+XL*Kj8h~ohNwv?-U-%zf zuY89;Pbu}G2V*5}+6+?f`osUn+`E8BRbBnVGh_$@44zRUMvV}4RFJe1MI{9^KtQUf zlMK0V6ka1h|(!jB;O99X=fCVHX^zLaG($!qo_N zx)A`S!hAQSFIn#RN{Ju0<@gQX7e6lgZqAT*%R?Qj0;Q+{z;yxolYcuvH&la~2>OPM zTEob&$3tG%s8gOifH2%a;Evhqz1fHxR~871YgtI`pF>a!ph{0J51#-OFrR(Gq#6m! zo2KU{CxV_oxSMNHTsz~5!(0noyQSxODbQl{*Xv48Tr8QR$0JDU%OEM@@nLGE6OgyO zx+;^T*I^Hja3U(9CaJFVe@IV-gI=hnD>YYrlcMI7PSn(jxIN#{Un}!|1KbDw@D&1? z_TNd<>n|sOUjMo4Q0R43s_}!<>kU2r4w+u#q!a(w^zwli-O+3I?t{@QbGGArC;nv+ zf+tnfUK|W>!EB+93W%AywdbIpVK0+YWNLi0_GAu8ll4b&%hJ)3g5$pY?JRFd?`1m> zqMhgGxTA{5Do@Mde%oL1*z4h&xWl`w1J{AO%vQ5~anEKx@+29|=qLfVZ|Gq;SJQ{F z(250$SWAofd88-^Lowq7=)#qmWibT&xGe|;Yjr`g!YW3IE80q~Y$L|OB^2%Q%_PzYRa z$2&fYs)bz+uW<_-!g(04-?)W42{;6_9C;8)b(azQI}!jYz@J{J9y?x(mJE3TVt|m$ z4{!dD^mod|-=SOwT0y-YcLZns%ix>}>6u?qslq2pHQbh#TYLkFbW zSjsu<_`TN2{(!>^4GSToC;@4dnM--aBW#}n3q-0Yjn@YXs@0Jn^kigK(h)&Sfn0Rc zT;VMJ%ZtWB;bD;GwKs%+j2|`oP8qL>uQ1(KhG+51_4>>C_Lmp&h2zy9X77W{G&?BY zAP&{Ey&TNwtGzh485^OeEd0@zg2>En8+GCvFVdbc%sJc?_p4401YeBxj?$dcs!WNV=XZXZU1sXY(XU$i^ z@U!fyQ-On!S53QJGeQZZ47$bq*N}G+5ygwZ9RxpKb{s;hd|TiJ1zhpUVO2bCfukrL zA-E0|GGv1h8;+6yLcEfPLd>|~%k74DvUx^g1S`#IABd1JK!hIOHX`Wz$rwn31#)v_ z;@osGLrJY4!`Z0FvDFp)ykz$!rnsD7g%tORW+N7 zTP<N+pW3}x#DHNdCKDx=29LW>viQ| zVghh-P6(8f_;QvnFvI`=sKAwT8Z(0mo~p{A>W31{bs1`s`BuU$`l2_00U{WtbUlG! zr7Vc>)|ywKl-t8c+d}{^FT5-O59I?7UVI6_6Ad7~V?UINa)@*0fs)j43j%aK40bblO$B1cIko7Dk2BX7aMjPV(8| zCv9JZ(ONn+SCAoB)p#NW(&KfN`kU@Z0d2-c$fN!4`TxLC95|KrvL?(1_+tn~s{;jY zwY&@iELR(kdv>1t_x-sZ*7`9a1J=FwB(KYQ847ZzNkOO_XRk| zSvGKP$(FjRF(t3p@3ID37kGxeUc41}aawCC8!)%gbL!ZV7wf+<4G9*{CSGxxsGXgd zLoU-SxYqs$wua;Qjy#u^*Qu`Q-w7S6CC(m0%}I8tp3)uB0+DaE)YH7j$E;4 z99UqSuWqXOHCUiG;c1+lgZ|%z{_l(ESXIHwknOd|zCYU@6&d}X8aMRfu*Xb|FrOAf zY5ve(?T$$66P@{ENcdw?~SLw-RKhx_67aF5L7HW@VxJv^j8GP*U`xj!EHg=Vy; zwAjHNomFaqKmeUbWTa!@6aO|5CPrG{NXwJMM4ljmtM-CziJ0afrv@@{H-g}?f3j_M z^i*`T@Hg$Bkcx1c!z5NAF$U{yv_iAskrxmz$hsLpTL}uO*N*gN%>Lq*24_1|FtM<_ zLY2Qk>xDm?f2?t{Q1KH0D5&QB5mVYYIJD8`_^`%bKHQum=dF^z7X3yCZIb{`ck0lZ z8Tz~fFEo~j_^1C+TBt*WIJ#g4)4-kpV9^vk44}15OMLw(=TD8{m4ad9CHTVv`Z0yU z3iYe40)6uFZ1@GffA-Mu{TA>^NIMMd)cP5S-G-_;>re)FlCLPQ@u8+MkKbci^NquA zh`tg14?Q#sG2BGLXpgIgokqh5h$C~3S1?386TDgdAsCO~!Qk)s)~Dn!BZk=Oa#T3L zU-*Ra(2X@#;wK%IgGcr$ZWLoGNo6!#ipMm$cJ~)@VXt@&BC0(P6%(LWtLcbBAsvSJ z2T0>i_YnDpOJd;#`^+(^&*!5NtVeJ3Sc`Eu*ZkT%19zMtYumV47#;YT&L0e_J!Ac) z=C~RoR%$~^FC1$uqX#tj@Q8N1Q=h+Lr9HhQJfX7O;sow^&d0%;>In)7tVYo+@^Q?Q81`h{~^uO zM(mGlM+@pq{&*1A36MW<8n-ilSaZCI6Ol|Pvi14|gP`c0RLwzH6&Mn}hOG2&l(G7Q zpT~Nl?e56nXgea2N8A08fx)nUDKvx)4oa#dF5Hvo{8qTu!tQ|e)V!7W4sD8*ugx7Ct^E9 z1H8`x&$ppn?3p?lMc}Q`mqm~dk+>s|$>VCsU-HSG}qDa!n zB=I@rYMxI0bYD1mf%U{Uj2-oArJ9c7lP~RnHMx43tc%5tShFMZ>nmW22vVBcshJ zHIhT*6HIQk?()>Ce^b{E&0gR0yByaMi^WX z=a1E1ByZWQ=^fy0fzJukx@_Wfieo!X{2NgO_KiKIhxb5F=0&a|H7F)EHGX&yYK+qm zks6uzK{EhCZraN6NjLbm*b}7f-|w}?)&$Gd#uXTTvZs*>k?QLP(d13p_F7`vR_YlB zc(qxgt+WQuxRP7<59eQ^1@_G^-ihumNY2S@pH3`I1DYnddF$XO{@xq#I-y7J4d&bH zzdEAn=3R3TJRXm}MtAg|=ceCt8^@#*8prgAesXTpP0ZXlCI``DqR)GxtvS(T4w&L9 zTxz-Gb}V-WpnhI(IjM8qsJYRt>xSxyn&a2^h>ywn^XQ0g{TI2cx=E@wa2s^1Yc%ea zMMvB755Xnuy*DHuVlozHw5y~}nLGMN%4`Ed43oGj;xG>D2q%TfP)p8-!60bdaz5W- zSF$Qypw_VXsAEcAGnQY8R8FWjrSaXM!7wUkpJ{pwgTyc7-~z)9HcvBC%6upJmhKNZRS*idP_kQ~ zPxuQwspSnE$TUcui+4F4k(hu< zH>0Pnfbb-#C@F^X{L=6cs8yxz@yZ;R_zv0G5Hxr9muxD2ky|?iw&wPMB`MH4!R;Ck zLj`X5_9ouP1f5#1r{s@Y8zXs@G3pU3mGlS(OKrw@`oG>ci*dhhwmho;-}XtSJkn&! zZ!J61)u*-Whaehe*m$K)E^umrS(&-(o6!q(=!KQGJRb-$Wy$llQdwSX)bfl=+Cn?5 zQxn26;Ihc2&GR6Bw`1%Cj93vxLPyTx@ ze*RYau^COn#nz2tZMLDb1RF>7S0|DHBy+xqZ8jPoL0W99(Re?8&0Vn;qwx+tsr4WG z)^9(e_Y3Pk$?d%b2j$kA8;J1wgn#`P-o^`Ejg{`k@jc*+<-r7z6ZHgg*a�z=(6g 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

x8tM1U&vI%f85M-kh&a< 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

g+4142`ZBK&MBTSqQdq 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Ν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 )kSS+GRQxR@w-N8N-a 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 z zpD=$y{CNp~F6EEKp9cQa@h8HcM*h_BrV9M^q(imX8a3UFdCQ`Jw?qv{trlk$ zwR)oPBJF5fTRSOeONe%aXj_Q(RcJd%+YHjSeQ39bc5i5hN7~qdU)$B8Egjm{skECz zn+s)jLy#}+Mrr#k+P28j$MNlbI-xdh%fZT`lv^zyxNwlX$dm^+)MLQIwhCx?(;+YzB{5N#WQb`iAAsL_w%y!WCWLE2svZAH=k8SO6owrrr$?$ip- zrEN{EvWfObDDP)cr=Z`aovGiJowbWtCwJgpfwZkPZMTYcM&{9W9zuQ7W)*FR&<-1I zk92@fyH(5Z({@!J?e-Dm^&GBO+pPL+*k_~7D`}(c^(X_*CD6`Zi0v!dbfb+p+P})b z0cE=dZ4spHyG`DQ_WD8OjccG?6xzaC{s`_PXcpH%8(6fZLOWQr(c!lPN4r=S;`r@g z(Kg)dJ&5;SoCowf8(64A^u7P5ZD9HBUj67@IOn_3=Ru>OQ`x)vovkah-?yTjz6Jg1 z9cagQ!;Svsw`-_vU(xQBwnumz;{t69(bggDUD4hlZC=slq2J~e?H|rTCTg2kw1r4} zg0zQ7n}XUVB5exNz94NQ(#9a|;LxTK?PCe{JIEB;#nN`KXuIkn^fTH_ybpZZO4N3& zXoHTntZ3^<+fAfht6Ahv+lhIU(*$W7inN_bn~AdsqYcIX6Z==csqL#5YV&H8b?{-d zVe}tu=ju1L$|FRE>0X}egoiA6i3e!Ez+>?@ER|6SWy`_Pw|x1N(zPI4|pxk=q%(W=U%)f+Kl78i*i<9v$P|N z>*sZH&O}*5TY;RnP=<3JLpxraJ5jz+CVcdZC?C$rd9|KLbFNK0sY@Wv$7%a>8OZrK z?HqD`&N(>e>_0*r+VbN(p7U`%U+4Uub98N^jyCPs4>_N-K(s%`wG-Dkv_;A_1=kH+ zLvZcGIW^~-lvNxTI6iQ_KwE3Hvo;B$?KRq2(>B(Y;eHN8yK}TRM>}w|w?;c`w7E79 z(zfY-1UGHP(LNk)+0jPbD2R6H{I=%&_T~J2!*3H#+k9JI!1+P6H%HrWwC_fnbK2J2 zJlwP$r)|NBKf(Dyw3$a+c%z`BpgGV-L5rYAKr0~Hz_UO*K(u>DTX(w8`fb(GJ{|4o zwSs74PTRX^-rQN{$K(tp#8-=u2Nc)AOpratJ%eb!QI+<%+j{UUN%rye-FpmOhw^7g2 z*|%xOS<3_qYgWnyj%i$5YP*ZHv8Zh_YP*iK3wBJa(jM@gHw%J%|r%~I1v=HBK z|54k1thC)|VqL)ThxQXWhHy+d4w?ro@_PRUWe1(go}S-tKpSYg>5$fnD{G9i2 z{=>1GYY?taxb~tBf#V@%7;SITCNK32w9Csi4%asGsAI0zXy2CWo5gn^-kVUbK-#EX z0n(oqlPH2ZBa>ovBv+f3Wc zwB1bm%s)b%oXXB9?dvXso&(XoF4rxz<*RM?9*0}o?xmey+V2(jqK-gvorC(KU1`qQ zsB@SDQU9t_mo`ia(6_8&~M7;_1F%%e28vyU5y(GHoo=Ml$Us z(}wag=s6JWF4M*`Z7$RHGHohr`^vPptZgsTPBU#9(~dE17}J)qwr$LHG1tdj8*AIp zv=dFc#kBdX?LSlRMw`aejZsHMy&Ls%)ZNgwwzkJk9T)Xl^JsUpSGxqFom%QMIQQq8 zfOF6TUhwzau-;F^JU*ST)c>jTsr#rY(^6 zZMD5y>JnN()QxZr!?_7{BvOY0q>h2Q!5tv#&8TCbjbN^8W2+Hd|SXc0ucBz1Pw-%(#l9Uk?0QiliRoQ7*6>fIKRFLhokpb+E+?QvVc z9iTX95=8slv%vd63!txpXs?^|FKxS>b291|sc)oR;aL!E4ATZN^@`LtQtwFpBIi|{ ze@XktK;Q4yNc+ar<#4UY^(xn+%OL8g%#WiCAkG!J_M`slIA|V3yXMr3(cUrb z98+(26hu42w69K`?;?=;F6x)4GqONCK(v+2H5+YBkAkRcm;=#{HP_p;Pd$1U_@Fru z*Q8vBc7V7xJH*H+g zF7{VJ%b@2#w4Y6z+1j2qZD`Xby0+0xo87bpz67ETaPc&A> z+We;NZ`uN3m4&;R^;_AF=-v`qIh_O@3X zX7sUDyoxBUcLC{_5I^4LrJ0L8W_N7y{BGnm9I-9!Teoe$;>sOYb#`_4^zNyQa^AB) zkhXO`t^yYSqrAK;6@C-@_ve0$Zw7qxF?)UqW%%}E_VTwLvn`N-KMtCw`xM8F5DiO6 z4|`J$PXkN9bw9!T&cH_CEx@aRDPSM)Cg21x4V(cU1>Occ27C|jR^S2Ru%Vxr4>qKT@nFNNiSxmRHxL(s4fhd$&9QXuH6mmA`Yl54_~;S z?{^2_A^oOD5(!A_K$n6p1pS^O^5{O@fqoz9s5;4h9vJ|l{v$63rh%^l-UGZ9csuZI zK=k*>2Z4|uk-r4a0>1@B|BXBaM8AtX4@5tXoLPO+9tSo8(f=bmfRHzlL%@51Ss?mL z8OLK**iQe*!-Qtg1apITbkz2>BMd z6bLyJ*$l*ek8}Ycmm+Z>&_ zBxszZeZI&gz`KF%!1n-qfcFE_!1n@=0^bL`ANYRY7lH2t{wEM}HBu8iNqHG*075QB zt_I!=JOqSXkGu*9`5n0#h;bk?2fPjVLEtId$YMD1DTXhFBTK~jU}S~35RCj>rVB@c zA@~=Ak#mUoP~;^N!;uZdj&S4(;))UJC(Z>UHxT3DNS-(wjND3`4@KTV>;;zBs`zlj}2SOofr#7_7KfrWRSQN zjEoYOgOMAFE5XPeL=lR-i)e--eBoLxr@MOuh? zBNCJTU}P^b9*kU1TnR^}iF4t|9}r{V$eW2)IPw6|3`hQwI3JFDgDC1E%fyagL9P%YeF0zM8h;Qn90stZrrA-K;0MnJ#90q-e~I-IBj@#a2@G3E1KIp-H~9iIUY z6i3*pGDr#0xV&D^z+7TK*-O=gFwj7#wj4=W#e%m zH?YZ6M@R&_oPuTN^PS{JY z@WoA>uuahE(lRUnVq51iS~_8`#7^2j2hmSH+dhxj%n7@83;HC8e)4sgIC8>%G5DKR z82boG9ygt^cY@!i!q{hY*b>5qz)!0%_92#s$NbR~b^-i9P+>vvbYEIHcEY{`{I{zx z_BWj_hOl>n|9}eHi?AWk2oB;-}p#x;J;s?i>AeP@xXTi^SvmhPMT!VME;&u4qowEinrg*bJ=EHMs0r4EX zPZy}NT(Ji4N*_;`C8>BUpys94;6c7Q_ska$vdpamea)CB$#Tdxg9bwWCsjQEIUe-I z(`ny;i_q7huk8b1FfSf_v7B+~Mj0=Q@ABFW<_DLJ(%)fRHsj|bK97YpcuvR*`&~l% z`16nzzdT{j{tEI!{FBX;9ie}+JE|S`>2gAOn_|1ATyNS7gdA^rIS_KZDF;OTHr)gq z2ObAv-rn>PAjXlVMIgq7rXK(?9yI+72zlRRyi|@WO_u=k@OJ@mPnr$^F}^e%1!8<@ z`VbJ~OVd|@rz~TK(R7mGaii&3;;7M7-2t>hO=l7pf=w3_^F~vQIBPWRBF-62FC)$y zO$UjwP}A=d7lTcc#08`2)zWV?-9}t8n%+)a4mQ1CqS5qe;)>DqS&6}>FB3(m=^rHq zoBo5?5o&slXa<|AI*FmCvx)P;rU=mrHeE%G1)F+^9l@q+iSba=%OwVz(!|kVQ=XU) zHqA;5HNBNM8*I8?hKHIyLR< zcLV2ugFvj?nqL9D1vmvne`r1i#2C|j9Ekqa{2t(&fe!-T4*Wb2>$>KD1ilUUG?0}i zkB<80nmzEx>zmIej@CCf6Z7@WTZwZ<^FHFd(L5xvu6dNW9BMvBwCbC0Coa@A-y_jz z{seK+X#OkWTz&J`iDrHC3F3Tx^M4Uz!RFvzU`Md|LSjDH+(MiUHg6@)1)IBxqv7U* zGCbUzCC&$%ZznDUo9Bp2_08`iE(e<*BATJ*C88B-{wLyWee*LC!_77O;9se4zJRz~ z-`qxAtZV)~iS^Cb5Ets3M~O?J=9`GW=CJz8<6vCb5PO-_V{GUKLcVP{2z0ZF85=V6 zcNiOv663~(+liybhP(ao+yv#0#T!oAPk`jOfS~xm(6H51wDt`T$1mTqId(=}cP?8> zXG?9v$MWf&mYvT}Ws-I&lgnP7OBVBOh4hUx>0-%?w?CboC{6CPno?)fol#eQHph2E z!da_K067jF1#&KS2e20SRv_n6?*RhDp8x~EzW_4+=M?`divMlJ|2~lUJOiu&21cFy z)&ZGc0}w->*a8Hsc`S?}>_^TxWc}N(ACLY9@t)P7nt|9*9=}ArHi>fRG2`4j^Fdqr(t)GdymH_YqeN@u$R5Lwt>x zH^gJaSwlQcoHN8viSvf2NdcD)aSn085SI}b4Y8fLWQe^)bp(j01A0B^9?&0x z{tWbW&95HeU~f95n9-Le80=078Fdeg%m7Hh%zw95jCdgd8+z0az5PB#x4ZIC_3phb?*l^qnhyYHfqxFX8Te%& z<~!y;0B;5U00{YQJ`2?K>EcSr6o<(Vn`aO)M!tk-h0QI*SlH|$c7)9lVmxdfCXR;9 zS>nPv^FHF@I`d=1rFG_C5trAQUnkCm&BuxJVRMDJfbUXF0T;vOrNpJMxs$jYHiw9@ zGt4YeoMGNZTnU>WmHc()lH}K!|3NhC%+NH@sxvPm#_G&Cv7^p>EioQ4|ByHuGCwE7 zL*^qy^9=JDVn@iV&jOd~%?4sVWOfi|*O{Zlxpn3d;`}=EO~iPe`BCC%o%#2~4#QlL ze8W61N4{ZRLChOwoH%Qklf=1@IV<^f=7*%;FqdR_ohkAN7a=oBoU1c$AetfbIB~wt z{4?T0o%u!SH_T<}51G#p7el6TBeBlBglL7#ZN#NI^BRdEGeI=hnI##%&b*trXqXGc zW~cyMGE9rOY?xOPR}6E2Xx5wKM62Gsi5ROlZzYb_oA(ks z>dgm;@p|)*iL&&Vd_&e5_=MWd_%?NR^-rP)Ft~d7(SL)5{h+>`jDq=otzJ@p( zHt&*rx2LV?=s0rHUTA&7?f@}@6@9{vZE)QF1hZE>Vb6oe%U}6~y{z0a&NaUHbRY2i zvo}FDbUOan9*^(O+wZ;)@jnA1?+Xh3;gxQVSKmZD$WO5hgq#%r4&-?CQy|By&{1c+ zY65b+x*EvwYA=xE)j=R&?W4mGNruM_kt2>8;`PM5A>KxuHN^XgbB6dhao!MrMO-w* zH;4;{c!H>o0PsKIH;$dOF95ZGbl6(BToJw;f5Kk8_SE(GzYzbdS37y0uW+q=HIMZd zK|I#q79i`dAISQ9Igs^tBaq|$>w$psqr(tyBp>y24{_8G4-ip5pY+A&b^o=`@6RNb z@~(&O*)*>4wHTj4jQ0bD{xsUn@;`%cmj8Jm%U}OGr~DTHS^lj+j7Q?7KwifHknLa` z$aZi9$aZiu5bGH6W+292@eUx?;o{RkjLYH+K#X_dAAkVo!1aHheq8^*6LI}NC*u0+ z{{T2^hzp5xhS*4)H^gq@f+4OYE*fH#xMYX|Q5~!=9wun+51z7Xq|ecbD5tCE)Be+; zIsSybG=aL!JYnCC^V|>mGtk#SCqSo4i~4I_e!Z;MRxvBc4dh5cS{M z1w_5J4guZ#7LC@!^e-8$w-Gyx*87PoM(d}EaijG!#8IPliMVXEK1s|Qt(v`7#jYZ}}z={ifv!Ao@+q3K0FKMcgjugDovU^q-cif#^RiHW2-% zWd?};*zyJ-=Fctf1!7&_@|Qr&n_K=4hImoKIXbS~d`^V9PGzveB}i*b!{`ed3DIQXq<8%U#5Hu;qTD8EpBaeQDVK{uq9?zyAv;+aHka?}tFPzv?$S?eAP5Le$OS&8RAmnydf?pE*N45Q5^x`Y)FWG;N1Yqfo=i44fHgIdS;Rm8O`bmDC2;%0E8V<5n-Pco|7sxX ze+bC?H3{VXx(UepbsWh1^&ued&!>QZ(;ukcFUxpA@m(V8nTUF>elrmDd;t;l+)6|} z?;x5%5htRaCy0xNI7VDD#9N8WhWHS1#Sot%&KqKhsEz=T^b~kM16}wQJSPL~0o?#P z0y+-*Fz9oj?}DBIRlW73eI7{XLyZ5cSLbwhfR^5N(*7?H>+g9W>ucTHo%*^A$oje( z$okp`Wc?tL_XulX83gRuC&VZIFNc=`$31TC&SVK4j~JdpSW{6F)qU#HWECSP$t zg)BMFZ$;oLFJe`xi9!`z&Ow*@3*atR{vlGG7t@WZle_?QQ=@wD@s8j459wJ}5-<1v z$A6z!?PuYCu>Ew1S=lVUtQU^MI=rCeQr4 z_Je+Nel6tdJs9JD33*e!Y|mCL+pM0^U%~%8*81Snf2t#TpQD>LR0P>2!3)Aq;z8cZ zy^ii$%PaC0z*`3-@gOgbv}XfJJjnAOD}Ut4R`TaR&V5YZcgxuAj|_Kyy|Xq7z&!&u z%S89<6d#u_Zh@P6cb@AG6^HJ(s5lgMcf(C2y-&sGH9r71k@PXRng4~LPpLR`{~6q8 z0WSi5NyVZ28!8Ul<2T{12hx24Zsx}_orF8A+|R(xd@cd~5^lz&yZR+g`7eMw2sh)? zeKy>T!}`4dZkCA~l0&bS^JWx{c z>7It0`Oy6u<-Qp1JK^Sa(LDz@+X6?acfrkk=zgzq^ZtK8xvOx;KCI%?{h;Dgmi&q0 z)BV?Qv&^+{e?hqoxWBI4LAbxI-1t0{cnogVPYCX1xLG#3{Ri~h(U|oV_28yd!!Ma0<8?hJh(Juh8UW_gS-v<085bMO~MVCFr^;fhVcqi~`Al7Zs1Q6@C=uzM; z!25vyx|i!Q1f zW?eK+Tn5bwBf3DGH=v&0qT-vV4Rq8AgF zjp!EQiV=M&Q3RuLq8W^i6RlwMHN?4a^qs_5F#0FNj$rg*VmuiAH{yIa`b*+yFnUfa zFdvLI6K8|b-y<%BqX&s|!DxXvAB?_5@`KTj6BonLFG&nWmx)Wk=+B8(UG%~Yz*t>$ zGqIyCx|bNQiyk75)Wx4% z6up>eg`(Stu~75?aVZ>46FZFPYlv|pdN*-782un|B^dp4q6kGFmbj`#tzww(@Wv0i z7eNb~mw0`dG$1OGRO=l>}%wAneo3A_-*^IO0c5YOKRyb{FozZ7^a z=v3!K6nV@cj`ac5-+NJaA6i{kkhdEb5ho3N7&s36S0Lo=#{U9Bu5JunF6Hh<3kZ3; zu>+{{M?2Ygi2k^-F-sgZHolgaH#WY>AJ0ut?!fsriI|l8o9clm$EHhwZmbSt({}pf z#-=@fzKYP({R1zq;^{i6L^sdhIsRX(fq{HFJ2bT4ifz7X^NvZYeTQ|xK4!JYVmrh@ zytf}gJ$-{at;ppw#lq!NxuiXHd9gSZ5!qbHvX9uADSK=xErus&tj?JUCXa2|xn;-B ztvj4N#%3~8B`cT3c9No)NG7eep8bj5{+_1yr+QxI!nNr($!JbaH z<#QQqSt(d;16!@OX}ge|+?Cn3;|iDp5sqq`FudCGF_sVv{%P({&t_LZl=-K!`WIH*&9S%>!z^&YA?Q}=<2 znz&}LtKtHBuJ7+W(ASN7xwo&s*TNx^x#@gnDqWEG`amW-ansgzk)N_l{*gBm4J@tNZ#7cJA-%+3n`o zIn=*-i5iBY=5RAvkrH%-lmrj$VP@nX8POW3JYAzdu)a!&Cw%tZI3 z$HW25G&}PJ;4$&CnJj2Zpht+IbY2W3OQJt_MD(PSf;BainaJ9unL^s?oSMiLGNnmW zj}SXWQ>^_c`bixl@xW?JB7TNu?T5TP;xl8| z@MRrNA1h01?L9CouurV1J!K(5YNz{yjbA83mz}aond!83#GaZ-yT#}$7H4pWo16<_ z;SSnUnN+59%quFn{SXgbY20{hITPLKLMb!OU1#Z?PP87oWW(9Cqj)e~C}J-fn#a_P z)fzk6G<9@?m(@_Zkg=z%{+a19oK;w@{pktpT|1KAAnKa7v=>oOS!cND9mTb)6@o`* z-Betaxl^UQ7>wiU(DkgU?HW{DUv@ml!s2{BuK(6CXe4_$o4YA%c~Ow&5bns4tycOd zcHr?ci=xfDGdv^fsdJpd4)w%rdb`VWAg>4gyewOk*EuDHuT{!fQ#sr&FG`(=qCLq2 z?SD(6uYb6AZ||UDt#VCQgekBrVWbLFw_3Kh4jZ#XeDJlNO2 zS4QDHsq)yN;|_EW_m;(W*7}w4Q#!uv&rT@kS(V2-bi9GCm-TiJ%V5sIDv!_Tcq7Am zcKFIlJwWAgQpb(sl7>6G_V@Y{ATrndm4|tys*B+(w)kUn?O%EH=(v5I+x>B=tEfEk zI_}=ye%y}z{`ePHMuz`>9e-rFd${jFuZ}|fOXcx*I&U}naX2M$L;LrD>d@?1tyf* zt?@HD-cawgBfb6Ix?-qnsXR{VxbFR@E(N-yU4gQwOlw{RJIZ}S@%^3G4`ck4@#3vz z(WE}-Y8h`3O>|)JdUa9E)7Y>&ZVGW_AM6?!*x%dPuVa*--Pz+Xr{fNnN3M)Z|7UdE zJ*SV$^ZiK2_4n6Azx$;KuD{9-EU?bo`J}CR6~ky^rj#sAJA+b+Lrf*TTqjgmnLgE? zNsQ-_!KuPC6WG0cn(!H4V&qYof2KWEmVfU+x6rku#U{j@rEZ<9744BCO35DwEX>im z2m9i<*#fPicd);6zZmSrk58;#&3kNZ*|J;sWRhZT-7S=Bo9o)XTeyvPsCO7M9SG>Y zZdD?;tt!7KhYn(jJAlTi0z9FkMMP!y-#geD-{)pr-qFj&P-Ulf%G`d{ZsB#^)){9+ z+#s6Tw(P(_&6!5qmhEtDpGxf%sa;KNU` zrb~kCqU00>mTO`hK@++BWV#?)L@`}Bl1Zj_wTQ`F5fj>tBA+Xi;B886*8i*=d6b_o zlT(voOJ7r0-@q%HVmqb|p@MMfsn(`cv?;a0YQwzC8ppju4WOtN7LHS6cJeR+RJ*WB zcpIN8P$nosW9d9%J^%YDnC;ymgTc5W}Pf%Ssb3L zjKQ;&G4>SFX;l)Qp;Z^F@`^D_jBPuLn0i`@DW1STrkDsSs=%v<;+@^SLzhE-4DGI% zV2#ErmxgK}nM~(P6{js06LvDMg!Shiu`d9LQ_$JquTx=FK+>t={*M3KsheM* zj-OTa{P)05{vXu&Yfh17^b~yFyH|h?G8_jb7upYofh^Ybs~Zpl&@gu@*(GMa_z1os z_Xxf>_lVsATKLi<_(mlB;9I~sAazxlY^H>zB>G2+t9dQwAn@=E_3s|B{~SbIi#`SZ zCsf!2z`MWU#XIhEua)+9Jg=@^Xk84VPPc)gzPdfr=YFC2tQGGExPNSC`qU< z$JMQk(haSxWrJvmwutc@l%=gL!rmkb!WK7)!Y0*Tb#6fK18eqJGL;^$$TWcoid1QN z@zjUdVj^}_Tuu4vXs@hJoB^Ri93*wWp5bECNL8y&%Yvk8ZU>IMW_geva>AM*SuA;tw^Aox73=(u7d6~ zRyG6f%1kJA-V0I6j%C#(&#fO3sH%clv+5dk)K(nEuQ`JM%_HU)fVd9?fq7*R~Pjl%<3E&`<@X}Glj2^0J z*PTeJ5XqTNmnL&5!FrTG?IM*Po0&*VWBry(3M}^omP=eXjveD=(Z>a)@^L|w$`k|? zehEBx$a1MIQj=wwAj@J-q>g2g;bDQ5b0(V>GZ~Ri@>=kW1dd5DmIY$8OegqUNjMiI zoo?OHF?$WZ!3lZ`=$)YVfIbZRW6(pOzX5#-^fl18Kqo*?ft~^V3>4b`q`eMwA?OlN z1avuQE2tAR0J;v80!@HsK*vBggN}pl0=*6N4$!+m_k%tPdJyEb2|n_2x+*T)p3WqN zyzBZAYa(NBZBJtF(vV1FYH>tl@D0T@_I)|Z3QV%il3_z}sce+ot zDF5=GcO@C_~4{FmXK7*^nVqeCy8g^NFuqmt2a*ulr7^xDeu?h4H zsBdPt1WfO0Dn>2bWH?fI;E zV)tays7dFW5Ns7F*K`_jVj_i>LrJ}@m?*WNyhm6N3 zg3=-H203zsk&eOZp*WU-cnU}kH)aqabtT5H=^naLx|q$utuAv*yL1kA_V-8!HdaVf zPv@D3d~i%h7W#7Z8#YTvP>3-+Jd|GNVY)SmD~5W9Y*b=d5Y>1XrSe#tL$X`Yams{6 zencdjObh8#+R*7taoR2=Cj}fu8C#w*R}|wIXW_W*%$y~&#?hLk+&Y$< zv5J$q88lTc;^o=%6l;u?oxyGp^lhi1iE`=3RB>Y7gP!kVd!Idjz4bCXl(5VEtb?!N3RH{}W`D6=8N*r7|8bQIx{35SJ@D}?RYm@Ia#su)*j1A$sXDVQdf@ls{sR1FjM!UQT)1Tq%3x}3h893I$bY> zMvjwHJBvN@Zo-^o7qLaq!XqG5MH)rI1j&uS(^5_&mCnkyFG-bE*0fzrW-@O5ICt2q zS_WXB3@;#yf@U!Dn$D{_RSjPUNO|o>o8~SkKCALLc!Ef&>@plt<$8;0wmCix(K*Tz ztNVa!R|S~KVkZ+ukg2tcF;g1f;e-f0(`0va+K3unogT&ci|Smmpy;5G>-^xCQ)bEZ z3lGV_Q^zuiqDSa7mU!BY?v~49+?8V3PNNB8 z#_l#$=2CX^$Vg{%GZT}RTn<-W6#Q~#!Tyk(%;90CbFt*lOqDXY-V*w5>Xn<&Hbmopp~dt5V+`)zha{(!>qm znNdvCp(9D$05odIJ1Yx;T4W52=mIk)Tt63Pf|sY8o7a$$O&Y6E)E@IyV=Cm6x~sCO zv8VX_GEaef>TC#=CQ#(>=3% zHe7kpGg-agO^q>}eNiidW6dzGs?@DO1V^w#mavuUd7kc++F$;>)3WsjO*etMMkx?< zBCOc-9?LR5y8z;FTcCFyx4J3QEIc8=ed3zdX~HvEFI+vFMHU_pLnf68oU!@K=0#Xt z7B5T|&g-4ZMbTzs8;sm~q&7p?*mfiRzD*7;Pj7;78ES_~XB<1mdlJ2e;&QE-@U{mg z&_)v&!yJBhm%@F$-Pa_B_xJWI|G@tJ*m#)0mX-s3!`L?FvAM-hmZzt^4=1RM;_MRg zVqnWn4^BVeaMZJFC;dR8vqzmjg=JpFMY5o)c%>XRlPm6_M0b0i4hIpV7f_)>5`i_bfgtq6Da zvp6xP#~cBZz|tgt%;7oh&#R1qk>U8raH0pAFDC-?OE~EqM!b9YkarziOl(iYyLuDc zDkbX|vNGY7fV54?;YImf|korL3rm5(O!j0#2G%unqiW@-{#r3lZxgL3som08I5uJs5a=o{X zQTlPOpw&$$pevGR?e85P>h8q-q*hh`7#LVs6>3EOULZ(_WOKgVq9lmIm<+!E|Yev zT=oz2@0Fqv3dY2Nfu525z1Vi%H!R|vgG0TE;m*ByPh_ufx@UeY-7Z_9>y^Ht18n(R zs>;#|$6vzkd8sy&mnnO?yv**w{p^P^Bsh|TCfJFCni!BhQO3bLD(Hp%-2*+nPO!sp zx}`6MBS0JmB%*Y%8f8wLUbu&&C{#0UE~ur_(ZX}Ev|L~F$q1i|V5yNi45>R-K-scZ zK7&CP(=%!&RpQ=(JzVuD6%Yq2XJMAN;etW`xxZA}sS zLavxnoN>D~RK}I@)MSXUR;Me@Bq!yQ15u&)$|4)mQFulW1O;oU3~C z_>Laf-IA3?bFhKP!HonOXaddWJ zu-}V!A(S{Gi<(OAj>OYCJlm5T?I^oxG6)f|IY@2a5Zrxvb+vChz)Lo6>Wj z^BT;rI{OBtk5djN0VeoB$Mx`G51xcNeqN&IiaAbM0Y0b0=H^Jrbkne+F?3<-#}lbk zBYXCs4!Va2_fz}b?{hg7#!Wd6Q@S`diT#+abomk_bws>@}ETr7ejSzhTiJ>lF5ZdV!G|*6n<#iXvS_kTDUJG>3$EZwk6uU)_N8L(}YHY0G z@Lm=4-?&-*d}zQ?ybCql0~w9ytvnADqesixvgcqX1%-QAfGpOk=(273a-GSeO3=dk z6JyzStlyN2+9>ciheLDLPL-Hk`8b zgP9esPrd;qH{*k~cTf9t0=JgI+AUN1{m>(ng`>icq!YL`<;gsD!p8G^e-6bPSNY}j z;mkZ+JBk36B~mEHnttAlBGj3<3)ZmiHj0bubBdqOwBuntxazLSy#w$P`Gb}X-%N3445KKzFgHDM=|v|y zFZM-14Ea2XB=_IDESW8WG3nRI;LOsk$33kg=Eef8ze-N!phkCklZEEOeWh+7o>xH? zDd+w=KGxxxB1RbX?8%MFPUz!OB&5Bb={!7fWC8l6b5fp7c2nFvyg*Mr92V3ccm$Mz zuAO76+X-cVR=RC=ZEu{*skbk^VM+~Os1jElu9XnDdn}pUl%e~#*4aB+J3eVlq-Lh` zc;iJrc1*C|JeOQ`%1Gq9k(`W+PGr0Yl-NH2d8{3BneCtODK{fwnmHhpe{iH;SFwv$h#E zl}pH0soZLXMjwibo+EeX&TjFcOL&`zPHhQ@svg=@^V99>&Xb zQEDz_O0{o9J=MjtW7f_Xx9zykiok#{r%Fl&vVQbqq%1?cM?rY%1l<%PIK3r_Su&m_ zN(~-$m@|2OI{$+kR;^CJw=(3gNWsP~gaK8)s)1*!>M3Sru=8w+Tt_jC4gy7O*(H<} z5{iAiF2UZ(f^x}+Cr5m8>OQ49lDDvYv79nW+2BqDyocgiF$p=ZnO162>MF}vN`L9+ z$z4#ZVy5LA+?YP7UF?3bA-p>jQjQ+Y z^`Y?PvDxHYNvV|4c(N~N{Z5-(Gc^!K;7VS9ufpR{RUp*?==Q{R zF1U9{f#CDX-8eFy3Wr)2YhQnigYiVSYzuv8ftbEo~_j%T9ZE3p%W z*N!VhP01K;ePA-lMY_wyqzh;9wQU_ep+%j`Q0jOuDaNlYiJpCx3@CuyG+6uLHGA%W z@^~^Cv@rg{aYDRB>W%PiHS)D}`qW-A>k(^c|Eh3_5;K8H)RmIfDMK z6fj5HWd)UScW|`ORe?{MBo1`$#Rooy2QWz+-X{jTw>wKRwr=mJ*u6kTA96%;-kEa*xg3V{ePSrK zaXHVz=z$1yp3>1%zB@vSaY`+SD!G5a*KHyFN)QK!G4I26Tzb@vm%^=NaY5-mf|M&3 z=ak@Ml{JmmLe-uGeM)Zf(~pcGSt;41CINRuJ-$<$u>5jl4e6zd!IhxYCbEgg9dUCF zx*lg)YwvEh$eYw|-0hNxc-H=&g zf}<`?diNxl(9t(b;e>}j2ca}!M_>plF2P2wWDV7OlCR6oIBo&yaL=rt0r6RpKS#;0 z;0>kiDb;0=AAM4=FmtbW(dS*Obh#&!8bhgjbPH3?S|g^HgReoeT^{95F6v{Xh*xif zI;~qzg>1}Fl9Opn#MHEc8^18P@a$Op;}JVP5rfS>Xng_=+j%_8-G5m4$;}Vg+K8D6 zUQKa1&gK-ke9)2bw7FOkXp^#STdtCg9J!>xqg<_c(@QW}5N@2*4730n59N!TLC8Re z89A4hQ)Np{M%6AqyaJ3O;qaC`3SZ3Nw&mf(j7rFd~Fb*C8GHWNw5I%H) zc^9gKHM)uiUA8QS6HV#(wj{6}7$1?U49ajSR}r1_9Z|_tT^17te9u6qQN@Bv_*y6a z@ZiYMFpK8*x)tF_9jDYj=?f<|Z0dcT_$U^3#y8;;vEG3#Th`UPEDlKrIu9lK4koaD zVK3%K-tJPosLz*i(D<;!G)w8@OMr1rr;wQRU^O5`56!TvD)&ER( z%Gzzk#2BME9|o}GhXEi^sr;^FQ{S(?E8t8t@O=R;K%kF!b=ums%i3bS_O(t9YlrXn zHQ`&XK>oh5ob4fVL@f{a&4LYUUQFf)-=-`@zh{%)*Y-X8UPY`xc}30&W6jj4Cn5DzF2nKJ}qE<$&)Z z%lJC~MdZ88ybt|$^5@wC<);)K$UE-KzaqHITMZw-w`wZxEYi(`7GGd`rn^t2T?_cV zBYs0x=f8q{&FjBs$3SbvujF-rFeW)vq~z!F2J*+;+kItKaaX-O=}m?Vp=> zb~`eSGQ&bRZofQu?tSq4)ll*W5F`21!RpQ%i47SyGlD$wHkTHuBX+%4dC;CASBwuwR#RJ42Dy`{{eO~t$p zkHg_z6)2Oh4us;3DckTRGyx?oBf#64O@YzY-PJ9e2;0jeZ1+XL959AQ?rMDsb+i0j zRnclav>72A_$@;z0`E8Sr_*vmswy{;FQ@kN6Ouy>o z=Q)vZp}p!oFn^#kl_<+WK2`DMx)m={Uz0x8iBF6TAC-EvGYj}_2 zPmU`;YMkN8v7`*|#ZD+0AInCWzNZ)YGJ{lltKdhGG_v4i$byr@n|GB+Pvh&BKFwxxrMy*PzdsEiec`OR-3~ejkOd- z*a$Mrhx4-eVRMEnom`<3x1Cq8%5v6clOKk~n^4_UIXYj+?Zo;$Gd6=aoQ2*$=sK)! zyq1UeEgbvpMR*JO%_3W5@?I>+ap*LbFG~wy&i7{#mrYDwj2n|2`6{n&5N;zvn`qMw z2@MBztg4fZ#UCPXr@kw!S>3e!0bAu=zzyEQyS+u{6_x~69jHc&b_Z_#>a;To8>jcx^!wNTg02s z=@Be!-RdL5A}3oM#7;!#-jv1g*eYJP?Xk*Yc6VA{h?^-^!4O6Ma}MIANbub3;yEb2 zj+I40Rt{H18Y)f=L6W8mvQ@jK=WCk|-;x2ie6%q%c<%x=!>O4e{i?5b1KJ7dkid}s zIMe~y)}!Oa)nhj|zNI3lGIUNkvR%j5pMC~EUBDy*dmEiPar6~#bREA>sxj~l?~3S9 z*k+R5@?{;UDWUkJQUjNVhJyWJ{s3s8`kmLSR21mI)YoxD(h~{tK4u^gbSy8(xyKB% zXRtMZGXY$#ukuuqP918oHhke-d*odj8<+P8J_>I5D7P7g4$m-jY4|8S;bRBq2kbF_ zNVcn~g7T?u%vnX-wiqWC1oppeF?k}60dR6S+S@NCP{&!>?uPo&G*Ii1rBnprLjpyC z>gmDjZBiWK2}hhCuAnkTR|6``AC9_^5jc10k7E+zpP>j$Bao@8?oy@%#W)0({A?kg zp73+~+hqxpcCoZw7SQ3bLL46JM8!izsCcLghsVlscyegbQyCK3eklgxVI) z#H8%vbgZpRGPbo#NvSK9PYlaMpTMVPdk^$%xdJtf4aUoE3}swB z#_3+FZ=W2LF!sq7>GWslyANS>Zaa+cy+~QbW-DN!z`8Cyro|L_kWXq56v?R!d}R^4 zB?|^A$|FKkK7{cZLpDBXfejtnBgcPC4NKgrfy?NH&56vE<>PSw-B8KKX9AFx$>PC8Fj7+hUc`wqm@h zh_sd8XciHx1n$(65e`2JsOtujfmt#_wyP#p9bOczl|6qO1;( zgIy}?)(&fiZ<(jsuqo5l19l&F9CYI40laxZfhLD|bT;RGQl3Wz^1~Mxf1F845o402 zoea^^LVg}Yd-||DGs7LTX?|&=jW0|K@T>#UZ*?hu+sKe)j|`QC9J;D)`<3F*Rh#8+ za@uiP-3P3f%9goB{%&_}m%3BDxFX*}Zo_6t&w~%Wx&gNBb5G%IeVrodOHj<;=nE)i zJP-11OHSi06`hO>`Pzz~k;CKOvKZ6FiMAtKA;ZhKc+sLwju}$p)V5>C>BFzO@)Y4t zKR9)I6^``o>64{4C_vKq)JhqT&4TN-GNydyU7TbuE#u?GJvNkb9xOdn^3)P{6~E_T z_mFDEtIp|!74w+prpp6uTbEq-0QaI01c4;=Rr~F+G(I1pZwf-Dr+VeK{e2kSKdCz>8J2t3{0Z4? zk+;*T`g|=NWn~!VY%sRPMV_phvNEZ(_~y=jwUj+YF!dCxf^wK~6>vvnQ(P6Q>WLF5 zDCF=_KYxEyW%E@A>a+ZkSvGHZyk>9`^(5~e*9nz%QgD~&DoSMptOr;)Ik{USJu}B# z=CtLfwK6PfylnjE;0>3eWL1+)9Z443@Z&4<)I?kFP|v=bp!<-s6E7oQ2nMV2B#e4f z0iO~qi;ifknasUB8a|h_c6tP?$|9L+n@agl1feXOR}rH>`nZ>MS%4b%-Qr=+EmL8u zTyA_|e4v1jWnpj6slo?W3&pbZn2@6SojpXS%3}x2?o8%X?dHm(qLFh%5pm?;YMih8N(S6 znctQ+Yz~KV2gdO*{5Y9`sXyFP#&ly|wRMe{4pWYgh3RodaK=hm7&;F_<%z@JE7hw=u$FeMSz!>Ta=`VQ>M`Ql(bl2AxgPqP7V*uD3>g{XJbdv zDU#E97%IdLhfEGHMieqhIf8X*pPVI$8bP2}4$d1`69xCO#tVC>D|8;7}>BGyY#Bsg4tUMyYkX;k>WvYNkU z@)+)VvnjQ{>WkxPjRn76aLMrD8N4|=C7eLzkpY|uE4FlU$QAnf(H@d^92JEDf-;kJ z0v;s{#~M3Rpp21K1vZAmHMm%~W5j}@d+6Bobf?oeWxj|zB45|jQvz~l5Hm~pr%vVD znTmJ5^_iesbCoK-@t;L23vp%+DyzdziQ{~=5Q*00$`*iZAjGLs&rcShcU3WUZ@>-2 zN42IE7sCyG*V&m8#j)aI0zCme!vV|*sZ&I?719&keB0J>>PuE!hPorH=5ZE=x=`y~ zFAGY5xZHp!WkY3F2<>!+hXLoSSH81T7tQ;K6_`Ii)e|@iz)kTLv5jAc;%$}{kAm@J zvOlQ`gs^FYf(r{tZm9vce&&+Avm^W{Ub^$jPXg zlcVeA2|R8I6CFr$%}imkIwP-7LKWYoaucKb>kh=c=ylpSeVj5JPWu|N z!<4nH&xFsh%4x8_hOqQ29E;vWEw4e%`QxSy3j{bXhJg@A4(Q>?$iJ zm&FpXfDa4WQ+n2oj><=o>4EXCOabaLoQ*7eMJ-v$!wUc$_*4w_$aG-58w=-G;{nkm z-Wab88%!5@x1FzV*KHKPI27B%j>ec zP|xZ_c9@vmUWh*%RwA(MWy-(ecq}WC=@}iAJ(z9>pcl2AW$8g*HG6Zh?}L77PtEEoo|K zAprsy8bX@*A&62!31D8|1xm~P|JQz;ea?&=r}zHu_xtYs&Tsadv)5kx{a$;mwMl81 zoZ+c=IBtOQp0G|_VmCXdZwZB*>fYecR-UOt+#u_XW6zI^e^cI6FdKwEy{tLw_h$Ca z%;O5xS&Yn_uto18<=W8}rjZdeePhu_KSrN230<IX^J zLpYT=_=E~{FXw!Zmo?w*czIBcr@Smq&8r{-&w@IOmc_IvyO$NPx^A`(#gkO**b=U2 z=4I9`Y6st*=F0IQjx-?IjPVcMiDY`cb|mEtRu1w?wHFsASOhH|WE0k>RqSb+)ME~+ z2%<7bhYF-S9Xc#yhJIRhteTt-VsgY;3bKTCkUl|CJ46s=Ll?CkazZw^sf<5t*GjWh z?88#L{+Vq+hlXYhsNOaD;wth781AQ9KrQM_dZ~e8-UrDDpQr|qfkfzl95_m8CAR)k zSd$&7Y6oPeQdTo6r$6!2+LOenU_W(8gtjSYvaQD;@KYo3(;#$o0zm{VTe!Var!N=- zaEQ&yUIu&A1`HVpYBbH8RgNV?C0hW3IPnNvtcK^BMo{f+i#UK|voaZL&7+*)O-r28ax zj>8zN5$kM4rvOt4&P=EuRLEH--KgaGex>Vql$Ri+Gx{>ILxilabOny$zYAcGUrTR@2fmSM>(2UY%OsyGK}$We`j7tdy_ zIY{s>M_e$i7Z9)H>67(F%3m9B&_UQEf629|(S&^%q~gD#zE z3tAY1^3e*eho72Rn2AG!MHgza7Op?W^TR_G#Ttkcl5t8m>I#=hqRtC0aX^&--yT-r zPAgGo4wH3H&WrlD6`{a^rx26%7D^)`o%IlcgAn#EOg_*~(?aPC9L~0A<}U-bie{~Y zR`iHwCE1eJ2?D^vcy;!mtoJE>BHgXx=eTgd@g^8ThQs|3C=V5^bh(BAN12?}iG-Pg z8d!Fy!W0TvR38%bl!aJp#Rqi!m~>qB>)tY&~+P9i1N5Xq#&iPeBYq*VF(OfWaj z$*{l9^H~;rm}3V~iUy_N=E5S@Lqx=ZqH1C{NfiV)6alb&W1ci9;xCo}kUhtv9xcFn z6G$XJfy5$oVNtKKC=1*LBTlDSHOMK1G%uP+jYFq#6w`%AlEgZoj4#SJEQS6`>iS0L zP-Sl~*4Yuv#x!Y27?=V?B1J~>v)4z;FURWyLQjQ!7UWb8c$M+tbk4Nbyy-?E%r;ts zWE*WGz?3ghbfYy$VGC^nvHl{BHl7AmvBtaGM4Q6WI#Z_I8YF8su?hgS6G4bZCMX&d z@y0gf_%w~w24w-(mp~f)#G-Q=Z7%9F8ll_l(92A;F4&36HZTX(HYejZ1lWkBUpV1_ z5<$YV@DXDc3R_joA<~l5nY_zHr#)eE0VQl!_=h~1*f3Mc_O!Z}`rj~a5oKnI)r~0$ zWKD{sE7m=%Ui^S?jRm$THSIZo6!iIPXKYH#`@rd@f-LU`Z3ZNIWB?pdBJXBcy@1i8 zX15kB7-bI0Fcp+_$FSsr$|xIIyTgy*ND|EuA`l^)qc1Li`XJMjK<9-TkM#i4BM`hf zhdNeH?-LeK*t&Cf*=0a6n9|dnHHd{vej{m7os!eOK~j4iwC|9y1y0+2O3v@Z!?n`wzEZ%J%E zK;aQ5G(c%pei-y{QfMy}yjCA*IgLowefdlVD;5tg>T8?l;kwTyjGWurRG~d*EBjSC zL2u#}*g}JgV7AEOswEHI)h*Ot%>q=QEVQkHIuim?XrE~2v!HR!kv1K=Tm$yg(6$5j z7CF{_>`5wfTu?Z`f$Dyc{e(v;+Yi0Kl>QjUi61C=gQ;8r#iYqhq8fO3q-EHfnqO#{ z_pTX)I^z~_0JY==`bzTCwtzzjCrfmPO)*BZYqq$1g}Rq_-F$ZgiG_8&ID&`ahR!(6b2k;tm82PKsyq+F(J5viyfw;6d6!DT3u2~tEHucE{X`ETr~AU z`O)MH?FTd+_~~{->vluaE-EzTqC-;#3dg3U^;1{wybh8!SB!2@v=wumH%OW0FhTA(eo4@w#r zxB$nfj7vteMZ0S;`xI__$t#I_(03v25X_LD5DAKq6uAYA5EN}Fxci4>Y0xylDr&z; z1_hTL3XiPLcr_A3HA-7|J5lgj5v8LQ{e3dPYeke~QbNJ25haoiN+pF+(iVnJTNn^_ zgvgaT0(U!w+IE52rUi6;?*N8bn3e-r^`lIhkUV)5QTM8|Jb-}K)|z_P^t+s_&5pHp zwt;eKKa=5SoBr$~X|tT12X0TR`$=34C2mzAw1=M^_(T-RME3z5f+D1fH$_ObpE?9W zbqM@4A#^1r1O(QWXg7hib&x76QM7g1DB9av=O6$C^{uU~N#~2>Hekta1H+ewbtd*{ zADs!~iZAWjlhm%LpYTiLp?PT-YF5KKk~#(Rt*vbeCSMZXe5*;Hd}&x`n+jzf)nR<# zOS|@17`_xN*=Bs;OZz~9=}?m0*0tNXwkM1$zO;{yu2$^>Ux4Y>gwxm=P;=3y4&Z9T z6~JxHvD=%2JDP(#n}fTWgS(r9dzyn=6Dz=1$Pjuu1}?o8(FYJ5y);BE6Z?Z2S@z@S z9TtqCZ3?%Nz+W^VjB|whPJn~KzUj(AP|%YDEp49gXS8`Puw4P$!Fk)C>+8#>=?@nNdGnr2Fi1XFdfW`iy?V&F(fZ82J<5Gb{GgC2&ATZb3!O?L!I65u|hxy`JN+c>Cs6AT;d|J zK!MfWk;@Q6b<{4~^EgM?$2Dv*m&;0^6k}r310+JR@kr&s3{% z;WQjzfGLCekJZ?ea4w4!r?nwa#qv%j275=ZZ2!0pz@Cct)(vAj!W9X&>b*<{jse+f z4A&;DXc3N;)h|}7L8dB4*Y#1nsqzL&Vm3gT5i8Monqos_%czurJlQ$vYf$`GJ}&d3 zf@HZJY`wmP47VasIVFL zg}AvaX!ecLMH#+&yD?VFpxmsx_it81cqCz69d%+F9 z7G;gEbyp5%K@LrvC5t~l)CSeR(e%4J=AQ5)JN92j8Sn%#@ST;Z|p%hWN> z&`jH+mj-w4m>mQ+(G59jmNJC|j;+Tjo`#5d4vC24rHnK_;ktFo!b!g^(3J|`CY_2o zy4<>G$P5&@L2;lo8OdjA2&;_Y+)xo$Y5TZh$F(VSmx9}vxp;$%V?0hNx(%**i*6|A z8n`>d3Up}vbq8xRi|{HJWH49p?e<=_Wbn0;Hlcqmw}NqfO!b)*XFd0S9R>A z&{fmtPK0$d`#@kEslVl)7=BDY%-w+bp9povP#4Q_;`KfdppPq6h9(f_-7NgX7atC` z{N01WoZ)6_5WrsF&vV2>Y7{1AQb}lJiN+1_p$4 zeAa*I;o#8LX!-X5#>kFoToAmux`hxTUHEzd~(bUfTc7H{;|MNWWmw1S{8L-tDYsNPSvx)as?VDwBBis`G z55Nt}IWSCa;3$EYRW77K6^th63ock!Cvi1FT!$NfJqLidvHq9DF!+ra{1o7O00-FW+Vj5pu#EeM z;YK*;0G8t(*i9WXUY4PnM{teB02YjR4DK)I=Fn`Q=i~H zXq!IXKeqV!VsQl8?s=O~F*lS?^~spY^c(@MNe_$i(tkE_^9Ds`4VZcp(_W;j?&$Qic@mV&w3r{D= z;2*(Q%lz`8j=E)wucvpw4DJ@-y7|25K9kREek)g#4(<}>OQxF-)3L?ka<1ofBm?5c zesC*r#iIYFqqsXz+P&&_7S(Uw9>c#G_^yBVdv44-0HqbEHL7Cvwhi`UVZ6!P=xx9a zLO@JqcccpWw&aFvU!S)&HmJ6LCdQT6uX8w`&gqy)S&+)N5+ zBW?liRitPNAuw&8H-fgV3k2B)A4G+W`?KRary#{}zymC^0EWdmZn0>)cA>IB0ZMY7 zi;P@l7&p{UR;Fuh$>MBK!%lJD%kXNZCh%>Q0BF4sY5~ipd=H=$^e44mxK6Z-GdFcO zGcz8oRUC&WsS@3|8JjqPnGY8x87E^Cr)<868(epXyA^Utjqa0FW#9~)IK>;1jBwSn);*3>Tp zX<}l29fI@hG8WPdX1tOt{tMnl}cI=Ai&gVJh85#k}&zXneSvFt`rf20P1#bHWnR6L$l+ z;W7A}*9t#ZYXt6`)OHDrB3a&Yaik9E8v@XPI}rD=pM`5srti~$xqBt%>GOb5Kd9MX zss*~{4%Uly5ul+AsV2X23!*nBVt8B=n)qbQ7|QJ!+^*K_tY=v( z!jHR#eGTk_3*xw0ARF96NITcBFTk5^>{bUC*07zSPNkjU%{cA@o}H0``fTgyA}@pp z303rr$Kotv03YRF31a6VS`+vEZK1Q0z7r}{bbi@$T9vsTzoCbY;>6Qx^i@$e{2!v9 z*!=Q)gkisCkXgQm0VAzK%FN!A5thXfxSR52+c^Py6gQlErr~D7=KF%BsNLpYm!YPr zS})c;EWhamr+oTw)1=&WgXtd!2ju|QQ^X1#_mog40X$*q6?_i6IwM}|Tsj24 zk_({fm}sQ%4=2Vshszw+l-DG>rx!QiYaFSJqB4zQ%6{ zo-JG5Hgw4vRC!yRuzjG2Q2qmhzRic@!{X~Oqts;wQGXuR`nqKur*GYAN*rwT>OG1) zxN`&Z`aQrnH%Qvl^(wY5RzIxj;y7^FuexDxNU!J|XJcIX;n+t1W?xRsxytoVbh+c* ziujL@hVwtu|53o)JaN4ETjDjD?~Z7{X1+5^otn~{9z+hBnMmhh`Y&CM&IfEK>j87; zF3w5qfN}j{Xw#gNt^|xUKPhM4I}@YR6yVPMT!=U4AU7Y9o5UvF)v8`Y6qcek(@|<1Kz_*>aSQboBXI-M^ zv6M~jCSN5rNNh?Z)Tf*?g$S}tR7p08;6+VN7W#Jut|Tb)l=uCb* z9)R6H(+jRIXiQRa@ff?TK!m;Q7C1w_8NaQotH%esH6&5XxHud10gQ0i0+X(Q-9DH) zFRNR3xxcQWbusyhzYO7+tMWi<0E064VL_FGN1s_T%r6Q#l)Pga&&8kJIsm^Wth`RB zbxANdajOR^plU#p7wdPQsfT_JA4M=%Md73D{fTL)`^5ItU!cYtf4o{zev#g3Xb#1? zY3~%+h#f9>8y^)!fL5Y4{TgOph} z$nodmv7Th$Fr^y7gQ|@QsRgzir*9!v*DC42iE2}1530J@x1sNpy95uzB(!I!D>b== zKr2Cq5BKnjc(@W?xb0sF&q)}=t7$aMXgT+vt#S2}V^!4gK?_KYBC^++n4+U?<`$m}8!R&{bffaslz&UpDY2bGo1rJ=pYl*EhC$M=SM__aO z24rwRVT2{VU2n;9H7JeYG$&kbHM(O0a-AFfAH>Zj5e$_N^MB}XRNl~zBHJ|X32r`v zwOQxsAhPKO{Lmc_LAc_2oNlfBMEq+s?osYBVQLuHd7qELxJS7+2Gi)CNw2Z5^!{HN zm)VbTaTO_~l_Ce6YrETj02+jc^3%`%Oq!aNC--4@A`Yn|6N!Ew`Gl(1Ih=^D^wfU% za8P6Y>W68b(=gi(aRI_8Oo{Cg?Fjn_9wys0>LK8Bjk*hOuF;R-4IJyfg!GY)d<))L zyqDpA9^S0?J%Dkqm}ug*g!*TC_!xhThjAQ%8@~_XZQNj$$EI8Q5AWix2`TCx!PaTh7ho7FG&byqbu*tIKCdxHpLdEcn~qrGt-A=l1g{_*pJK4uHt7Cyy0cEY{@g|DMy z6QxAas5phHJUr^!T3JNlE^aNW@&qk!1hVxOqeAy`;pvA!H&oqBt?!or<0 z+~kn8BMi&=R0)8SRfgm95&@gBmcN1jJ@feF~7hy{gF%5BLr#stm_cyeADxOSQcMj!o*}bwWmOs?4u(nQ(m82}nST=?(PEop0-gQF$ ze7WY_wp&Gv4;@r>Xv}neu$0O|)2L#LQ&`aVWI|$F%F5uOJrK|<*K#Xd+NqsJJ7=Li zKse??*Bzv59W>t6=%Q_!WEAXCx+P<#vPHq3|*tfwP zhB*e~Kk!hnbbq*4Vi-;Qk5{L{JF=4+t%E0 zDbtrK;%1lu5N1aTrQEI(o2l4)hjO_H01`0P?i2<-$z}%mJzQLNE{le!U)pSWsq(}X zUC|P=?q>fwHIL10h-2L=`)i{$te9A-&J%M--&(<4!bc!xW1_>D4#mLMibR>yju<6< zDDgXKd3CHfsuKp&%^#PLqq2^4r1hNqtK|%&|4KY&wOed*zMf0T+I$M9Bji)~R#{E& zu3`@Wf-jGT*hPhwH;AUW5M+z#9f0~A8g{$T)-dedDSxCzQv-y~x8K0V%kQ^NPql>q1`^cT|`r+4K zbv3`OXM9+E-9DgVW_|{~)+E};xtEEX>s-(H-f8Tk;W>%{nfGD19gn$}!G;S`ECvmO z)%?x9sd*O9TMmwZ*TcZLAAL1ol>bO$f)IZ2;_y%keUfMXW?y>*INYD|;ePcV*fXgx z>pX$l-!{6xtu)3H4CH>j@F#5Y*0U{b0zFmKwQrITqJLv(4pTL*n?!F7t(wJQY}Q9_ zO5&v!8~8x`VKHNAGGBp4O6>sV3`S#Y3+nKu;=c+iIk7zV)H)a`!(1UtVLBKn$3U)D zL(0EG2RYXPL31?qH2VRT(~=dRF?tpQxHz||I{+s|Ay&A+axl#TJ+iiR+@&aW=B9Ab z_+D&`D>F5m3fO=>1BbpzbsXdIFbNkfl;`zPlV2Bw=>9y;a?HvOWvOlt4FTx2ywpJ5 zsE5Tk)ISGcs}*vd1>1Pz4qDZV=%+SeKxPds$tn86GXvs((cLC)EMDVe5@Sk+-*GFuy}3Q=7w>e_Q;TSUMSudX~Di{@E4-e%Bwt71L?d?tzb1R&ZrCWf~*kMxR@Xm$85@3SW2_G zY>BxaDWl+qpLz`mMx_;fJ z=79TCg#sFq3a&Vkz6Q+$vKGVa4?Ehpa~WbY$YXy3dO&J;8`_lSbA+=b5^JZBQI@ArD*+#58>(@*^IvN3~ z8Qg(LO5`}s1TDlSY$ia6AzrC4GE^8W=4=uz05c(rrs-4rEwzr7ojoZcD<9W1_`mqV zW#L~nyyaY9SW7puq!}Ns4AZ(hiNRam-EA{4C7#L>0O%a$aw$ zubA_|%u(@nLuhX|Sa%Or>fQuyL$7!P5c3-t#9Y4O^1R_Nm}f8gr=pkqmWFX@F6>Vs z>=^&TNBG>Hz8vFQ4dhlGq_VZgOC~~WCqH`sRKY3&c=l;Xk~*KZ)hga5AiJ!+LDmt( z+UWsQp0qr+A@dx52KGOHe!|E~69*E|>UIHb!3_xdYq33%Na>X;1gNnHC{sC)c7+mo zROY;~F3e7m8DvQFf;mcC$2UwB!eAi%Nd7J;jKxUV^tn+(neN+>-a{Wa5fH|9PS`QP zw&WiW7~4BxUvywRe!$Wq7PR!hQnSYLp3KJl7=b{AY%7kcXHs zA29MY67K>HTMrod&1X@NDJ)`1P{yv*6brB#AIbxn=ls>n!I=RiBV_XTEDhuMftgG7 zI^!Ys-UVF7&ph&BI`;rZdAY&iZRA9kc523m8r%e&~epb{zqTLc7T$vuQ^cN?B!+#xh-*Jxq zY9EdI8yU)b&>yW^B`>17%2`5Qt*)?O1$%PMy+_f6UFaIp53*Bp^3J)vVa+aFI_R4= zZ-x(yBi>bdt8_Ken!EKxP=fhwm_LE}8<>BEIgNZj8TorQzIE_mMz(u~P0`dznmD>5 zS$vt4#n9aJ#hj3TdJI#%DNLmUbhEJuIg~T&&wc1b@Ew?+!#wS_6TuYTzlQe*%NiaK8~vkJx+DM`twe9fZFH=E7IX1#NSo|@W0Z>GAx;xwViC&WYL zX{Kvr>EkDY+9#s*Z#*|iXC1o~B$NlX1`Bdx&Uuk@TN8z;{k2%(t;59SaJcg<-d}5& z+p*2a(XnU<{Jz6+F6`gk^}Hx&(cIwO^**WqQzCI_2dm(j0@e-$ROr5t5>iKF=8b#f zuGZQ*(!_)6q9{u72ZZRs&QMMI?&v z*xxlT_poFkoBGKR2fNF2;=^{w(_PQOczR8AJRQ@pf?aEu3eblzm_@{9Ts#CEGnR4u zx)pX=#BgDvQh_4D%7%8~L4;L5MhD6kE&pNQ^1d_7j|)HaAKwf{X6vA-iPBph=-Kb> z;BL)O%Uu<8kqX&s9a|>lx@A(1Q)&W-{9sq6Ucn4lg!h7K5ri-U!ZHh|R>FG>3V`{{ z@G?*FIym8jFs)8|J!%CIFs>E0K(_<%jw)bTPHnLdfjbn85xtZyLo@Q`#7--1@n;VA z4a+TOwgZx?kE7C3bsyJ3!;=*sBnTYWjLlUK%;J1@(SPN_OpV9Spl1pxeL8p*XeHIX zV0Yv}&IUJ*1y~NiT%>_#K6@fqefNnV0psGW^t}ZR<10A=t|%Fb0)^2E9OKgwY`1-S z7ppY{+YH+t=j*2e#x)u7*aq4Do(>pk(%~LnZ7ofE_2JHS4j=NMjlwRLCV#eA)%vnN zTdJ{$>HX0nz`4yDd4A`X6_*G*%P8>?qm)z0W@=0O0 zgm(7#V+cp&6H$>|3laMVfGr_xQ=hDV?>Ep+tWE)?*T`Mtjl!L4JlVo-KxvJEsI4sZ z$*47$sMNI+ks6;r0>};fH3<92&rbw@9D~0J@WRYP!Mg!}n+}F$bTi;Ao10_!?U!E(WoJlR%f(cpX=N!f~bNJ#cWt zz6J4dZE++9zfHs68-xEX(}(>Ec$2^d1Wo)qflsvT^Kz-JOeBzjQaxF|;f0(agnWRuJfGrb}VIYu*j1tEK zA%pWU!iyYg;G8==;m`~v`n}${3Rk6(Ah=oUb!ewZ3H3q&6hvCl<`88vdgete|I(s!=`^Am-6%Tt_Q0_2_gkPX? zt1+IOMZH6L=&9{f+g=UFv{y2h`f>Lm_4Qd5-EjMnn(hm03602IQo+Keata!n2f( zDi8q`w?%>AXrYE@6SzcJ>ynnPxL7j*pXFV^ z+)rmSw@^O-x*Pa0!9Hpwnj4AQOzQ(WttNQRFH3;A^75QF9tDi+7bCCE`Qp38! zv%#BU#ijY*r1o!I>3;?=t{>z$3?vs*mWKd$+s>`93l97koGme&dtv9kc!yedfJQM5 zZDAyC>{jOco;V zEo)S}F+k=o2N?SY)69o$?wS~kZEhGawnM}+u`p{dx}y5ybAFEMFpLMre}{&leFwEGjcM@q0FPnuVP8l9&z79ikM}3Taua0y?baVhUl6uE1ttB=!E??AftfL?9V%J*jgWBIEfaIq~ocWMsXsi_yH<$}x5 zeh|Nb(f_jnW0#8D`2MK?*zp&hG-nzHRr=12aN{_G z-E6In+mdnE!5*ZNsxjYheW?ESe)!>f{R1)hUjbfw(aAvZN+6+&uIP?EAz?P7HN3XXO0kzK1-8|dYB3;0vo$J<7*o_;^`zrzgs&^Cr@Gz`V?eER_HsQY#FzSuEYGj}| zQYZ`#fr;j75Xn_A0}L3-N{7KA0iFh7y$H{>4#BV6X8#fP5ZUPifV+FoGqBrwaoX_Q zH0f$68}JI5D2q%y9`@-oC{JZm|H<`EI9%UgIcL_UxgCWP^c~}nucU6-*gHSDR_&+O zk!8BI6LVvTgK4j%W>*)<<+caQ^88F~of|*DZ9dF>6t#Wb$VBtI3%G0pkBD5IpaX&^ z2e!{sapALiy`+TCw)CD1F5G%DIEgpEiNEz za2%CRJd#`C9MFR@De%oNuBn?NI?PT!k9ENQjFTO|DAXA>+xUJiqAH4*%uFn*5v!a^ zgo;CMRyoPlofR)zejK+%Ut_(t&yfkC$U=E~io_(8ivA)HvnBRC1nRG_q(WCnHdy!K z#(uETh_oQse?1W>BM*hA9W>d4D|B%)WDty>))USd#fw}tr}>cs+>AV!DHePx%|?nK zqg>OUk<2NMed={Fb<0v{c14b}Hp5*pd2_@ph4u%SXgK%yuZ_;1;;8?Q!fngzn!A4# zIR6#@ThGGhvzS~C4!`Ck<~C{1q)qW~&rMR(?_1zc*4NsV>3SbvoQo9$X$g0;W*~AT z+@p4_cnmo1JozZ>;n@|}qlW)f1%uuxtHbnLd_}O2?dC-X%mH5C z3#B?d&2)p5Z+HE12yu{?jxe)6xKYDI0T4oYCD@#x)S4WK7$LCESH~|6;TnKh%hP@j z!eaTEGhvqBmo$v=@!|UBYk(aFo`G?H`Ve5;r<=1uuHC;u81}5Y$c-p`f2omOfYTq{ zq4>}4B}fk$hdsnqE!E&2L0E1b9R@CgphOf}2Nc(N?8O$DK}0;LFt&pZpC8AXALDr) zBRctJfSh9UQlqzGmRu!llaeEwRz=O0^H|V7ZOKL4yF`AI0?H^cM{C0aI^oW8jgb>9pF*V_Jk5-o)ojBw2Ff-Wo|V;*oa?&yzNnP5v-gi zNgBo1QDG`2Jl(9fNPoEV!zY8Aj-Cwu@*^jM@8G)&=6;yZ!00nANrM-!`lbzu%`W1g z+LwS${o_VJkGVn@aGR%Ti%h3dIq$lva6&if7v`@?`&ac|_RyRm(yb1Xtf-yExBL&f zyO`F3>qbI#hZ{}GBEZM%IJRCSr}4r=b*|KJOsBcTyX61IKI3!}86v_4elEQu=H;w? zBGx<6OE6Bg@IvzSMy^O8xD*t3%i$srxa!NxaSw>nDT9?mrn^0doNM=i>bom`I-t{h1yWZ)lM= zYZ~&o_R?mZAnby!>sh;JIM)iA%uhTuvP*2+AMO5v8YSQ?!z}2GLjzmoOr3Yuf`^Ur z*CLXS`W-Ln6)l!0xzz5GxTSXwE3O_jLfG)f>s9Evs)pJPlsk`jaNTME7IfTrGByW= zDrVm&2xdQc8SbfROJ24DYC|l7ja;nr%#^X#s~?R~$&Q+&L6#Uw*O-NCEvd0W7PYN03wl) zZjFWq^+D8M>K}kAMo{CSYXv+8Haj|O&tpQEmy$3=h;}0`9VpbhfKKS7dyJ}AAQ?>` z6jy{I71S*Xe+<2m*n zsUdCc8%#mSPcR{?M=?BQG4fcrg$puM8aOhb(IcTMiwd%25Nu#pTF{16GQkuFK}|#V zkdv*fvF#7$px$ke;#1fg&C4YKQXT@NHWhwM@bWEwP)y3yg9WIz7=;ri2s4#A2uss1 z)nDkoNh=TVBS8_ss7+e1TOi&-4Ju0}ydC{TmG$E8ez8d23DueBr_Srn{6JgMDK*E= zf>YLOK+Hv1D~klCK6P-)5~~;m#I;rVVb+tf>PS`Bm4EJC%_BtHU;gsE^YDZD<@vvS z(&z{jA58D^MtAa-1iWR{Kia4^@+ICS*cI4uMDKpEGpSG+H;*IyE9B?^D#>s|ALgkm zyesk5pKS*{73$6)W^Bf)#D<;?-IIQ@+wTt!`pHD1+evWj^E_+_Z-SBiBisrvJ{8np z4#UJyn_9O3x~Hj&0xH>MJBS(HCH7r*Dh>%EwO*c4qfTY9QeJ>4H};=qNSwzZE%phs zwFTVms)tDh!!TpOvlBS@QJM>8_wwc{Y}KhD$TvP1+tduyI&&${5q44%5CPSZoERFK zrBxBdL7DDKCln}ehzA-~wFU&mu%w_Sd(fJ|VMt^MwM!ITjc+p6Qs&*!UIigF&IF-T zC~po1sVOKSv}0p9W>?1`+&+sTb#5F~kcu8#z00P?FY}@M>@xPb%dpB633~|Rg8@s2 zB3xtSyJA{3^Oce0H)np@| zs4q1kngJNjzS6sc4;igp7YrAW9-GC{A6)ATYqut1pYc$oIj3?1G zG%^f%cJ0i0Ku zPNn;DP?xq9S-@POQ>7*gvMsrg3@&FXL5WztxXpm|w8sNSHks14TpwgoMDvplib?|V zTSta+F0g+vJA!Bt)Uek#xD}IQQDny>qcMi|$YW<1)lWw8iY$ra_;GtP|Exu`pl{|L zxl^VY0tadYfNhxfTgg+wpS7L}dhuQlb0N(Auzwzg8ENL7Ll(S45mx}JlfCdkl^rx{ zWxc8K&0Z1*yF+>zg%7qg>3-3x6gFZLuu+u_kGDPC8o?{=u{=rPYWOVbEW=NHaJS*9 zBiAB==7p`rrpcQKm^uu8Bv!}E^HqqCdOfg~HVRM#1VVQl#BnlQgigI{P91%Aww^Tf+@eoS|EU7`BeUd{}Z)=$TC?DP0Fpdmw^*3iI7@BTVq zJbS>&%m_v%yub;;*D%RNxZ~If-UB09;W{_fVupNq}RU%F!CrExqQ;=-w7Dc67-ya zlLJi#&yRzD4L75fE90qo4F*x!e&y`#FR|1pt6M%^pDGK3$n;$R*it@BGt+kwU@RZH z^I`g44A|lArzFj6gIw>e1C007ktB#@@&$FXylIwdJR7gzqgtNn%E}48o#FL{X<_`I z1k6Lc_>_m~`z&BgpUE53_Z1CenVR&SV0cKM63y6K#aXQS#0)~2Ms3r~;1Ybp-;El= zv<&wnUYw~A#yAKo0am-_l)%`&2%FJ(j7Du;rLl(AAz^C)X7st2{+xU`ad7lfbJ=Y*^d+Ffkyp;<7@sHF=dd(ca8hW6FGyapJs_WxEO#4f`-~O&t*TsKG5lGf*Fjw^*?0 zJ%fH@=6s$zpD?(@5+$Z#-U>0?3yQiNL`RYYYr{Q?In}L;c7qF+4-|vNO90QLm2Gv8 z!2^Hl4(PXnZX}C)2I~>G3~mH2ysY?aA4+$Kv?z3h5vc%U{2zzkTJcm6?1v5+%J)oT zWy3ADSKe3WDhKq;GN=$-=|Djo_y<7TydDG(bL-Ko9-j|`W4(EPjQH3G31hor+58N! zw+!V5WYbvO}#u>DScnGXYzTbP#6h z_ql-WK|7GNL($vz+_0pbWy|O7a6dG7Dwy9l&(y01T$ct6l8UN4H+{DQ-?SG~Kc56F z-u^xX7~7wlzPkZqS{S;N5kE9RNTsIvzZ<{5Q^o&wpqlvC0mk@Mp!=jJPJzG6$i=w+ z7qx%R`NscmYZ&oN`Q88++nkgeI9v4)CVo}}?=alm@#bFG1sD9T0~w_`hv5^q05>yU zu%Gz|9?xr=4(? z(VpCJ*nTCP%(fgf$c^;F(S&mpZf@FdM>wWTNYyZSwHV%#!6VaGZ2V8ea4*f_h`DW3V_2Q=7pd_c6cQbI zIOS0X^bB~6M7|dkL_Z!L*%U|l2O^)Pu6Q0!NvLtpD{2iPxNQLhW>Nd8&%8kO@)hYL zcG3oAXQdrd&4|nKuWq%Nnq2?^0-W^z)P!#+n=)RKFik3P-CwH};I1Q0#SH@-JUYrL zknz#8CF>;1k>G17d+@V!5{Gyw9I7rJrvhOjfy}MF>pVoM(Q6Z%XRGU5H$!#X`s8LF zlX4h^26;=+ank~|r6vZ3t**7cjHn>_Tn1gNN^{v1NcU$Am;@rwf5ykbpk#gFE)ME3 zIWRc|QnN}k4k3~KF;Mv>CyJ<~?$yTmD{IHphEeL`j~(=djSy!Cav6!UL%RoY?zwI` zn1o^9`y9+I_`Vf}{q6HG-@^A}+WiZ#U-WX&Enw(=FU$3oK3PRX(`0me`k?7fmd0kAy+cL>{SAF%e@PmRCkK$qm4T-|d@48u)ANy2 zK^5k$FfWAt{V+CieAJi;JgfgY3Rh6|e}rzgH+TPSjrc_ULvbVoz(JbDz@~L@$~xu$>Pm$>LFlODuG0s(&68aC*Q=i+fJu~CrU*v|@+|8QLD&Z*ZL|wjj zkq6C-E-Qb40|XJk21Z6o4aWY}g@WG{+gL|C71q#Ysvv>{5I8`msbH`IE$ND=U`7me z3I|11q@IHPd}=Q-KL3X*uHU{v~zwllU;NJ@~t$pkATVL=VmsWJGd zJ~f-Z#^TgvXJ~{ziG+yUGtpZI)n(mMV#iU>?>>n0j)zVKNtoxr{0R29Y8Wvdf4;wr zcPy9VoJl%(kMl`k41C})W-Vvj_#R0^`LpjxyC{G?K~}?tId||RF7 zi<33O3QS8M5R^9mcB9>^5lQ?k|i$doh=>7O3=DMxnS45emHJvLKBI2sm!?y~d+H z%Tum$7^gmQJO^#X1s%M$LFx0bhB(}6$^(v>N>NV^L_A9ALzl%OPdO>SSDLDp=cm0n z9O9`j+;lZr3NTDgSD>^F8bigM_d8-q2X0sgz|#`rAMQ|-f|Vw2)dOdc4%LAwh>E{F zU4>wU`mRD;N`FFYd!1Uk$AsjpoaI}9aKv1qT2pAuEAj_R^M7O_r+5~;JQAw zg!K#R(3w(V7&}&ZW_#)V(RrSC#tm@_{(6(nX(2esML!C{y)wbMc3`qRN4 zm?JQ&=S~M(V3z85FPsjJ!kk&eJ)N%w&Y{!6u^Rw?Gwg3U9TZ?{Fniv1Iyn9g!2USA z&yzVj_9MjgW0lv#c%OkO{KVP2RJiY{p?cMQwe;gYcK#3N_x%%8bBXb{k$c+1>J}R2 z_2Z5wTP}P!z_RFdOB2h%bq-P-hhER$>#UVz-LVLTIqH5~6Slm$Ky?G)rZ{f=7)*Ah zY7a}V41)V^dh@ox9Kt+?*A|#VFoI4;jbzIsTn|AP56WY`%w?Os-l@toPLnyYaS`^m z=bjEe_UzNa!_PS#JP+pE7o84v!Vt#b;}3(?>^1Uf=0#`@fP~A~!UXtPoPiAbe|%Km zzL00d4w#U##+C1oiJ?X+uv5LNGFSB~(C0K)#lC~PKx{MAUQ7?M5=S^>dV-m38aVU} ztrTy_?EwHI>EW7>~t(FwkJ=uyE|KMJ~evRLK}lBd+?alges! zj?zX30pr3vv`@@%?Fh+^sqg|6m$}MdlOxH+HM3Ay-gaVgy>nIyeDH7#lVuC!T?MeG z^KmDKqexK6F@Xfib(r8(QWb*{*rSRi?1t6dlZH{u z9;jT+#JY1J)$8$k-dv_&@=-T{?TsKczHY}X;Cdjl46+JLHa0V6Q z4%?eJg`lKFWc?twsUc|aWe|%g?r5%16LsgR^7?UybQsEl)#7T4!2N{o=IY8W^2|6RiB1mr3 zVi8Bes$V}B@uEsSEKQV+)LlWUt|ZluyB)w5#_glsoBgpiWc*jYp+3 zdQR0}i?)(x=`H5_3*bd-mSUTy1{}TK9vm{c(y5sN!>_L2m`kjE*@T77E1EBX*Rf&_ z12pX~>UX8)XX-wet6F*rDs%@07yMNz6JmR^Zpx@ME++B9s|_PK?9 zmgXI{Bb{z(L)h}*e6r{~gb-V&XP9+LcGmdIsl6)dM^M6Ur|B-O)gdcYlW>FI(EZE1W zF-`;(!iahGX7A8ozfx~%!^T>ME1CuDxhRJf;@jR5%c~1_^2(Y5EpiCkPTu}$!zX&A zd`YJiN~_{{%?ROA)ZxPq9W{2vb=R4svzb{1S1f9pR8vK?&mcr;`G8{3Gd8&h$6CrW zk_**COgfZpe9ZC0I%@0;s&G`hRi0MFbD|;6HQ=tJkUo?ExkEexbP%!JBU6q|ELf)l zY;(<$$%R*E_0(p8?&uK$-Gb1?suCWKQ5HEIp28%sLeHffR>X6%CvB| z)vzmn^K|fCKQtR*KTpGKnBo3f-M7RmUOoQRLECR{Z}YknOrDY9(d_9IiJQaP9<*!> zqLq*wuZ|lv6$D9~^B_0@&Gu^B&Lg`P5;^rQUhfv5+r_45O!R|cncy5QBK~xKD=wE~ zN}^luEzf#b_Or+Kt8))`TTVBSK|JHeZ$3OHao>cW13j}`KQJ{hzXCy%^i2Q2aZpv2IkLTQBSbLfGQp}_$~_Ew*|2`G!S0QG4afTYsUfg{9PaY1Fsn^f18 zA3MJ2^G3W%BF?9V(R1nllLyLkllvNKr+08@d&#gbc*6^GvvqPA>|47I%oSkk;+Ti3 z!8t&6V!~ln7~VDnDF_IDWVZ8mOgzf({3IBj##^W~8%4IVf3C===~7*C*qh3bRnsd% zN||T-d#9^opfp8?X`hPppjb4RUgycu8&V|cRA#$c(>;z~^q)B}98mYW6Aa_zBjewz zG5*1@eUd-mI($#UaC{|yz}xWser+dzz*q78C=5xQUeIk#&f3#cnEAX)fpup5OGlWQRH3}Hu%gVczIA8BclZCn}fuJ>cG%N3?8R# zsU10xoQ2s(3uxKi1_ePbJlCn4_yb2WK z%G}i)IWp!ODF#;$j?ti?DWY^0(>0D#{OUfrhg#vd%v~a?>d@FjyE>UflLXZpJ49d6 z`qB8r#D+_>)+X?N)dgA%omRFt*4#6CSS%TTK59ewBo6gt#TW|&k!?d_hIM1o`wK~YC zdWv(=&Sk#CNME07nC^5a9Pd}ZemS@prrCNVHIGgdxC;`Thbq`gYZAlM!t=cAIss1)2qP99`<+zkJU)oxkFJRMz<0AHB@_m40I#sTV zBajPr<2YFBoi$#zX~}skWO1u}WO!5Mg*wJZeackw81@4~c6a!C$UbS$PCb1`33`>M zmaSm+q)hZe4gSC=DF=Vng_3toTyXwFi6Vai-PFv9+)?rnU*Oc2<~hNRRgiV?N7&%x z+=&FSG6x_Ln&kZGB%3-GIFwDziUXJOIC}w3s2r3w<6C800P2Q8k#lh8+VLuQEV&{D zR|422ov1L#sVSGP%mZd&k0YO?3wt7*;X&CSJR>^GM@FT!r7t<2#;EEXZR z00D9h>k^32JaR(OXc$zIHI77VR~Y-jGJHoD-dSX_dMPB`i1f^{{NlRufq7+Ku$ zEfQ0>VG`?A`INdR&8`(gu}FD3U}nrkQ!Q9QSZ};Eom4LIB8zaS{_M+b#k7-kf%$AP zVwJndbue6{^TO|`aUN4jNd2kd3~mn>EF7B&Oe&?shAvi}VH`o26dH(|M$>dSx3mgr z7jobfFT*uQ z|1~Y$<6s7utIV^c!H~(CUBCxtkUr!BP6zZXXk1|b<5Gd@sB2{gLEO( zUj|Nc9S2KZzR$u6hZe}e1s7pitt|$mLveQh)qNOFaXT4Cbent=8J1XMvt|`-V?Aen zx>OFT=4Fb;hnb)8$&C-1@jxyk>VS!+=4*V|$vXTN3KNk;k%D|UTNsIijAj{|e2*~f zyVC<1tX$IA;9)Wch$Pb(7WXEKzd|sueUTawOTXF=;W&Vvl`T5aS0Wmqb;r`LA}VNS zfSJ`{nY6H#S{g1JsgQ{c9L(y&(1M~HW;3zJ$bvPD*_`8r%3wm5Vh;0_3q-o*a;a=C6Nd}ar@NCZPGLb--5Wg%l4!SCfkX#^svVKB`i6-S2DkWP{a(BZJa zii9R$ML3ASHIX0!V@Hhmj`Xy;?hcqi=yLKzI8=e$8-45{$+MQ2lNIM zw?<{$;{c`9HhPh?skYwW|7-y5pB&2LpfIrUKcVLw))Vbr9o^+}(0on7{dMiFke7mK zww}nR`+WxBXELc3R}wmg_-aBJJh4La%@~Us@_ zd1|r`ouoYpq0^cFpYZr^mwRecf$WyJrIta^SoDz+%A~|Bmk5`YKm?*k_y|nKcngV) z@G+kDgdESt`*BvEuc z#!q0wRW}w=dPjipkOaL@mcyxOsvPv@#=MuWslNgTuTa~)%6mC2uh0wc71CEL7qI^B z!#a6>5{noR$*}RAr^=wkgX)T?6+CJ%$Yb_Nyj{sh8^HPa*a}$f7vLe6>!$i}5&Qxv z1(T=pQcb;bPP z0Nfci*{y3af9Jm=Do+O#dAR4_3w?cl9W-D_(%Y>DmQJH%xHf2g!h9Wu zcKUfDar}QB_gg5JPs04~&WCAVhDU*Re*Y)`&hi+4=Ix>y7~gE?bTfU4Fc;VTj>kz{ z^SF5brEfO@CQ#=ccaGa_f2)IouQH19Noe)xaO!!N?)+z7yc9UWHhdoPmjeIN5C=E$ z%uLNg5o>W_3`%Y*;PhQAPcJ|e+yW$w|K^0W_MOl#f_MmHIypXV(lAiBC_@I_olvg= z2`PCye)+iwT68R`GOA-b&$X6o37GA4Oc_qzy|Z%Xg&b(KoD1j?&Wl0GnvvZDL>^JmW?rlo3@8f z3nz?r^X%Gyi)s7}$c0+K)zc7=^SQwwxqCY{L)e8tS+9I*Emf&Gh=7Rh^(@AF6W%Z0 zwH!R--8lPzxfEt2Oeai}HmP{3;IZ7b6#Ny;T`*tPW(n^%!W{2j3O)|=oSvoNd~JRN z`!``$Z(0ie9kAcSd%rdnyoX`-T)7nFU_Jozc5QCJdk*HvRZGF|!(6m^DR{CrKZN}o zFy7Tm!S?{m;oYvyOYnX+OyOlqK?>$mFh{j{FW!H^?=4HgdtiP7v#iZOU$weJBH%M_}&L<{$C?7>qZt6#SrnDOkjNuQogI&cW;%M3^ui zfO)$%H{d-7bLhII;7?($dwJBfz`h-ZZ@LkO=GZHif*-={`K_pV1oqFs@J%=3&>XHT z1=BDmW9Bok{}l}1bR!OpY2SQ*M-L3EC!%l{XAj)Y#N5?Ntkj<>6u{LIy&HD&Jy=Tt zU#W%5R&iC+tX@k(4HcPXBQQ6rvwq)%aE%TGB656quZBg_6OMhy;T{?Lm^M5dI~Mgf z?R=PS+qc6(ur?FaI0&Az4h0pO`hP12VLY|TmCN@S-KL`Mq_5!^2ZSBDP*xY;)a>LG zMk;0N$1ND3%c<~J`Zse8-S2sCbgp6fozgH}evui3N#}gC`be}4yI~(v>4SK`N}#V( zm{%#(Rw#g1X>3-kdTu#;vEq=0B6`@6$oS3S8#^hSJ%MGS?kQRZf#>oZN4gVUc$Uum zKL8l_7u3nbhx6~lgv~4ojAg(%_IrR)=c*jGY~bP7xaQMV5GPRzz>PJp0-ipYNx}c) zJxt4R!8 z^PD)D|DOZKaxx*ZUHlR-u3cD0d^k@(<@W!wYdSbM$8{yZDgL!?khM72+zMBAJ zT}b{Z2 z5@dN$*h}*Vs$uZt4>1q@48sr04~-9KLaeDrwFz?7iRE;6U*LzziN9Qioq`j zocX>j25$#Efwb&v_4XybeQk{~gpiww8_VCjV=$)SJsM^Q6_GJ7k=%u0S`}>py1Y^Y zgZ=qbpIrwZg+F)Q{G<=4xq$V?r=Z<0#G7_jA=~+Jl&9;D_}w`jQWw_3xA z$8@u;>53QGO@nt7a5wxTNEZYNtgt2h8{E~vrCvln)QxzL!gWM5L%#W==$|HB#{Xl% zmGcIio0GZE2^YAg9GGYS&s83C&^dlCv@54B#wQ{1KdDubIdJMf1Lf9k-4Kh4Uq19- zaa)S_V4X{pt~dLA$%of|{pO8tPJglT{g=Eo+jafMEBhb&^1mPZ_?-{E>32Tx(8s^s z{qb!-dike!^gQqQQ$F#7XZ>LJy9b~5k@vs;WpBIqcV-^^+Hbw!w)B&p{Jxt%^eYeC zRjuXDd-)B|zUgDj19!c#_0n(N{>!iZ<7+P*slMseKb(KXU2`A(qvu}vpC3JSsN>mp zule9pPrUo>FP-}G{14v!sjpu1gZF%D>fOr^uNmzA-K}?h|Kne~>GwbTC!cy|<(9uZ zaPOa9c9cD-xatqLzV(A& ztG@opOV^e^|J2&-Ggj?gx9*}}Z2W5P8(00!WiS2QOGmqZ^Z6UTd-*?I_lueJ{ipx> z9e?s`Pwy_CDu3knhwG~7)PfXXho-cW$5fja%RP$3Hz@`~B^oPTV#8)c0LGefPyf-@pHPkG}0ItN)@ha_Ljw zdH?19^*i6#@r)ne@s&>|Ye!zW`kv!oz2mu`djIo^x23MVV7lu?@BGdmobEfY?Xp|9 zz55#B&`MS@2=C3b&LC+W7oO<}04?QqYf4F>L@bkC4{C#(P?EW8BH%$KGW8Z(p z_g?>&`8^wdJyR`zU~%rYGkFpS>k`>A!vH>dQX=E1y30n|I&wyI*p2Reyc%LwnCW_0Mm<=g&U#+VZLoKmBKSoqzMop7s2#FZi{NU%meM zZ+PwbFZs!Vht~e#rFU<6^=+R|-g(#Op0nz%_gvNY^wqcg)7}?mK9Roq3wPc3nZC<^ zyYh=$*1c}`V?V!t({0r+lzx5J)@yEhUUr%dk$shYi8>J3m!1W~x$!wLTVPT!Sr{^M z7htZ18HO2wvHfLCL z@U~kP)z^vA_9cjlYM%&#wsxwC9IRvPzpF?YIg%rfpazv2CC z`)f{-BwCYg?H!$6-94#vCY$RG3s6l8n7Jd0N1&1mp`Y91-v&BKXLP-IiH2cZRHqXN z%8boh;Kuax;dnaTfLv z_u+l?k>%iPgfA}#_tXB(<>2dle`7g#0Po|cmxF)7yLM_hco6Tz$>rc7yjMT89GoEh zUzUTDcptuhIXK1leapdL;(he^a`0EQe|b6hFy6H6-rvHT zm*#Ower*8*y<&`)=H(vYwh+D<7kh)O`lx0 zx2G%9-kweO^d{SriFB$rlj`cgK(*>=`9iT$-k9H>+c+5Po2KL#C8hnBwEI;uKL&nl zcZZM7Dau3I}+{f=|s9K+m-Ik zcBfOxu0*=6r@bxN*3r@1n{H>k>8?aBkx6Ge)9LnfFG@Yx+SZdu_q3-HZJE|=TSsRm z+1i@KAm5hkPGmbB~M*vs4pP$q)Pjb<=%xIhcnz3iBAuTJ&jDt$oH}KUA0c2q|jc3n2j(3zyWYiDAGG}}bsgZtY% zkv6u!NAUg@%(r14gE8sn+U8=6T`Q(Po9kkjvGlg)GPzVoM{6qE-PV=sX_`jt1URHL zmMg>K!}PrdamUkl3t(>g?u7j;V`ege7L{o2?Ck34>PfX@;A`*c%5`K>>0ODg?nGxR za*#;$qCvN(dXe%>va<~>x4WymBa=&KGOZor9xZ}wy0@n_)!UiPrMjBeL2H}j&mA&V zzRW-S{|hjmu-s{`!uKf5Yhc{*?-tls82-Yx@kG9wwXM*<^uN|rcd{$jn@D7{oxK?} zxVH98syETzndwY*WV?wzoCWp3NnDIx|_cc|5I&Y!8aRE!&f5@4|orw6+ec`+C!@ z=`IX9-5u#fJ8A<1cCxK2%UE*RR8My@g=$T8q#j6{NOg8}=X$#_c;&h>9l73IPiIG4XDjlU?CI&rBr?hNu5r8Bv9 zgqrT?Y3*&xb@z5cZFDA$Q8&|`N%r=%ccr?J?o>B(-jPMU^mP9Z_Ra-9it23mllzU3 zgpdm)Asa#nAtagI*()I=dzr-)kRTvZq{(Kp!N?_n1d%EQN~yKh5~~!cQi9Y{%1ez! zL_{RMNRc8XNGVmM1kqB9lu)!vf%^T=ZZ;PZyuJP2@Av)Qci_p{IdkUBxjg5&pBWoe zQx^S`75!KGuT$)bR&iQw2H9Y?m}JFfQ0+{Z!VoYjM%lqYu_W{sJBwS-xbtlUOTJOp zAu@CjAibjf9OS2sUj7Ge&wUP=516n684MVOtW}XMdf_`B=lllx(uJ*G@>ehEN!-s2 zsj@?-sydvE2Aynl8dRNC@3g26ozCLaI$?M!XvQ+I!7dmUhuHxb4K@eUU^3ecCZofs zbIMkm$)L5^?GBw)YX$kOsv>*&iqo#uX-y6|olL&optCbkR`AGScPO$QjFpWR8-uUc z8x&}!Rne;sxUS8hw`fhO*2^g!WX8EYs<~oUL0q%R z?m&VxSRGcYSy&MeD;?Sj$!0}walr2k4u{^(iZUoV z)}=vfS7F{dhgNnfHj|aHx7ZwJxQuMEs(RUKbZQl?YOy=*s+b?6cm4H&ql(e|**NOO zPjK(fo!}*q`U12WcpIqe=A9mcj_~iI&%H=9>&pP^;vZy3&!C$OdMBcjYPG=FOyHjp z71^$*jKN@_?-u@AK?|mp3m~v!HK;NYn-L$1&U7l!7zs^Q$0vvvN)`&3VwiKMk@j( zJG7jxSinKqLc0x$!vu>q=qv`kN!FWLT}-*f;8aW&tpi%Gw-~{3vs2MKt&mdIj0#Ir zj0Oj?KT<#Pld880K?)gEkqrn2CYX|q)hff+b!MZ@&KmyQ9~LLVq|t_`z_^<&5OvvV zg7dLVRg+1}kg#4Y3?($w)+eom&-IOm0{@-_w>|-;zKDDY^g}Pb3z)!~PkrfKmypk1 zXs@2kIgH|;<;Bd@1 zGohFes+?vs3)5!M$~L`TYlO7wA$(?TH#79e{cwCUcX(wCsEJKTVh{$Hwna9pdc`Jd z?ItFjMQ??*o6QJhC>IvJ>a;rzCZsr<8SW!0lC|85lme%-d36z(= zk)5Cf8Xpph6NYSsikWSQB6h_zN z8X&}WL)^UhS*zE|=q{ikLWGSDLv0Nz<6)G=T5~$=S{o<<7Zo&`anyp_;EBP6 zUdme=pc;MU=pe9mfyP>s0-o@CXh_E)@Jj}V zmIJMTW)E}?XaVy7Dzy!ooyG3WS>ELw;VrCS5c#dAx>Z}$Pqe+&b z5ilkg0+Oq&I4u@LG`m@E)~N=)?DX;lBaG8#r4kqw{Lo}JA@^7zmv$Svt5Zc7bePaU ztxP!d2F_(gZ$vPL{V+X()OhCtE^9I(=xU8-mW2vMup;!DA+8{k4%E}>wKlUNI}t6g zyV%h(tZ+0{=q>O!)#A{3{bybrk!i32imOM{Q!EIB79AqB3R$(Abapcmn33+lW1*zT z*k&t(0Tp67LJocUb04^&Gx-#*FN7On_62_2&)mNX^xF#!0-glk1wy;=zfsuEzC8cy zL=7)35Vl^yM~v_TBkTfk3YOLF4%z7eGYX6BVoNcF6LlZ|tu z72N@wfE5t{N(7=fg!C!|GlW?dCNrTzp0rxTXNTU0Pcj2+aiEnj(O{!kY@n55P-F}o z$QBBf3#`;4p`-iQoCrgzUho{Wb@-?XbyLv?RRj1T8*CPtx{yH7og7Hc=rS;E6nv~x z3dpLZ1DH=NP8hYgUq)uT`C)}OvnZfxa7Kh5C;ZiH0~=L6bWPmf*L*8C;VYuNIK2FY zxqBN(eFZrOcoKLU5T1tnv5gA;l1lp1u-b_Pq};X0HF?pQAsbFDzM`?}bqe&$WJ1h@ zzr$w9zz~BR%RFKvav;iT71kazr864!$Y~~MpI$ZkWJ-gKZ9qshTDXD}8P#DH3tp?Y z>LB(kYbTN;L;&5-poe54#wtRGqhfd6auuvg_ zXyF|)c28MGcd{b6ivA0^N9YHv3f<4)+46y^NDDpW1JOU9iv&q5Z6%1HbqpCwI zwws031(_Spb@Kzw65#>XfJBTusyOXvy(qsrgnylvX86ayk@0N>VzEh=0gXT?^2a$szm!uC?a4adXK~ER3N1+LS!_jP2mKw&55>x;AOWeVgT(Ru3fK#alwGS_ak^? zL9t*#wIIP!62a1;I2{HIe@4|Q!~qO?h^mO9h<|pp6$LFor^4FA^Wkb{6@8uND+(;x ziS!C7v+2+`RXsBb<2DJo&0@7cSmCF3*et}4^(F4_QVRJWw{(+V+QhXlGuU2>A^2%$hS9R2+i(LN2hyFBFWwU>E@4R#*Z6OVs^b9tgF(HY=_l3%+!r{?`=^Ta- z3#>vJzP6SW1L$n;d1%z~ z@CA0QcmxU=DZ!5S2~&yLqS$OUjK-few&I$9e9IWe?*K0V9{?JB%z<2glGH!Gx5oc= zYPQ3Vztak`fAWLxd@g?wdbR(6FCb20bzx`>veAIvgKK;C(#E5e4S z1E-LdG1cjvC_mI@!8U4>t;pY?wo_$k-HhI|g!;CHi1y!ji1}$|4%&d&*P$yw9nb{K z@1~!$a^7vE{UhF23cZK#nXDkZ-KaP)Ga9T&fL4$l4FrKoZ&D%NECQ@+GTaqC3}Htr zOcrQjxJk?y70?a9SsT_TluAtbdL5c9Wnpwkv=AE1{tg-a0Um)>3wanboXG$#WAVc5 zCCZ{f;7SE)kup`-q*c!okcbrs9i##_j!J>*2sNS&y$_a>is*yEO^f5fiP)sb_~H7Z z=f;~js=WA5T*Y0$V?Yb=0g(K=4*Vw-`0pSsJ9O#IJGXR-NSE$5Zh8T1z#)MJ4AUac z7_&`d|=30{>b4PN7yHxS0`k6#Pa)`%b<-Q&0_bP3$b&|DY>(P#8f%mRWKW1n)Epq%v3&MyX*g%170NTqo341XtNS&K~ztFYCfT5-&S zq)6|0C-gX*o#;?@ua=Fr(EGsXfF}*JA6_A_+KLWr_j1(^`U$?YG7i^(5v|w|faQP~ zpSMZ<t(ZXkS?2%thZg{y)u zI&>v1LG2=JW#PIgNyxlbRv6I{ zR+b00Q4rsWVGY8F%>kc3e93CZ<4e_43;RZ?FkuB1D??WJhoMu^V;09GWkg@J%NSa~ zT0}Wv>s1_hTe$_b1xW#X7dV7sZ_`uja;k6euAWePYPAe3eurV z!d>w7&_>iB#iq9t1OgerTL#Gy1_2e^W^w!4B%Hqp6fiTSaNHZ%9cjDG#4sU?nC-Ae zla*>MxLC3LBUd;vC7=mwar{C%geHxB8mk>1DHGj7%r^`34aP&BQnYMg@Gfaa>P-E&^X~zAWfpyI9XhS;udn zcL8ILvEBhM{Uc^itnVt)kxh4eJi5QK^_Dp?uHe}HqnE{J#$qOC{0SwnSagchW`~AA z{V+9{p;}H*)K05GXK+b)9Q8)%K8_tB@aa+IQFpOEK%|i8u;?HJnH*M}P3T%M5+PCB za774Dr|{8YImT#a)1y;im$SlPSTqFx=*$Xg0K`^sAu%WT9I?xroO&nGHNtrVNkg#( zCoD`coW#KLv0Jc@ASSSS>_#mXT`W*UMW7-$2reN80E?Ztk^9k*kv6epA~wLp z0HJ^Q4>AA$u0C{ixKHljqlsOG{%`*3cos?wkwk*nSRg0J?Wh(e1DW0mb=nB**D*}#BpS}rwBkref`u5TvkXue5{{qqj?^mF-gUv z3c)5u1WX{N2MO3N+{uWn7$by*0#auIsYDDbHb24TMHB{#fnGSLEV$aS6Nz<(1q4MJ zLjuAYv|MK;P6LCR9kYZUjS_D?vus8I5o)s@9w`j;S|hGfBtE=M4w$eJ^Df#Y7FsP& z6tovyG(#y6tPv2f#Tb2j3+ni#58)ezPUGQ68Ap($QX~dp3sh7E~?x>8K9a4d4)&=ydIbt zg|!#^7|V=kH0n7_LF5dV09di-e&y*F92fw-g(NmeuGID zztdb_cRpt2$a%+~&%5@$!=bys^D?VRge>C}7Q%)ZV<18(mN~>~t=UZQ0g|Z>UltZ_ zXsHR;1wKiPSrBE`A7&~<6B^dBJ_!o5Vrhh}V@A}Pg&7!eUB*j-GK&O8IEruS1_owShbzfDo{;s=J22NXxm1tChc-HdjBX)%M~ekUE23=>TSQ%- zb$In##?8OJ>KLb&fbc(ctuGT*eBb7G>S_G2KzI7}BhFA-~v7%(9tV1_eWaTd!8REO9g)qr;utC9_RNeB?$ViqBs1kwd{B0S8i zNf>-`eP_6VAMLuQM08k8dewx~U^QBZLlL?h(h)pXcJ!n>1-+x~bxI$^hc=7(y~f;) zX(MhBcnP=$j5*U`{~#6X=YG;fEfR>LCgIV;dx(f2 zR+XJlVFSTk}KD!i9>`}^<5 z?{@krzk`hy=#Jl_|6drtz0=0h11n(>c%}&+!+!u>K#aga4;N$lv5<=}X+#&adm=aB zROpIelCY!EXe^LA!a0!5?ILass{>I6Sh9uQj_So&p)2E3CxBPn!$4v8=F`4Jo(c~F zj2XKoTAXUup;+r7M~LZIGKlsekKUulso3vC%m*SVMs;GtRi=VSAOtHg6Y`Fike~)c zRN?xDirrKW7UGx)0>jlJw%@=>^k^Fle_wP5s`xo{N8pAy#QeO?T*RJz*X0221^xqQ z0|bA(|6Lz`4kV4;`JCS_H`(;s#@g1mhQ=`oIFFGFP~x#R68UUoP*}Bu;Sg9rZ=vBV zcY?%;=)_SZ=8T|Uwg-WDf{+lq4p|Uk!EjGB6`Nf+;Sf{^HbvJKo3xN17%c)kZFYkb zR|Z}pHoiE}ln57KJlRj-bN^r-QO^J(`akV`euL8mCH39&<$41-3OpcR*o0ZzvR$l`$7#n=y)b7!ipl z_AOuoLBfN-BCrsxX+kS>iZSoad$6(-N`mzO&mDoFB4mgahlF_(IgSYwrX0}VhEAja2!yv{k}V#G*oXNihX2}CbpyFm*h4gpzCM^qOf5SVC$t=)u= z8Iu$Jw1dd3JqE=_^a3jv76pOhcKj4xTRU181|OrvWW_1QBEWzz;)=vy2rl9bfR<_y zc#NqBeaD8DMVJPTJ{g^1GkIlIehFadA!Ax?GtBMi5S!1NEm=w!^l`FG_@0F z`ryG|tjB(g@TLC#`}benPd|SF{2u7uf9ZYt-fwGs&i6?3LyUNK|IBkmM82tnsa zLC}A8eh{RAfF$~BLscR|k$o5<4wzUh5v{>62{*P*d_A6e449`8o>13OK_FN-2#F8H z0c1lwLQ1BL5$~d~IpWL(MHyE%4&nR40f4~(50T(OH;ygz*?=z`YY7Axl1-UDaOaC` z-SG~f7{B`&n|_|Qv;;5-BQ}`N-YUY{Y+hW#O^8$iLSUIRD%hMLMHt^%VmQ1|j_9WdKwwP@YZJ-? zQEI4GcI-_MF`R~Q0m=vqKYkKaFl@DA5er=vx1^28a=4a3_!Vy)FE%oWQD@7R9-Eax z&m4>K>I?n)8Z`g-w9@|%f#mbZen15v#^-HPF+SfR?WFzQfqF}f&pSxGA`BIE9uq#O zCHCSWK?{co!Rw;m1V#`Whcy~vf*}rGh+iJ#KRTpW1`&~5*y@O=!@fe;262@Rp}-QD zWYz5Ro;Z~=i8?Afv-_YogNA2742h$IA(d;6!N9pJ9Q zjgK@B3q)-vtQ#!_!P+~1>=PuO5FrvXKb|E)(O7)MpnBI2>k9oHDr?|AXV(ULfk<#M2zr1L}ZAz&rn>o&7tPxpkm_dEEZ5y{iwE zZt*jK4l;AY)4GU{zub+f7-)aqSFFRUTN|vzLLiYrvhm!pnTAaiHZ(Jg9gG9A0s9dM zS%O+)_9l)RUkMD2L1*_78`Nx~9hjC7pkV@tVtS$-Q1sY2!Z@MBuv{5p#54y1XgC~* zVZryuwjkUy4l_X!xDZ7h`f4_K>pZ$@kJe?Xwp5xu9+Rh1?=rdNYKsSPrqb;};x-v8 znI(_gmhP#^35{T@A;vl@^=D}cUfZBA# zQ1sy>BT&REyxe?8v$(tK5c`|k!2$i>kiCJI0O=yKIKU<88mYjK?~%T`-WdMfbHR_^ zU48GF`1QkguGsLc#+zATyXSXjTix?TE4rU|AB67tH@V-77h?M=5+z1Sh42mh2gvDm z8-4~z4$2U2E!HMN3Q{F@9kEvpx?(_pVL^)L3k#!_s3ihg#4Z^uz6c1ABa0Oo6LyB3 zQz2Lcn;^~yY?1gQ;D=ZX2sIP;6Z~rOKqAf61a`S)W2IYLh4Grtrm@_sl}cl^yV|2S zR~kLSsAjRas6?^ppCHK3@n0 z#Qev$Ll=NXpcRO{#5v%de^M`fAYEGDkhuC^`UTHNuDa*D8y{PAZ0}Q_qW1{@4AK=i zkGIn)c8m&n2|p+vl1z$PNM9`TCNQx6|C;Bg9ZDg^-5*r&6iR~A~1`$Iz z1qk?q%wymr5Fhd=V*JJS26kPDT`aym|AtB&vj&g8s?y_x}+Iebs(AqJFavGGC+bHZIMv_Po4(K~ekQf{>CFr+>%hx@g+qU7*PyU<;$s#a8A>axt2-`=* z_BL#XOtOgxLlOT^G#+v~gbObcLO$+OXpx=`T~^V4hzF5JVvLabsEG(0%)_|*2z0{m zWgy^&ZPN&TMAYa|Ic@9!BFw2DzSx zcxKO>US~Jnq8JfxC?0G##bL!3Du{*HMh$+jPm7Q|hX~L1@(Ngw(8b`H zuqWXO!&HGC09PE_M2MFs5`g$P6hAhRh^Pb6HpT3+$khxI@r&ZWzEW?ga#tFSE@PG3 zT#cS*cDY^nVkoCqD!p;Qy?W4*f!xKeT7|#@#fbwB&pu%~glCH9^c90=>EmS>VtyK# zgI9r1fKeYII|7dZ0>4xL;hUe=IDfU~E{EYy+wXn#`8&7F7&3CYJLD(%7|V4+Vzd#5 z&#nrC3RM8baVl7aN7yU^VijmDn<{Zf`20R9?l~J9X2q@vwgf;b2=)=dG*DgMJwgS< zFB^9T#Y>kC6;h2rqe31O5IDiVe*Hll!LP<>3K-Zmil3Cq6< zn`5`S@Y51j#3^PWE{V5@5RESABt}}ccKU43*duk77DIKl+g#-$Y8qFCRtq1h)al(- zRS<}3aMeW?x*TpZ(Z`$N6;?mC6CkwGB*cEy7u-VF%EUch{n(3KeF!Hs;Y$f8)YpA{ z%NWb=051R^0AhTf{KPlD8d6#PRqboGf~pJC*Nix}Li5)%89zS$1>96O>*l{JU;2OF z20O95Y|2Mw77T=q0YrRY`4uq__ zGkydxohTwA^z}GzP`k0CQyUS`Vq**x5Nj^)fb!}~T9k3*3f6$drBu2xh#A~wmx0$i z>D;C&ZDkcvtJMTqS=D)qc6Mr(3aS61N&F)1F}>b95=`bCI55{1~K;5HcKN}Rk=6A zPwaQVEmu3}-!wpMFouNqu3;k6)jiWYK-+mrZX~z4%`ohE87HrHT4}`Rf&9 z?f?B1)6aW`S3W>t#KsNnCPEXG6WWG&;f0Mom*Q;%tRl85VEw_#PACInF0KU-1E(3Y zVG`OcYA7*G!sJMC-ra(n$D3JDQ*h)9%OmggWKR$QF^G0-e8UKegOd0>))_{1D{<9g zJA~M5#Ab4AvSK$DuM)u7j(LI@2C?lC3o2V;anA#bYs7Rwzcq~;W7apuCliMN-`P@+bRpx`OqKY29oQQPXD{MM2L$wf#S?gkl8A2FR4VnV7 z82$Rp7%N`)@x^glv{m4D894kLkbE5eCosRUvR$3@T0po4SMREY0`st z&#wR3x4(J#KkENWIETtFVMAgvQ9vPjM1|V$UE@Awix~nH0UP)j@hd{Vn1&@SIT8ogO@!S{*7a4BxYdSrclbtQU|2ZyWKWrj4FAa-UKG+Jziwzv_O zWOH?OrB<%eS9U!KQ(qW;f%f8I6f74<(!x@UoY+`8ij zuDz}9*sy8W*41}E_R#*%8Iv0?dua(4Cx?Ut3O8eOD?H1A3QSxAyPeq@g-?t(#4+8x zbb)QvyjBcDBHMEi@SySRhVs%IlZT*^YEPA^y3)mVO(Hklf=L;xc>$r;QjIyPQm(8r zSUlwGE2~g}ja5di%PaTZXfy0VJ7K6|vo?Vy*ek^A*2KPNco#CUuxIu$f1fqHKK(A> zJ@5RLl1>1=2fPY&pFfFr$lf?uH#zr>p{mdt_WcmqiFl%7pBHj7HUky}(P84n2G9!> zYFHsrq$+#RFxq2L=KUX)CB77887*Yda*123}a}^w3S8b^h z_uQ;4giT?W(;~O?iXz-11a=cq>3bhX@3H#w0KftzU>Uqnhz{!=!~r7TVbr#YdT|m7 z^Bck!$_Q}?5N+m1yjhNbQ;;0ChpP$v=cx9$s;fQKIt-@TY8a9S8$q>8u0qQNow;h_ zMVnj}W&6fiVyfV_c#yGBIE7oCo%=WUkM#9IN-@4qiuV`;9|9WQnL7cv7ZBrnja01v zpONl*VqNpP?U`-a5kK==$tU{<>}ILojw$+Zvoiktj!+^j> zJ=~BYsG8UVJB~ZCHB!{eJ{sY?LgHXkEUy9*(}G!?z0~ZM7tt{oeAwFJ)dO{k3!EqD z3{N{UDHNj0?Pg;+QH~5I7ABV)QJBwCa`ZXo!oG^v3z-`qgm`%`Mvp$}0+!J)z-q<# z$A-M;8Ux$~JO;D?9{^(f@8_M{8@q}{>6;&Z{POd!M*8s*@E1Vz&wq&ib>IPUl6@bdtb>R!@v2#9 znqaWRonbf-;Y4h&6q_wY83QhGf_4e?gb)f(Fo8*Md{9B`4>5Sx9-#d~1hg(=GgqEsm^bRL54t35>RSG$E>N-xUzLj?SIj%y3cuQ0?16~6@0AhJJc`$W9Nh`@cJ{x2bms{4YZ>jRZ#6C<3>*D{_#|Fs!}cV? zym54^ye*Zju)O?)?H>ex;m_dd_;k^=Mf@+ud%J`~4aFZhk^nwlAEXzXH^ufg-Y9C3 zFz73&3`lqEzlJ^F^yKZ4Xyit{BDtz~Lo%uZeo+s51JEa`6{Ck>6wGgI#7ElULA<=f z%u8-~<)3(8nTY82I_dhrmCt-fuNa?Z#^5mUS0Idc*bf7&fWVKJNX7V6kV@IpH^z02 z(3HfMZ$$n6Gsed(8R2(033-ztVWCEqz*7P%;Pt#ANGB18gyw`}AB!+6PQ(uo`!3#d ziNwvCaeEA|YD(zcvP-9UWRF~3EjAv?$SmFGgl&B6DfTLW1T%?w7h}+uf4{GR@b|x! z{#^hfdG~uZ-~a@EyhJMcUqvc?6czZx&i>~FFTA(-*>2wk5Z_PnzH`0%2O&DI-^*)B z?@{iob1x|u-?J2D{xIo`>m{HGc%}oclD-3oeuyKGuPuZ~VN#S7&37u|r6eg$N|&;v z94VKtI~t@ysYtR*LotDl@?@8}V7o|(mRVg4KEFd}{CLkeTP(VsRR)7*<3a|te1&j}v z956FrR)8yDc0g^wqJaAXmIbT|csSsZfOP?z0-g?dCg9nCodLT8UI{oDa5&&dz_EbS z0p|kF2V4&LIN*9fL|{~4T3}{iUZ4_a2`mh>296J$95_92MqqiMC$J`PPT=Ce6@e=Q z9|(Ln@X^3Efg1y#4%`~JJ#bIp{=g%FCjw6eo(((~croy!z$<|PK_Nl$L1{rbLAgPO zAX89bP*KphplLxff@TJl2h9sw5L6$uIOw6E)j?~6HU@18+7`4uXjjmIphH1NgH8mU z4tg)>QqV_1SA(txg#||h#{>@wP6^Hm&JNBCE)KQ_tHGtglY*xO&kA-2*90#MUJ?9I z@T0-&gEs|l34S(sPw*?j2Z9d=9|=Ald?xsO@b%zNgM&gMLZU+ALJ~rfLQ+DqLvlh2 zLMDey51AF>30WMnB4l;QqakZT)`e^c*&MPpWLwDgki8)XLk@);2{{^aJmh4^xsb~t zS3|-=qeJ6DlS0!&GedJj3qp%Rt)b&WOG77yP6?eBIy2N0x+HX2=*rMlq3c68hHeVo z7P>2Rcj*4m!=cAQ-wZt+dMWhd(5s=>LnFfC!_vdD!%Sgn*!ZwXVUxqAg-s80h0P1A z4_gxUP}sv^>%%sL?Fic)wlC~p*x|4vVaLKwhMfsJA9f+^J?8a_FEO8AWMS>fg3HQ@`wSB5_kz9IbS@NMCH!uN*n3qKToGW=Bdneg|+FNS{< zekD94A}k^;A~PZ@A~&KS!VqDPD2PM$@n*!?i1QH_BR-1wIO2Lld}MlLMx-{<5?K^k8aX}E73q$g9a$T>DDu9@Wsxf) zS4BP)`DoZ?q9#X8kD3+biK>mdFY3Xlhoc^iS{L<1)Xu0~QTw6}MIDJc6?G=+{iu(ku11CR zi|QBGFRNccKW#s2znT5Y`?>nf>sQ}zale)Q9_;r>zcu~V_uJlYN55VDcK18b?`*&K z`kn80so%%_uJ#Lv4vLP6j*m`{&WO&9&WkRJE{>iQJuSK>dP($(=vC1VL_ZY$aP+3= ztUDrMV`j(9iCGr2CT3&IrkKq!+hVrI?1gUQ5?d5o96LF-Cbm9yN$h>Gt70FBeI)kL*!8iSVxNwE zCidCb-LbF49*jK~dnxvE?Dg1?xTv^ws|srVJ<_ zuwX#_fF%Q#4p=>4?SN+nY#*>=z^(y%2fQ-i@PMNOP7k;~AS^yQeo%aNd|tdM-X5>U zm&Q+upB_Iees+9K{Ji-4;#b5!5dTp8Bk_;MuaDml|4jVu_NfpZ4d4qPyB(ZGiXt{b>v;KqT^4%|6#&%i?ij}JUM z@Z7+Vgs6nLgrtP@gsg;|gxmyELQ#S>!Jbf>P@dpPn4K^uVQIp$gp~=a6CO!eoA5-! zj)dI_uO#eGIGk`I;p2p`#E8V0#Q4O7#6gKEiCKwCq9w5?QB9nbI4!Xzab99=;-bVy z6W1ngNZgY6OyZ8jJ&F4gk0c&Td^7Q6;+e$v63-`INc=eQN@7G(Oj2f2c9N20O`4VD zPFkFFU(&-#Ym%Nw+K}{g()OfXNqdtHCLKyTo^&SZ{iMrDA0>U76qX#HoR(}zHYFD( z+mlO^Cnirzo}IiPd2#a66bMm(2?a8~6Ur9cYd^Gt)@|(%0liy1| zpZrns_2h&>DTB0wltJpC(m|64%^b93(27Bi4q7{C-Jnf_whY=j=-EL#1|1l5WYEb$ z7Y1D)6f`(waNOXe!5M=y2j>kg7;G3^Jb2>Z$%AVK&l!B*;H85f82sSiM+a{nymj!l z!OsrfHTdA*BZH3*J~8<0;LC%r4*qm-NJ?f(R!TvNHpP@um|{&Cmoh13TFQ(RPs*H> z`jllUD^ngxS)Z~wWpB#zThf*I-U6;Bk_36|dsXJ2-rk+W?oO&fSA}u8?BP}z{kY-6MPP3+sPn(i9E6tr& zleQpjQQCcJOVb`mdoXQH+Pbt2X-}tZPTQWgGi`s`iL{exXVN}OyOI_#By333koX}< zL$ZeC4k;K?G^BLM#37T0%p0;`$b&;x4_Py0(bY!Kb`(e`i}J7>BrK~q@PPa zpME+0)ATq^iY85yt;x~kX%x*k%|y*)O}WOc@n~u^i#1C%4{A1QwrZZ$?9%Mh?AM&t zoYP#;T-03Ee5#4gh|e%&STjm9CS}aXn3++YQJ=9iV^zkQjI|jXGoH!Vp0Ok2m5c)! zCo)cDyqEEQ#-)spGOlI>4UHHYGc;vr#?Y*xxkI%>Eknl-oix-vboS8tp^Jtt8@g)f z14ADfx_;<}p__*89J*)d$)RV4zBly3(2s`(WkzI1WoBpQWENy9nTAX?b8_aC%o&;P z%sH7WGgoJ>$=sZ|E%VvTy_x$n4`v?EJe7Gi^J3=Z%qy88!=i>I4I4BpXIRlN>oEJU ziNnf=%^o&q*pgvOhbUH&3ZO#PuAhABUx`|oyqz* z>q=J0@TlQ2!xM&Q56>BH7+yHMc=-6?Q-;qN?ipS)ymt6~!&eMnIehi-Cx&krzHRvS z;rsY#+o9pdho2gLarj5Wld=b88?sH=6SJpePs=XPo|8QZ>@6SG(eKz}IcF>5h5z!;!N2H8MACWOaJECYr@rcq9lSj-PF>8ct#Ox7^ zMywdIcEpAeyGQI9@ydwfBiVHo7e;(MA}A*$CoU%=Co`uwXI###98XS7PHoPj zoRv8bo@xe=pcMkS5P991yN zFv>E@I%@i;8KY`OEgrRE)B~d)9kpT9wo%(h?HqMz)R9pqN1YjUcGUZ$E{^(iR9IeG zUV2_(o;|NLZ(^P+&y%+x@4>wFc^mV#3H?CHc$pSLHvNzczn;{-*q=^PkP%ng2@uzWl@a$MVnRpU)2| zh$x6Eh%3l0$SJTEs0HH-CKgOCm|jp@u&7{Z!HR;F1y2`jE!bYLui!|*(Snl&rwYy$ zTqyXc;7UP&94%+cIk*Q3n`Xn>#pd+lq@AzDZn&iRmLeZm2zdaGDoRbmMF`VmC8nCld?_OrM#jX zQjRI-l}pNXB|smekJk^c_ zYkc4Mu`$3DWC}B-n2K>fmzpM-W|>^3MW$t@hfSMITTEL`2TjLKr%jhkmrWm=Ld;R- z3|8SbA2A;{pD>>?pD~{`e`*e} zq**d8S(Y42fu)EbtBIDGmN}LsmZg@JmWM2lSk_pcuxzw!wmf6mZrN?wYdLH=WqHqX z-g41$)eIM6NgtCl#xTY{X404`V`h%=jF~fL!I)KJ z9vriF%;qsW#_Sz)V9e1mr^cKfb7{=SV}gpJiv|^?6r~qs6y+5uMW&+SB70G7QGL;( zq9sN56|E|Iq-br?`l78x&lK$_+FkTY(ZQl4MVE_0#zu^d85=h?ZEWV)oUsLCm9f^b z)5p5Udd4muyJGAEV>gc7HFnR~y<_){-9Pr=*b`$+}Mj_KOGxY99?WGE-Wr8 zwieGQE-&^J&n{k4ytMeC;zx?N74I!RTzstfRPp=8=Zh~DUoTE6$tcMx$t}^A6qndb z)RI{xu9Dd$^GY5ld8A}h$(E95OLms*DLGkky5xMx$0b)vBCJu?IBSA6gZO2Gwa{8@ zoniG@=U5k8@3TH?-D=%w-DBNrJ!Cy+y=c8`y*<nGW#+iUC( z*&nt)YJb|k#r}+ahkcLzfc=R5jQyPby#0dxlKqN3!V%?2a%4Jk9EFZzK4~-FG1)Q2 zF~i|;)H+r=Ry#I2o_1_?Y;){!>~$P;oN%0UTyb1=gs5?9yqe34j;v~_Iz^qPy41z$ zQgxZSTHT~>Q=d_Hs|Qr^y;b4iPNpUt5A zU-7L~@tsxijaBh|Rq<`rOMF*Vd{b3?PgQ(NReVQPd_z@yKUI7?ReU#fGv7=V-%AzW zN)_Kp72ik|-$xbSMit*h72iY^-$NDOLKWXZ72iM=-#-=KJ{8|R72iA+-#ZoGIu+kJ z72h}&-!~QCHWlAB72h-!-!m28G8Nx372hxw-!B#4E*0M`72hls-zyd0Diz-;72hZo z-zOE{CKcZ$72hNk-y;>@A{E~u72hBg-yap<9u?mm{g`i#itmluCQX_ki9f3KR_WGh z6DCNdw@wwHj#F=w)LW-b^!`zANZldh0mJRw{mVBqC$lt);iCw@tB5=qMo0rBZgA1OBY3PBRa2 znx{1IDa_fDZDN^#j;ptqPARobP-kNPXw@+I#Mt zblXHp{IO2$`pT#H=<}W8Px)-me2iWVuGvMBb&9>TRI>B2?jq?H^$sy$6L@Epz}x(# zXI!59&$!Nh^Nj1$`_8z22Fw5+;9Mq^>b=8MB+9<@oinb$RcBn^1TJ;JcG6>jxaJ3O zUHl$(L%#pI|C;~0NY`{g_iNp+i|31j&B;@&Uu1Q58Uj7;s(Kf;!upOcF#GDc*oa5XSom_rke-rsKC0>2khwK{h?0(W ztE1lE9RD>c>CBr~TUArNq|c%0y40;Qe_h=!cJ;R_vuC5a^6|pl!w74-^`qOxMU``F z+}*D&^xRWB=Z5b1ThMu}TV3@HwSqGAo@W1rK6>K6)JHWPy_nBuKWpaI&GpRl%x~~i zN%Lzp?%Mec3v1_Usu#_7iw}Q_JTH=Yx}M$FMPH45U8$|S+v9HNais&PJQ`4{?+Z8H zB$@%LXgcycvHga-I}3Dgez*JjXr;g%f3=?ZRdqdTyy4-yryQ_ZImu z!~fLoSG;r2=O25InV3zys*Hp8m%m8gBhjNs_xgKW=wmc|#ATv7vE1S18O_^%F&38I+lB3i)!+T}Q)JeC&Uc}#W>(r^Ym6zV?oCG&$ zkjvc=^S-ZC&F?$E19|(bt^O{Twyz3(Bi{GJI|WDX1%AO?+1zt zeLPKM-=uHiQqRZO)!U|)I!o<{EFJA~H$bm^gW_AT<(;_EGrK#f=uut}_#PQOTGLT! z2cat$RHaAZIxmsymhWHXJuWVs+v_>Lte*9g*Q;LgdezshuQ%3v!=)becfWSy zbGl#a{k+am?De=FS9(6J>r$_WbzSQItd2!>Bkp!&_r?nUg-*oi$moF^9eLgQ*D*8x z3!QE0$e-_7OfP5G%=dK5==c=859?9J>OJMIhK7ap-NxgFT>n^f&+ax3-Lt!ofsYGx z$Iy;ebX@4&5C4T5`{AYcz1Ej6xA$0fVHM0D?)2_Ptr(KOed);Z5yx_E}0%!ta7oK*N0B!Z8i?|PHzxT9DT1uJa zr(G>8$^Sm*t53VifI6V!N2gt_Ysgy*bUT_F&$#Ly>GG%hFLe{gk;UuE=R+2{`|bVZ z>ReTGYu$4s-fIs3%@fIOD0ci5$?c_9O_{4|0wpvfvg$`^vg&grI|7w!(ZX9?i{{o# zetmtOXI?EIUH1-^rUr>?VYSQc>C%(D7w&|8l~b}?LwdHe+f&vr zs9xlW_DS~JCipVlw@vV7_-oZnnm>1mMC45IEacJouQOeN?y(m4(E7y&dM$LE4 z^Ngl#UfF(hN5B2}>C8()y#D*obAz6*De%_ z4h6pHkvt0*YCLYu+?q;hUQKv;o|&m*#uWV4<`c#G6HRKE<}4HZ63`ud1D= z@zEW`exC*kCi;|Ksq@*Id9JyvOn<(&{pAkpRBQRI>h$u7>eO2%IeglAc~xz>cdUJ7 zIAe~`4?C`kOXc2Hh#_f$UI`E}KjJ9c4*dWc0bh+5PE45(T)4RZR z$Dw(S^$s)w?SSU_Gp^>H(A*c!xXOUoU8KNrpaqa$?CM(uze{$L_Y!4*mc7)qkL$0I z2Q&dK!1CYn`}H%f*27#Yc*oT)zvGJ4zT?vTj{AV+K(}spA*jav#$ zgHK&tGidwa(e@NMH*((J%Lke!oiWUtH~Bx+cUSGWr}7)$`pt(EZ14Ykv{B=)*Ps4d z>o;AP6ZPqx&wm)Y^TOZEbFO~0hCKe(EymPo$9__iSp19Y!;X}%^vue9d(*Zbr&eCRU9;-8-9J5^6IS=* zAJ3cJ&v5J4UV1$EQp4Qv-)7cl``hhL|G#Q~a>o6-#&0pX?VvDRg6}waG4lI=T`+xCXuqY~*T$^+ z`I&bQZ2jn0KR6kooEY+h$J)M@$uAI8xy>sH37gA2$lTmj|YHR2t*~go|zU9&9{`&aCt53c1-A{ME-T3pC)e}E7 z9Mp$u*ZJq&pZ@Rs{|}n~!0-IXxbL6Oy>Wlt@K=8S_OC03JO6ZW(U5zJUNr6b_Te#5{1 zar_%~1-K{moR~i*_^#lwtE-D|srcJ~y?HaE8XEra=f|!LnfH3h zFhAb=)BnZ)|Hc3RG5G&-+>C}zKdK$@ulL?HFTVfzExOY`_~Xm3w$|^`zF7F0?)it; zACnr=H}C!awQ(1+?)k@~bAC3gdh}NJlV5-Lqr3E(&o$&;I(Tp9>cm55*L(8LUVq`` zYv1|)n?r}@2mdVS{;>G-(|<8Iv;Ba+{#w=CzshsQAA0S(1uIvb`se!b%bsd^;4e$= zQi3kbJT*Ercg#oIpSt(w^G3#hQtbF7@3gjmTf^47jq2LJtZT}e^-9&{)cxVkRcTkY z-ZE&`g>P+q_IT``Z=IW1|If>F_6<4m)Ln)~=ZEJX*zlv02>U~~q|QC@y`M<=$Ny%| zJvb=(=hp(~k6UxcyW?(O{QfV0Dwn-;&+U($el7j>zbxN1e?i5;<)L_+ghvrpM+S|UQ zxrz=5bSh`vew2R2`@Z%S?;HOW@0;)y@0<7)@4NLY-Y4d_g+&I4&hH6}fE*$tE z&{tivqxbx_u6)}iU+a5*{f+oR$B&!c?=N?=^p5}H{a@#Pu}`hyz}tP|p{Tx$K4`A@ z><4D5nkr$at8vYhTyqz@h#u%;tX!01u&`e(!mcMQXx_*ZQLFE$5Ada}6aRG6=ljbx z2ffp)%z}>l+nv3~U)!_mj%A#k}1v6%OgA5NNr`VhPyNqa7B^WYvoe%=k;#&&vS{n z^Bs8;N^Rrp_UVc)PrW5i$(!=E317<_H}#g=@+K0%M>fS4E7&UuR`XQVH7v{ zQK7FX<2()4hT3_zLSd|$5iWj?(%?@L&*B;NIXRk)B8_)fxv$;+zvY$l#h{kEs;bHt z*DkE8m;5!Yy>UOpB zl&h1<2soTF0q(+5RfcjYXu zsq={1x^l$O)wsoYbmi5|uc}#y-=o}(&p?vO=T#ZXD}`IH+*LoXT%c1qLkEH9nh3S% zxY*-@f586@>9y-Sykgae#%M{9uV-T<>5)jj?aleM-$hF$SE41{CLY%kMVDVCT8vG9 zfFv!C!FxuvsJTIT?HJp#)T%_~4{w0ps z`{~0f>IIq_>BCxX{sC1Rmf!%XqCfWo%|KH^ z0CN@~wQ2&S<$Chc0;D=4zZJ?@0wg(yGNu4YGm85P1Eko&{LUkf{IUqjI|HQl+XAFE z%2!anaSG?tC^wbgoO|0>$8)QFznl2I{1)!Nhq|MEd5wc8{|NPtOOnKTWKgBbXXuH5U+StlH%|GYbX7Wj!wgB6x=hxKN%)QT1=09lP zi`;vF=k2H7*L-a#`vdhpPuqZ2paf`a<=$QVKE^#S1Ba;RFy}xUdCh-dtVB7W0%-aj zK>9_Frnji?ZJzfhU-?GPTiU4mUF!aj^dtJg^(NAmcHr+kBPLL)2n&?z0)W6kNfRC@ zm5>(;ltczf&0K5aTE#$q15!euR0cEw;%Fz8|3%%2fl?#T2KWy-i9Dc;9sVu-xd&(* zOkIPhKbCSqfzt8_?n&j@Blw-oGx8~)$+JyB5$z#uHggZxqyo-|az2jwN&=;JpiWC_ z;2zRC9rX|AKFXD7y4q1UnP+^Bd&($7Dox_LNP#+j`ww|4?V9F0ZznCez3ZC4jAnZ8 zJpZ-NN}IV)a|dGuw268-Z%gT2R~y&MX3!6y&x5gQ68C+bwgW9QNx#88cQP)sXftU$ z=PebCr;Bkb?_G~vNk4%Wpb03eq7FCZYe^fpe?E1sB7X(tzQgZD)Wfx=g`^9pPozsI zM_J7`>Bj?sQppDHeT+I*_k3P#6W6&Wkv2X}U8J!;=RWSK_#XM+C-1wI`HAno*8d=X z8|PaBrPk+sdCPZDo^$CJ+`Gn?CvRmeDc4MX?5}-!Wt3~DOzURSANulIDc3@|l3#NE ztS_&Pa?81|g0f{l@Z~j9u90%FlxuGGG{e*r1 z@;@0zp!r{v1xf;fq_W5$sYN3FlI>nVv;w?ov~rztb)?Ot%MDx;VB%gQX%ywT7CVmn?eJnJ&rGFU8bBI5 zfqKT1H#taZoyI++6+p=>ego}5D z7D#zg4bZ~xSn^xuaj$@fxc)ubHI(P20D~zvgt~u7xj{iv1!?O>k$NN`tKh!aZ%}6?c(s&zC|4H8 zINa>uT5~M*#Bd*=;dgugzRR}{L7w|D&;JR}L)L65KsMXRy+T%5&vQ1=uK~yc@timL z>S$AuwSLJnkc-PoxyONwhAdpiTVLCdab=|Kl3!6LX&L8rUnBq5)Zgs8zkMg^Y{sBk z&?v?fXchc{{)s~tvGw6JcM1OKm% z=H0Xd_^hLO4Qc26seYG#AO+)*0y6P!QXYN9Sr4pbiBv@(& zg&ku8v;y!R z@P%eO{c?1bZD!0WZlSH{=i(@v!0&N9k1`c1?Jwo|vA((Tm4FserU^RYEx*Y(X8voR zmul9b%K}Y68_>QUe3%J7phGVYBSr6Sr*8S5v0gI`_9W1roL(1>E3Vw@g_tS>uj1|{3E2w8B*H%&YxB2~D@*m)NfP~Yn z;z{o1nJqlC`=R05a<0i-YwNhSd>rk7SC;`zKV?ofaBma$ZKMxC-BUdG=Zpo=4#aLI zA7}zffC`{(3$TNGp7%X3_F?V;x*sJka_+}O?K1}{m?gN^EmN)o)%vV;FZ}|gxC+YVI%D+v&|HO0JxPF?vGxXsd()YLqQ~)hN z*}L=!s002Fd-nkzRkbjBf49l(*)0)!JH}pt(2+WnfFOhjK{_)b2@psbQs^ZhRf+)t z0YQQaC@2KQf)s~lMGOck7K})d?)gqc$9P?z>6{jkVO7T?n}|G3Tsu4irI{=5_w_%D5S z{}<2yFJ=CJPyWwZz{`A1ZNi-8T~`p$92N@2=Tfw$BAFojQE{c2c~jQjM5as*spkvd(PE7EAZRP|5rbi+ynow z{v?eGt-odccs})V?@Zfy`Szx=Zu0HtyW9@vTOdv)zx72viH}xYgG)cJYR3|OBeFl` z;qMB*{Uf*s^Uycxw0}SFU4ioc^nFGsozlKMW6(F{+{1XezbTg~$GK4X5}JqFBG8oY z>`;97DAw>XRb{9Qzn_nkuW~ebj3+O?eUoD1O(mT40~{;meHVWeBn0edrTL6O?x!N3 zz-Lu;ii9QdPA2k6pw1%JzELe;mA z-z`dJ@SM|yac;lEx{v-Kt;i>lXWiIO8TqF6k-&R1{t@utr=0e&KdIsI<0bEMj`_%| zVjyY8d`g?iLP@y)Djs9Zh3n&ITtz-^`~4iB%886O%5(82A>2O|gBW8AIZj)+X}id$ zG~5S~efzsCd`={+(r(M}CxP;mHK5%m)8EOAqI#F}K! zOSq9pSgM{qbuC!Ux6q_=tZ$$Oj<_;~N+`;|2OT&q|YOOTMsdc}9@ zNzTjQS&i*7zDp1wES2MBKT~e<`|tcz%;)a|_!|eWgZ4y%%C|_FpQgUFtB*1653gmV z{1)lAe~+9(-%@^IYti|`Tdmnk3DneuSn|DA31 z-<_7X21-h+u3vVU1B{o-P26+w zK0b-RNeOHWjgbVl6YYKO$ppT=gjcd%-jH-y;}YIs9lMrm25Xy_zky24<{EP+u89-; z2wWW}l<}QN&e-YOpQo6EY*+FhyjSvFc557eb3!@p2_Gj) z`F)}7!2MNWB@b{;4dQdmUz4(NPRU(yLL%oU+1m}{1owk{b3EZ*&TB@TRvaVT+nDo+ z8~G%1Jb|<-TZY0a>oXT`4{cWvKasdT(zQQjlq-pJ?2ni4$~!~bNp?AilStn7r<}a) zPbpzO!u)oA_Iq5rjX1AjAJ6@)!xe0MlR4f2j}TrECzOt)+-=x?h;#e%&Vk>YDrV3p zb~<@H`*RIWc$hjoO}U$p$uq>K?4_$H&$W!BSBcvVn@F3#u}fM?d)j$$Z7OFwwKMVN z+hye*g0#xEQnnP%f0r~fsNdpn9k>ovcu0eC*`Gx2dCFwQRT^opBwkJ^yn_6bD0d}k zmpmB?3w%JFN$k_M6;IF?Rns6QCgnllkE{RW3 zAAaMtKVE*LENMqs`hj=E0qWvjPP$#lpSqTwq>Of3&m|4|Cy-7U+oksVsQrvnNf!M4 z*6F6L0!PS?bONO3J5T&qLTi!RzPBSS|39Qnza}gJaT1!dzHKLMe*aA6zPw^H$2pcX zoAi%{%I>Be-P}WZDRaORs%xMP=Zxq6^QO>s)VrCwonvhC`-GSC6FEnqEqwG%u#U8I z5^Yh@k^akJtTHzI?dc!8FFEGl&A5%DuV`EMKKhlqlyV=M%G^q2&iFYu!0)|2+RsNC zm9%e3op3+d_qX&xz(@M@ksvq)-_xwE%!gFsCKhw-W7aX+&d1-f`uM%KlJS{J``RD3 zkMeLlkVD>_TgH8xcM0XE4az7}<(Hv0EVG}bB#tvTlj_qRjA@|;X_rz~#-4v3Wuk2p znU`hMFNu1UQ$PDtI*fIn-$IgB@*Z&vYd13Pt9dbU~VVe=oCumdq4eJKG+_&p)v`y zlb?K(Xb*pH?jJeszR5`+2a7DY+i;BbEa6_ff-;t}?|+o-`t<86<|kn#M`>rmOP?jp zyE&h7Bs@wU$+WNi8#|v$fw9H!`z0$FBh*p2%_)>qPdC4>B+?(=cc?q_Bb7C+Yzk$h zT}x^ZpTD0;EF!Jlq{;Ep=jkiPjF~Syhx#Si`_GY9HR{G1TETb>e8{otl&=@NZe(NE5=7c9{JmIg))?pcL`&}SD!rW@yMJCa7`+sO)GC8A3lL?#I3`< zFYCGYF6#R}$7qkzv~d2EIr1sv_oOn~xQySK{Nz#k5AVuWP=TU3?c`?LM_ZPWR_a-fQSK7z?&Uh> zew8*QUO9F4b`F)doa;*Y3eF*&Qm$8Jl-EyRmETH#P7mindZ~=ra?W)#M@kC$CVs$f z-!9>H?ao|coCu7~1jc_7$J~t3M4m0&%O!52I|t@&>QP491-M5jSxmiJ zaF5DwFadkcF(7!PxugvXI@~EJX%D5JI8SnNd zP@VLtx1VxUvd;Slv%Qk*%@FEBf0VRk+%0E&9p{y^7P^VYciF2>A@ODQUt{g!yM(X+ zystQggteqid_Vi;NO*zt__jZ#d{-c8Bj@wmQoy9V_HRt#Pb%R7_%}IO56R~++o(kB zCveez>@j=0f-)riNWQO=4&UDJ-&nZ$EEoPBTD}Eb zuWzPIJX4j|C5;DNT-(`CVw-Dt#Z8=hJ^Q?;_C3P(Vzw8N7W1yOCiP1utR7{%n>kd| zB?wK)w;AQT!X@|`v0Vq`_mM;XYsG?VhL;XZ(RdufAG+NOeYe6?Ld zBHv|=2zOJKJ6uBLT=JvMDsN!lK2Dn?(Y6U|x!(5Tx=s6}vR`JGgZqB}N$wY2)R%kI z(vGa@)T!)F+BS(aX@|rosK3E`Bg#}p8U5trql~^mtTVKKVqMaH$ZkWIP+EsNccu+) zqdo&!TLY|HSr_bc8?)VmveJ(UjK`AtsbVf;iQiD&lsRxC^lzyduN``UX1imM8J$`_EnWw%R zC?n&doNG)ac_fsu-Ps-^lv@RLPi(=MYGt3tIJ%#FRn8R|gUpiv>83LN6YVh}lPC46 zq<;j)i+2|NL>at`>4T1>QAoLH8zGJOSJOT>)5bMOi#R2;r~5(9C%rQ2<73{H!hhKQ z+cn~sbH7@ju`rXkFEf@%yR<#w*HLfE>L*`6eNowj@-MOH4|&rD{`+W0`n{aKsqj(n z{1= zB#q!0T1DRc4U_w6?(gjJUyC-T?-T5Gg!4*iH?KYBpJd8&UIk-0sV4UacDZ%pHROEe za~bQBZwBLXApJnw`RPMHb0?uS?OhZauL1rW9Dy_i+R{%yB&1P))|S$C%nR~Pq>Ntb zT>dKKpY+@T)?V7y&%Xaj%EG;I#dPA%=lZ~!U186+<{ZDDXFk$QSWmmoBt6!DKYz=c z_%m~!@!}>d!NEAEPG06*Ib*DhdX>+oJ*bD5zX`73x1|7mRZ96PDT|LjN}yh)^kF6K zm~@i+dEW1&Qf@DE-p!oxay-Cw#D6RGqwjo_x%6YgSbHmWhw7ZbzRwP0KZ);Dl(U^+ zj{)AxCf-|hJq>oq|EB-(&I{dN+u3BUemdBLQ-cP(tS%k}l*^%uJ>6OH$(IQlCUu+oBN-oOR zKDCTE6-eTk|DyQzabNfxFZn0BtJ))#{iJ_aCi~?7E{Fa^u70ekT? z;;yiSyU+}27>v=Ff#ukM4{;DDAyl)3YPcPB&>CGa5W_GLbFdt*V<-0GBpg>-!i}hn zw&;UG%*1kR!CoB3S?E_;!cC}+4(NvhJccK+0&id+j^S@uS6hr>OQ?sA=z}~=!n4?p z&u|>)am6*%1@+Mu-OwL}7?0UlicRDtXonuiMG0nN307kxc49BS!6_&=S;95A2aVAd{V)pi zunL>82gh+9SKiE+#XV?*_UMZN7>{SL79Zkk1fczk^Kc99M`NTQ9r+lIX_$|tSc|vt zJ}Pk<(k+ZLT!$KHjx=Oq1g2p=UchF2jL-2M0^r4ikbvuOHyYw0Jc@MWVFadO0hVDk zUdKB)fWrvjcgVMr9iTERwSVrx*->1 zF$+tu60c$_KEyZp4e_@#j!++|$iN6p!%}R(E_{aXZ~}kAaR=)J67c|dvO4jIF7#{-E9e1;a<4W4SAS^#aM;c;m3RU6o+sMaraolzi>b5!HtgS zj%*ZR66Rqoc3>Zl;tb?_sT=M_W3)kU6krUdVJ?581fIfjyo$|u51-&WoWgl1_cMQREp91@Dt9%tZoT+pb0u72ajP9)?*8H;Q+peRD=9b z6D`mMgD@7eumZ2)1AL8B5NonN;sLZmR}92BEWm2)Km`utEUrqjga+t^(U^x9@Bt3t z4_LLhX5$g$Vg_EsP8`Hpn6;@NlF$rYkbxph#bT_59~C%+Q;4g>nvCjbk6g^gE7*x+ z_#3y@r5(@*qp=XLVK=_PX*lcAW_SRN@i4q7#1uS*dWqEXFFlfnC^-Z*Uy{AfX}G8#I6$ z?a>+O7>;RJfVFrF@8WX=AU;U`s0lYx(HFTGg=tuXRoIUG_z8|ioQHc*2QAPUeJ}{) z@Dx_Tk5BPE&f$v2tfy##RP@1M498?VgLQZhmG})-6WSR~@dz^U7*=2t4&W@brj!e{ z(H`j-iP?A&eteFTsMd@zh+0cmU1N4TCTa3$O+|@il&f zl}uh}fiB3wILyH+?8K)yhBL6*aBV?zc#w~AcmgZ21s~ubPC#tSy%uVqHM(Ii#$Yy< zV>9;Qd;EpChv*AbM@w`^F2>_2tie0@27jPhJ4?6^t>MKOEW|o|fI|r2ZISK!CzI1NWA3hwwM5b)k)rjP4kW$FLNe@i|VxnMT^EiPq?eY)rsHyomMKfzNOhzr)p) zv4(rm5be+tc^He?cn)i@1$$75Um!n9AL4e@Mk}OYAckW)mY^K(;xqh!bBOQ8dVuO^ ziS8JLQJ8`!u>!B-9qh+p{0Xx=*CMn)FAT;AOvW>K1MlH$oWMC)Jt!yYAq4|44o~9+ zY{e%yj^Cj4r0sDVYQc>TNJAeCKoO?l8Iequ>rgA6@I`UF#0g>Q4`7NfjpF;6w9z4 zJMkI5#~;x8GAD2!8X*N<6k;Nt#B+EJJMk$F;t+nq83-QoM*?oZ?Wlz&aHBoCARRfF zfcaRBH?R}?a0ox+JQBS04eFp7I-(b{Fdk3ib$o!Ya1v@d_gtupj_3;?CSnQ7u@n37 zEl%Pb%zm^T>Y@cYp&tq`9y75RFQ6P7u^XS_Tl|dQp=2-)a3k(UZ8SrB^v4)Hh1GZ$ z2XPKJWO7e|p2)#Clwv8?Vh29MkN69&EXEpYAsM}qi^*7o*HD1~wEoP0+>6F|7`-tR z)A1Z$!^b!bVF35zXo~I_h!L29XYdMk;4}PyzhDkzokVpsMJm!!h$&ctb$AC~;sm5@ z)^6N`#^??orlSm-u^*>#$R8uPIR+i?H^2!ol^xE&4g5PBdNV=x0{cnMpu z2S;!kt{m_#Pi!9Td6fI6ZbvM>(w@fJQpCB#CWn^7Ij z(G^251xv6JZ(|>hLoA}L@c=ra4{|XD%ds8%@I8KqUd%lT8lXMWk&o$k9-D9gr(q1G z50Q)>7>0$|hzfjF(}1Kyn#<} z5`W{W5tJMC&<NVm4M{J$7Orj^I41jbdD& z2~sft#h8kvSc6U2izE0G#%R_DREHanAOj=u1eRk1KEy$s#|>ks6CS|;j6x}v;|;uv z&v6pUSmGlI?cl|5%)tt5!Us5rv(U%!&K(WV1zGT6JZ7T|>+m+d!cm;YKd4s1xoC+# zD8ytufrVI$9oUa!_#Ib`XMI5pv_?-1Knb40T5LlF4&o%@CU8waEwn%<^hE(C;wh}f zPJD%vkRM}?;2yL^CMIAmp2ut0iVv_Khwvl*gkvJ*#Jy;UmPkW3iZKpz@giQsPJE1S za01dK#yhUXO}HDi;6?{@ffqR#iSd|)MOcju@Z%#Kz%iV_UvN%lF5@mF;X$-TXY@k> z9>Xk@VI^M2ZhVLHxOxiZK?>3_45fGp@8B@xsgxf{Xp4Rri|JT`HQ0uaa2V%dO=FEl zV|2kl6k;+K;$>{d9(;#Cp+8O=p*Gs0AI4%4-oOVqh+p8GPWotuo*0JNcnR;~J2+;r z1|S&&F&V3|8^7S%nao%8!B{+lo%jjXEaoLrFa%FvJwC%iY=#CtW!veg3ckww+z`2kyi#lkH-WZIrD8&kF z#7FoRXA!rEv4{KcARa<@48%}O!aS^kA7A57T>CWVpc%TM0MoGq<#->5aTe-g+8Z^{ z5@{HKp?D0l@jPC`yZ9QvLRrH5Jlu(TXo*y$V+3Yn4R+!S9L2AYo?)FtbtIz?3Q&Ss zcn0gR8$aT2R9i~<&<0)yNkcFX`g2i|lo3R%GSj!lraHA{o zFb#`Qj`wjGzvIehDF@o28}cv?Gw~c=!8`aC=Wxw)jAJxM2lPY^M&k)A$E)}V$DuyY zbq-DNFnYj;@tBP=l*5lbIEvp9znuArX6TN5JcdPBjV<^X-{Lf^6`aUah!v-lJwz5cNAd;%J334;5~eSpP;_LSVw(4j2;+-k(i4Yu@#@-IFuLZGqgZ& z6k`(R<8|!AA)LTpsJ4o08Qkz}*0+|?&=~#vB_!?(my~H&eEzt`@ z@dQ?38@|NvxcX({p$R&pA4X$7mSZD6$Ip<~@cf4wXo^&LQH;m26zlOmKF3L%hiffk z26gcW@-Z3DVhcXUDLBh{_Cq7|#8AvZIX=WOIM-1I)WSpPiYydkA{OBVyoEhDj5GKf zSG~eD6SdI{ZP5)wF&*>pGB#rujzN5t>kJy92Zmw_mS7dOU@v~e--ut&H5YZ!30WA0 z=~#hn_zXYe3>>e~2dIt~NJAgwV?37NEqsR4xcYUjm1v9pcpNM73jElEZ}1D0H;9k> z&;*^}K{2LdF;-wB_TV_gH>m>>Q439xf*g#&JiLsZ_#6QU8(5oB1Fg{oSt!EeD8oin z-~dj-c#FA&B(%UI@W6+Wn1ESWiZ$?K7Y^VU&LD0heTqapfMj&X5RAoiEX4D84cqWB zzCr-vCf0h~gC^(%FN!b|&tpB_#pgJR-(YNJOrRl>(H;F!gvnTna_qpD_yK?8x-FCw z&CwOP7>{{aj`esCUmyU-+sqr>iH2y8N0EsFOu~Gu#3oeWAOaBmtS7h^jnDzTkcSe? z#tOWN_i+F};T+7Zv#-N#;RMb@-$^-9 z9nH}Z-H?F-jKbqsgqQIacHtZRj6Y$#Ls?NBZls|fhGHV-Vi{h=4(!7b{DOaAyvuk% zO(df?3h_9W;Z1yuuW=gcd#ro77Z0K%`l1-quoy36E55)fi0?B$a3|`Z6?z~ClQ0L% z@hZ0B3;c+GaLosthvw*lY>dY|yoe2W4`1N~ln*H%?!$xVfW8=n;h2ntScQ$Kz+wCX zWf$ud?m|9oLz+5cHTiAuK@iX{iJpSEau7_xXPDn>SCSVR$;5F>Tr#OZ`VeDr8 zK@GG*Hw?m9%)lb7#2eU#y*P?LpngpIAQ83D3O$g6sdx%6VKY9#kN5*|6@fm)Bu!lK_+ff_I$UqUsVHOr+HMXDv2XP#yA@8MrxDofG86HL-_%IgJu>@LmZ5gYIkj^TG$`?!vyHd>)82B8RJ@HpmRF`mOZ zY{zFfiE~i*vo_;jxEJ-%5}nWs1K>jmrehwK;bm;ZhxinSZ~}iI?o+N)sE!6mMhB$9 zg8>+Vv6zI}Sb(KijaTs&KENmV5=U_oXW{sae#5P(jn;VIxka1k{6d%bL-^a3rg~TP zdFNJV6SdNLhoY*7v?rX&#t+Wdly`JlU9Y^MoY5vKh0fcwj_M?3vNA>a$@QLgvn~sY zz<g=W_2v-Q>Tw`3-gx>KVI!`)RI;Xjw zab77bbjE2ewXgBDw#>OmTko8z99F!>Rl<{U9i^^vwJ=xi6<<%Ouap_fj3vf3!nMMD z*LLSFU01IYt`{08_p1k8vz^Iml0Mxz#JEAY%eqmxNw`_~m$20Q#k@sG6mAv1*U#y7 z^s}x{v>AG9G>n*T>)NdfYYLl_Ttur<%j9eew)TH$Re9^AowVxxv~k`_)`wo0_NO30u|K z<{9%F^DVQ#*~`4rGOa|@u->qinRlA4t?p)P^Aqz+bEG-lOjGiOe8ndW5q>tZl>z*p zG!Ie=ghHX1|0AgH<)Ol@%2L;GVT3SJ7$uArj>}_&TxF~>VquB!jIdOwZGEGZ3Co0Mg=6x|`s>Pb!glF-VTZI_SRt$wRv0hvZ(Y17ykM*{ z-ZYo%A30WPyBrTGZIxllaAkxtQt`x}RDV!c2_uZv!b`%-!boG3F~%5Y6dNT*p0P$S zoThWQ;WLIB1;#>Sw2^BR8N-ZIs%l7ab#*art#H3qF6>m-39kq_YK}`#zSP$XKg!1) zuL*^&AugY*!1a^d%t%mP7v2!Q(vCXb6!O$})w}c!Lbgj(^3}J5jr{Xln}p567U69{ zQgr7KwLtX?D~+u}uDVUga}9RoyH3d0>Dz@p+7ZVN!KW6g2eh5SJHi>~Zmqlek@HHu zz^TRQhAYk)H%WKI^>)^C)OFN%G;mZ1dxX70e`~I@zq6lnpWt!s7d{nsI5VA#ou3Jx z3kQTs?F->c;Va>g`i=UvdQe^Bs#FKMzEU65POJOXed_1xea0&7fcmAn&f2SfqJE|} z)xJ;@jT`hKW@GCbGuL!jUzs;qH(0k@W6hRkzWJ!t&Dv_NH)iYb`HyY1dpPRC_%Y05tw3eI8t$WN;tB?7$`I~vI^_1DzywhrD z9yU{~>&)ur5-ZDWYZjQP)*I#oGu`T8zH5HxN;VJbQ}wO-dA-o|>0f9MTfOyHtWJ6Z ztwOukxLvpO!TJ?iZL_nLZCKhZW^L_W>ke&zVd|swp=L{clb)yTca1kTxhCrGXyvXh zdMoW^*G|`3*JrNBtjDdlTyMI%SlhL?^-5Q|_POf~*ZZzUW=Ct6Yq`s5Y}6#}AMI}4 zr9bc5=<2I~;#%i=&6Qys)7HD*b-nI#n{A9$uGz*k<3Zy|O)?s4d-Y#jCv>m&p}Ezy z#`U=Iu(sEAt@gflgBfQgX#=!OtEZl&H?`VXr(C~lCrrP-Q175M)<)|O={sC6xSn&( zHLtREyZkPPS*SJA54bkC_PAbkt+5W6+gu;I_UV~gzOhyxu0N-5cJ(kmcD>^2r+uis z=Ms!eeW2zu-?YBde{eN0zj2+@mKzO~uZ4rcFX}f!rSPqANcc|p!EukaQ$8#l5snJS zgyX{Z!Vkh%t{?gTp!-?)R(-;%V7I3--^m@h9@H=EUr>B?#0jPRRq zR`^}`(J|4OU_560Z2ln>XnzWS3Fm}0#(CjENb$y^WQjS>(@lBM!ti<>`;u|YX6<^$~@q&1-CW`%ZNt8uJbck`H zQ}k%6_^0j?dmEZKOxMLb3_~qY%q;}89D zt&8!9u|jXIZPpTuntDeuMeHP|ijRmTt_iM*uJNwNT%E-(Vw(7i+*Nd$SDW+9#l|Az zg!+?uTn(sCXg{mR)bG?E)g$Urb%yebHdE;-rfR*!9OocsZ*j15v))G>=*)KZ6+PlX z$A0}QM+c>oGE#qCOI03GIxAfiub3{ntbSsKm?<8Xv&8=50CAw0Ee;X~iyfUgVy-w# zxkmrX^}Fk8y}RDj(2NAFtF}`=sVT;C?TG7;-dnrhxKHb**Ejm;4;jUJALBP_*twL*s;YK!09OjnCEp)aGlV{**pW zt7ELw=j)lqUB+&GlQv%aOrNGV)?d|XX;&M6xN7LN^k?+?`W!7^e^giXxq2_Hnl@SA zsh!eI?QU(lUfW33kLd&TN40r+XMK@AM$0j7)MeudeT4pr-c`THc))m2zgat~-()qIev8&JMzSQ(I*ZOi^ZYhFmbpzLL4c6q&=pO5=V<; z#IfQyalH7pbAs5~Gsj5`(gfpeBvDz0$8V9gfih);_1#JcKyv60o+y3U%dJSF}f=WrIOf5nwJ7l@0* z-<>A2SFv*PpO73u(Uxwt}nUwuZ4 zb3Cmp4$BeH4aW&3pj_qn$l`m@n&Z53 zjpH}vPo<~!wQGvjM*mAWr??!w)iUjr@{4k<W+jP9h3EmDe=p~`AGTkU3S5?5L!N^PY~UTlq5mdbBSG~jWhJKslYR4|^q;j`o zuhLQ5qwIC8(JLIEIvQ#F9Py^x`oheydYY!W%=+H=!8mUGXdE_vGP)}Z)Q`mqahICz z+N16feac>OsB4K@qJJXp6JOMNC?Bc&#jBJnl`E91m1@eb;%V`W_?!5vd{%tTJZ9Fg zzBiMtan^jZleOL|v!1pVSO?8C>ztWn^|Wp@e;5A{Ps@Lb8EScaUv+@mhyTP^6lR($ z&F0o~=7VMvE5($pr_Eo@^X9GQXls?Z(5z!>rfz*|Hn3*#pMuRW*O@)6JFI`qpUkFa zeY1~s*1Xx8Xm+*cTVAV$^^p0f`GVQZoM%02J!5V#hnvObB2%&6HVdrh&B4}q^DeWV zHQ1bB^|q>8>1L(*x4FuCmj58{h#6w5EBv&39tK52ez)-?N>eNCtNjP<_x zlG)L$W*s-1oBuKgSrz6^)3OGcYpsXPTGj`qW!`W7X|6S=Sy!4@SgJM2eA(P<{%+QB zKfib~KVtiv-)*f zTjNUY9(}FWU8|?vpw%!Q)^F9T8%wmC^ey^9ZIU)YE7YIWe$c+vI~W=IVZB&;R^OqI z*U!5SYpskd<7Okx=%9P`ar$rCEd5>m3rAz)b4Q*t*LhI+R3G4MsXeL8Rpu%Aaq;>G z+I;0HWr4C^S*R>ha^rq+1$j;`@PI~3{B_=TE7>K0$BPEcm4v(*>X$CNl}o;pW;TwSd>rRnMu z>Llk1t-`t4`G@(DnPI8YUz$tOq+1MK+NfWl8rtt* zvzyeg+A`k@`v=$t$HxmeEhjkTRt#slPNp z8YpE;Mb1aGK~hcagln+$FFi-fmCBvv=5yB5>JzRr@^A84`FHsb`C(#Ip+0Nn%Tu{WA-+?nlD)^ z%pK-b?N+syI$XM5o#7lIjgzV*HiKWxkSp+GF+YF z$4e8W$E1nUBx$m=#Cga$MVcy2lOC6*OUs=zq?ytz=?SS+nk~(do|NWF^Q3*+ZRXRi zSDo{v&GJ*y5p9Zf(#$sRGbfwF%xUH=R$a5Lb=q7YopimgFO*XBDQdBEk@U2*SXv@I zBQ2H6q-D}|jdWuvr7s$o899kxWrW@(GmQYo~q)_&2;^-8_H{ z*EMPxmh!eVK=(^qrEStqsh3jZ8s-}1n(Ta6YNfmhac~qIEu2gnAV(b)AT zpnN5LEq(3y)>T{o+4Zs3$!KqM(~i0p=rgqs^}DpcwT61GR#P46xWzHlp*kE6({Y94 zM#oK#Z=_1;Tj`MWope|_A{~{ENynw{r5~iB>R9!5$8T}J#{Cj^Hm*Y1Lm3isk)<<n-aYFYbH0B-Es?glk;omE6xWUE#=#+Qu7J(CUcb8#`2qjRb=(jf7IVnwkoQ2hrUc7 ztTizH(cQ+C#(Mod{cC-#(n@YEf9ZHb`%8aZ-=WRb{-v$c-qc!akLV+`cDktjq@U3b zI)^)Mb`&|B4%wkQ;vLsJZg8}b+sY5g?d10I!*amvAa|5g>a*muUKVW{Y98mTt+m*d? zed{A-oAP-4P%0uI3 z$xq0W<4WbCxY_c%isW!wyOmFr8?6?tS|xYs;%S}SrB&y4scG#xrFi-mWMv7L3C}LN zTxed_Frh`4lvtxG|;cm>RBQOiiL;(E>+9 zstVPqQ-|ahDbdzSPU+e)xpRxOIQ&>dr54fOsm-I;Zym0tMMGJ>U3-(ZQi`L1VV|pPR5RK5TMZNGj7me$x16A!( z6&A_1Dx@mKl(giw6T_aLjC%1{t zhEB0ZqOEd4XtZfA2#v`*Hi>8nVgoN%4Zono!Ds|}`iCb|IP%5Gv!8Uqi3E81jqs$jYkf)Z ze^?v)oY;d^mymF-Ot!9RZ5m#XVoc|TTF?%t8U<v?cLCQ*C2kEUnuR3&Ba#WZ;E%xDV+_o&%`th}s(^qlOGS(!!Ix#3Zf)+04JX5a^R zqr)z;=iw6W$a<8mv=HIMsxl7; z#PnX|oM@B91YA_IHVrSWKI1nWSe0osD4Or1?YgwP-12#0cqD}jL!*hXo_X@KGd;Qa znZ-Hb0TsL>bW${IXq`v^!=~S$tc>v4*|jsPvaoj|Sy0Se4|#@8i|ob34IjVg zgqVVb&WSAH!97;A3zM{$xZr)eeKC$ip%^i_5+&NS!59~vaAE8V>tmPkl1k;V*x8{m zd0d!*FFkVe7|gFQdq7@H+~T~8jt|W$$nHNP6eG7^Xp(p`@_iQv(Jhg%P!D(tS#?6^ z*-2h7ihbz?h0$YddNPY6cUnw}-0Y(4p;<9aR}~hmim$lHla(KSaIkk`yS*@Lh^ML= z_FinYs%l)6KA?8=xyIh1dZ7~2w7wkfqpCVI8dB9k(V%E^M?<3J3}t*lEXm8Vsw z6xNUy++%eKHT|W*oPTLxFokw)d0euuR4v={s; zUXY$w#4~dAppRw9eh`TU6lB>~mCL6zEH-v#R=?r_o=DMy31ki^NYC};<>z_&bN`j& z$tozwF9;p6N3NZRJ%l|O{i?QEYog)VOiLb#FWSE#dMJv$;Dln4*ueDcyx?AcPrvlS zton5$JH`F`XN9uw@5#va4UF#OW`?8Wv9fxKBCXZmlUJM*YXAPUKu&ggKh|zLpZ=Mb ztrfwA1M`b>>_(6D3afjjCwONRJkeg*A{!pMIk;o@RjB(th4~qSc}BLQ*r69RXKa8c zy&%*{cA&k4+Bdk7vqH-w7mrNtAtQkU^SP>IhuX2Y9y|Q)UArTE>Di&~ zvIDq&<=Iy#yE^uMaBM~Q`iFYZKF~iq+)2TmP<`#qT-N=5#r>nF#I&?MkwW42IIr4D z3T+nW_RA^=PJ!5cdkPh0h1w=BIG;jCgPWl@c%$o`OkVJlyPg z9~pnq;T8<6nmhJx?C7)it5zv{uPDRkVI1b9hZd>AyqLzYyTB89s0)_C4yalsg2(N< zqfi0ugO^)Og3&ISc%lCFWOG9tnq}btdyWUwv*&qCVTT4UB6cZ;#uRbr1qBXwbBd>B zhjuBg?RSCx7@@uk#SZ6f z$0#gH4>cKYv|62+vnJAMkNbG)iF zFNu>ioJkpT4*QqHq4h3^!~P|4a*G*OG3l^>Nu0v`9B#>m6x)kROw_92OV1c`VT}rh z6kIM&u!V!|MU!}l#04a#E$l|C9S-Q&DJ3n~UBO#TiV+QnbXqhZ(p}MjaGyo@85wp( zV)s2c_7y8wzs||6QiC}~5{?E$5{?Fh6OQhO6ApL2{j@YJzaW@szwEr){a9sFJpI_P zuk69C%&d&?*1*s-<7logI}{e2+1%L#6A0cq+2NskDErPex)Uj={kq5wv~R}wCh>5d z;Q_@L>wiWtlD!=%oc)|d{P2*9q}IP6KbI%HyrKd5xmotjS&C;sMzAc=M=$%{JUEXo z3<=LyW>AtRFPr5l7|&Dd!P>z@E()$)yY6L!>(#$paGi#ija{#Ht#Itn%EWbu;<5lm z>PY*B8za(-+4l9QDEOj+xa>u16WI>eBf8r^y^w3AeG^(0pL@bkU^w#Nf_yIUgYBEL z6i-g!!0i6P=%KA(8SQs&cFw^f+T%VvT*8~ovuqyHINJ^g_eprOcCbHUj$L-&Ud<^} zxNE|v24hBBBN7-H4UzrAY#x1rJ!*#pS6`mh!eyzdjeRh-Mpe5PmOd2c!m#jyV<%y+ zH5U%BNGRpX_7&uF-Hv3=;t;bLY*RaOVKFz|p{8QwAGso(9odd%p6@HlrmyUH!HactBlsjh zU}08qX1*t~2E^>zVFQ9a6FF#q$An(cfCbTU7}^SsL;Ly|UPkQAysQD~_M^95275nv zfe#kV-itI>xEsRFZZ~=K$guR_D#F{e;O`Grzi-(oMnc2Ca@av!PJ%5|9A37H!-)<} z&neFGFpGqiUE6p%CU*=!k%o5$6y$UDkJ$;`dPReR9m-*D7=!B?n>^XaZ02O7Gkik9 zIT`j+8QRXXcOnbXKV?qj;mcesJ=4AJ)+KS$H@&w-|^cZU27*_4^NEzG- zuIj-pR>fM;x8nBuwCn+)r;W%_d(85v5IWCZLkoFgVVuSUgns4=o{-Hz=Vf4Uu?^kr zT@oCM5js6Kdhm(rlGw$C1)=A_OO6Cb#)Zk)WAie(+QAp5latTgOE5)yi-8|*q~Knp zk-}B62WBv8Ow}$-Eqvh8Y(fWkgyAZ~Q&CJRgxOEc7lc$5Dso<^IQC=D1rdw$s-gzp zpLue)u7={+g^2#h5qwmw3J<+6ZPmGhr**q7X`a+hRd0AM4zx$`Me%||v~!QtG+yg) zFB2M`q5bgVj{WSLTSj~P;uC{mcJka7hLg9e5ow9& zLuKs2aDl=<#QxhTnc+G_o=q>8jGg{S?xMbk3GxIl?YX>(Vwtxm^93i- z)&GON_YSkFy8gxwLsO#!6brV1BBDV(y`Os-m;pxGFf$<7hG7bf49qZvqDIAF!Nk}= zC9#VNMiU{#7Bv~roN^Zott{_*~vFVAzBvp;+7zW3T| zt-a2^p`k^cc9T4KM=|pR>d@3RpRtU%v#BBiNw@JZ+7&I6%pTk{S2Sr7 zotY_AE=6`%CyFbYBXvl@^rGA-f?ASHI>?8V4L=A;dX|WyUQSPR9*R_su)|pvWcw7t zFqh7ayO0PNK$gQS5eW<-MitCV0}?!_I&oew>CmAJcpx7^GT|_wHbOEBF${)#ZJ4UP zG2JeNTcIctPY^Sw1>EhbVcd%^3wUMLU9 z#f*&3^ymefYkFYC11d4h>oXa`JdVA}Y8zURRtPoK&ldq^;1vj3F?Jmt zsWc1cQ7^|?ENY&wsSJQ=1qZ#@eUi|^x^@-_ZJbQjWxE$;z>NI#!i7loMzRaN(0~;5 z9*4;~ALl`IB%XmC6yR~UPG%%5UszM1x={&yH2Fz@Kv{IyU^PcMsR9VdB%?}2)?A42 zR7f~l<)h2S#mj&NNb%@`DVL@)1Bx^_#-sTn0?E{5Xpw5icq+M2ZxCQYMXQsC;`NyX zsiSx(TBE5Dt*jUbrz8&-ZxV{62%%C5l4=y-;;jlJ(m52gi>)MH5w@1%Y6>eWipJXF zuW|h=$5)b(o$-`#UBNV20MgCeacEGikr@nc|GX9)(|WfC9@W*j2DJPt5U9EUK9a>SEy zCY#1P8X>uh5O;m1m7a!iz6u$Ro#&;<>sy=Z>N_*}*4B5mL&zbkbvl;_7b;7WjKhps zq%v=4oSo_bqJ^;-i#A0D-q%?-zja`HZE9`L)Qh?Sg5&&j zLek)i<~pYit%E@#;tsHx2}8$cM{R3Uk{e%};n33RftOyfMpIPOM`GWJxX^dqR)JO- z^Yu*+B*De97jYr`1WpeP;o+Vx4m`naKi$_v5=}YySA_ZiXRfsj2xm3DhjW@dm9GL$g;|e{ejy#iWhvXbX07!=nSBUA_K}{%wU>LaUkSV6sA5+jdcXlW}a#fQ5Lj^K-deD zo+F@0$1%8|-{Orkl3QqrHZ?cGF(Tp>%%H*y_-FtR-~@+F6lxMj_=!z4%pu0vT^I-_ z1`jpNYDv4I?>uyphXPeJj`pI4w>nh?^&Q5Mf;tEK*q-z6yEX-4Y2I z(HTmnZTx^XDGPkGj(j_rHz4ETJbU0^PHcT9#PjOrLR(}t6F}~5!8r_1OlJGIH^ZsM zV{j^-tr4pr+56)Z9H9fY420APM04PO)SX25U%RtgBB48pCNlnlMW@G49Gjmc%wz~d zdqMBRK2fBnf%1N(p`X>&+|t<`j!=hGURF_AT2(V6QOr^ZbgWdEjmf036_d*OT8LkX z?=(TKVD6&j9LDwl+esJ*?TB%39!{M)Aec4QcXcv9rHGC!Bf>kr&PehgcQAw_N4tT@r65x)m_QpkZ?QsvX zN_Ne{30PFR!0Xx@XX6wGPIbvrOQ2*O#F)6qM6d{{xV&OgVQs}&iq*s@nP7`lior!n zBfMzk!ia8?6s;sBDOOR!yRR%~hw&6jHH7xa7HGlI2&5u2oFR_uF2im!E69j!*-??S z11J5-LP?)cQ0%=hoF)+aiU@=*qF}0L2*}i*LD_A9fyK4~iU=99*n)^hr&|)E=?X`1 zwq*idJVCalQG!g1Be+OIqo~Y~2(8L&^*pBdPQ&8ZP7}{Af->6&LEUTBHn!bP}w*Zg?WCj%>j$uJ41IIL;7D7iSO0=Y1z0-Bo4 z0-hOaAtp1@k>*uZ#SV^`D{ZKa0^<4<_pdESm`7vu$>To@)MDEJ4XIAyq`@>G05;;n zl(fYoJHCtZ&SumhP8I>AjYBwvC*iFCO6tmF24Y{y!D~d$zI)(xhf7C$9bD|9sBjYx z^W`lQY6J4ZsLR3-@J=eov~v9DYDF!M zTZJ$!twNNop+b0SMIkobkez8-al8<%XL48}E;ggBu`zOBrzx2PlL?=}k{Qn;NE+r- zl+Ec3mdPa{W)VVGIHiU@JFl*NF3*Opmf+d)`3cS%19U3RDl1}S8m9)(2V?B39SY$r z8()JIt{{9HgBbXM6k!12(RQ*hi5c_7%f4Bmd`hMjR`GT_HuS&-?->BPjq>e|}EK}pAP zJtBiGBwI6mL!QZ;^qk@`OrlQbGN1O>G{pQHkx3S(Uhl4g6xV&Z6bqGseJCar#_Wxl zcI*ICEUox(6!awPF}h;~Ui?C~@V72(e(}m>TF)v%3xR4TX33gfSQ0l*Qt$CETv#R8 z>ll~^p_Ro^EX)qiVyJ??Q%NW&m?oIYKb|0xG8_^#G>+mrR~$|X;qh^fJeW>T%qW#0 z2BK1tiZC&kD4Zb?a}G@lR4MiU92f@6~Ul@Nt) zI3m;>O`I?h+2@i3G*y$85|XeF98zdziGi+-mPkCK0kAKN!<=Kha#VRZ+vDCMsIFx; zH%Ou)6c!mI?b5bdi30^zPkKQJSSDCItG#tDot{x1bo>C0p}@$EuZ0Vt=!S~oF%T@e zNz;ih_mVUn{Mj7arT98ureMaM)@73MXgli({@tc}rr z!bYou9cRWT;Ykjdk(ov?B-@C1y0P5i30Do*m}I$6W8cXqVN8+e(_E@C1-XX9iWg^L z1N>2m1b;beZ>(?VfRzmp27!OMO9AQ!zUhZwu0|lwHv_gU!YLQ5CcMMuHK;7Zc@28_ z*9iY6`D2AQ)FK&|0$Fr>a~oXf6;oy*TEOXSJLd3u;xDf{Ug&EHsu{iFLy7Q}zL5xD z4Fz?XUQ><>hRWE9-_+{Tv7zr*5uEm-LTVb|@D?fNB^LVSry(Rw1KCvk;8modZ`f1e zf+S4fjA^Q;j;g6D4{IMKj6fl;2%_x9O)MSF{!6iGLK(ogC=2n~#9kRsi{FSjvp~r8 z$5)LqYD+7t%BPH)ToxWDXE4+ygHTlxhjg(zO#%F>OSdO)l1vC#B(v>wsiQJx7l#A3eSrml80(#b{zEN)!WeLHLR@)3^wU z(nMh~32g~UF`ytoNI=1up6;0%ogAvMnk872Dna6eH5JIWMkpu*q9kE3p&y^^@0t*a zQ-onkGGQ{l0Y=2cGL@cMKKJO2O+9)ECmX#+E~gXAbWrOtwH{IHwKb5|JD4j95yWW? z&>Jzm5z!kddLyD|{RBHh`eup(6!k8^s8N%ciQ<@wNpKD1@1b2W3elYn^c_eTNkQm~ zJj6ycdFAR44-+fqU&z!phSUT_AIT&{Aur_s8Dc_eW|K(@X2G~%R`c?j>d~dRM2S8r zs*SH0<8>+?N1aeSCY51z<#;ffbVeK#GvG)zVMXmMQ-@iZ-7ppx23j70?TW4*OGgxx zRKa#K9KMhym!{3spn|QMGzn+FX^d@5#qwi9RGKz)t(!C%%cZ;uSKRUX#X+h<9H91- zDTqxjY~e{D+Q8#jI3?nEBO%~nTu;#62^X}O4AUeDFisywp|J4WGKRRxfh8aTBD~{< zqH!Em*Iqw|MTPIQDNvMHHIft=#>MyKHO#An#gc~!MYYUVN$;drs!aUe+@QA1=P+JT zi}<~R!+_$H^iHxY<qjQu=z+G z!#*?&Z~0*~ArK`AgDLvzn$nu7p_~+_2|+Pk2qkH&CPWts@nkFWR|?JBO}_d*Z924fT=Z5BraY7MdH$(nI#Z< zGl~*AhgG?tbND{MCM41@!C7o*b>%30h9b^(Vlf;`@{SN8_v*?-01R^vAu$=FNu^3H z5h@FSm;%8RJ!G0tYlur>keG%6g{e|apEh|s{IKW-F|qjxn&g*YahBEPRnxEyPM91D z1gt6o7$p{&p7*a_egMLB*ouA)gIlSwY%*?BHRC0!tZ zg|j^!S+tO1?4vMQiiH%9PS5-zG{WQ;Vw3)h`y=ka@PaLTFy4ln1K{eJ#6ToqexO~Q ztxdS}i^Lb&F34-Vp7WD>y5lDc;x3~4#sZX1I=UbsBsnm7N(hI-6hkOu`cf_~lmR>s zvMKO<7)TC^;SSHgm=wzA06uDMZfNdY5+)*3mPpgyA}*(Tc)^7SI&nGl$sWl*RCl~% zIAwB*Y>g2ZkGkNt6BFUG0o*Sa5{8w7WeI0NU2r>O`Goh+Q9mNHkVXKN+N5(+uu$~~ zhle9|CW(er#Rv{-AJX#KEGu1IJ9Vr-i8yZi3fbCWwJc z<^W41R)EjH=*sChBbt=dkqV!8NtP@ko1*|G)1(8J_o3cQH)Hum0K4-ljYN~2jDh?T z0y$M}j9+cX!g?H0@VQx8J_(-z;%j)g4N!xHFqyz&fFy46Sb_z)72?~RdF;xvrk{$R z-%8G|F$I&vad}Eq1VuK_j)Tp0np$7iM&FSpSO>o zmNJEbrHbh(oC(H3;v{i^El&O&WLYyR#$Rbhv!+Jg8Cg8?&42-2g;Q{8XjMsqC?p9` zAqb@jd5F{TcTP6GY)m@K1YpETkkR9?ojEwLk)osbIK<{kjPU!-(!rRbI=0*r0fm^2 zBMOAJ3JTJ>I=`PYE-($nc_uI`I>u+w(Jrwke&GaV3L8Z7Z88Vua^}PWt+jJNjgNpR zgk@AqcGK`km^ONb)6F>iOoXW7%CT}_mapV4kK>_XNAYB>udSRqitO_u#?0p(36%c6 zEQJ@zl-%hvdB*xSDIu}xBFTtOSgdr=&ID^={+h;Y!*PRI%d$lkYbFguk{uhC(y7xk z2&-CUX+>2QubPlSAY3L0S#09ILxB3USRKNsg02biY?l+oOV@kqjaFobYsvK5VCb{m?dLTr%{3}chw3xQ${iU*FeqOlj71JFa15v991zh2u;3 ze;s2Y%8qk{iDMmOMaR2HY-Y@3if+f9QDn!Sf!#GaGY5#a$UKPQVsjyhOwETFPR|Ju z=JSF()zKx`)um&g+>?O7u~DUCLtS44GVx4+;PiCXmgxCmnix#d#ZW5k_;T8tP-ay8 z#8N=jx8_2D7E!3pAjZ|1iT~nh-MPY~+yx*xN zvvAS+Vzx;aVo>E`QtbHfI0+MmP7AdiLLHc(8^)tk;UpNhn#3mZJAnKYcQ#>S>!Pfg z6+X-+>0x#`epD*ii(?90%R;yAM-CDq-o`GvM}yJEC;=)=wGjI`f`slB1`@ArbVpT~ zG0U^At8-4OBN^IeF~>uZu+2if(kNZEACb($_n+iI6ajQ{B6J(+9=HP_>BsQ;`hwy^ zJY9hp%v6CZo?^B%{AxHCqN)&v;ZMN^bJ>X&5f9OXi`NiAq#@L@)9~tXr3%Z=sBN3o z2=`kYwouDiPzWtlS-z>9tlH9=nku>&hW!Q@B?}?^=19dDcAm?@vWl@}osDOo1yzzE z;pBVs(d5yv zTWmDT!($R&a~fYDab96K$%g?|1@#c&bmEY+2X2j!eZr1DPSBzI!5#M$8g z-!TvOyTX9L=D5X`cou^jT?CBQS#uLkpVDZ^X?Z$!*(x>#zFsm|sGG7C!8kk=W>|&r zg&gnG2*U@=yk_b0nVk#TEK5(7!7{+L!WlvW6M#D@ zBw?<`vx10z8vpH*Fg|p93q#Dolh-7!H0QY%yP1KLiA>%SmoGLGSeeLzhs&NgZM5e! z&q~@)SZHaa%RF&^0xt0o=vfYh-A2g@`-h?FF^{K9GC?rqWM&ztZSABVhTxS0nhZ`< zV**1r@`NfJ1tDGNx0aA(Yc1x-+~Y!0bWfB`G-Xml5?&*dna81>lJcTLfl;yvL`t8q+nKuEXZm= zSI5ps&S=jJSQ05I6EZ33(k39#p6Vc3yDoK61s_tf1byJv_9D< z3gP`p4CJmobek&+;y(M9@Qq*WEaZ$|w`qspb-FlQp412#mL+Ca%Y<)XQQ_qQX;3Ub zG`BMXt`SqMCH$^z`NT5v?2O++r>rE*xM>nh9J&%LG?hZ|l9=#C|AqOmSC$2POH#97 zl92pG0pU-QkOEOsdKakSQcBc@DNrL2Q{z2V6j3J0$qg0B@h3@6fhak>C)DJr3TpgG zs3{Op(|f8g0+QrOqBupGJf@wzX7MERwisrdH3T}z?S<3wkqsmH zEa#J*ZZM=vp(Oq>8Iy6@YNU^#=_B_n&X!Xa#LSj!>*;WQHx|3*SR^xtS$SN#+b-ND>}yAyw^LLp=AzQ(xX2H#%&L^1!Z z1p3_ee^8Mw_D$nY)|YW~{!v{w^=5n_^` zm*; zZV_Sv$BPy>FRfso#I_E;$1V-yY=nT+js(dLY=G<?TsCYU^>%v4B_!1lKBn3J=4fFJLOkwm9!_;OhYIT$;zAXt<1{aF>Z}d} z&@7`@CR-8AObc)^i++5`<~_mjJRX;&1e00^zJ91ScTbN)wi;G>0;kPQawngca104F?LtP{{aw zO!_qrp#=-DYT$?BsdMY4sq}{VRWH#YKCX^|b*`3v{D;;Z`6(8| z`A-Q63CLrkSb_*INC09nV@eB=wXP!zW@|u%B(h}biWR_rAs#2iB5`Ee6DprAgTl;@ zLZG38Um=LD%LKCt=+h-3K|%c(kWGZ`2qr}#83X7`L;-_KG-l2G2nt<2=^!QiX|9kK zU4?r`l4?-bVgH`rP}fesC5RIivIoUIPSN})gp%|eVB9z=E+%7WZ8ATS2%!xL*o7al zZjUlyJND>Q-|O264B1ZVlXwxAw!E>Sz9_`?BptDNv9lmkex6I!3;Iq7FY=(IaabjO)FUl zqMmXX#tC-CsHru$<$}3(bD{)fazOzpL!*y-iYAFZbLcjbzW2*SV%y6?LM!7sVSHr1 zooCXs2z(?+zm#1pik&lMBI0g}vroDzhR|L3?K}FB@l0wKA(qHonBY5_%nE**K~Pjw zOcR$BBgu^B$;jO_n-#-Sc`+o(47OS^4FzLz3M7=^-OR9?^fIw?2E{2NAe9P>RSvZ) z&by+0Ao&=R^;EPwkkvT`==+H{5bCxmg7EM#p^4@NWtXlit<_Z85J=5UN+#g+(OI0g zfXAQR6hsP3L(D7U^sMn>ho$;T98**z#ivU$-PkV7 zjwC9a4dKy0>+U2HzjvB&xDaNliAcu|>{0+-(k245LBT_ZZ?sXh$PSdE$~LBBPFH6` z>!NT*F@XZEMpgLPioz|SXly)1ipIv9f)E?eAOTCJkO0ygN(L z&2%o~kePf5W43_8)}*4+t)VD7fGnOUibkJjgU2Q^8a7s=hb!M zRt8q5Fe%i3{8E}YFwCPQ85kCfn;-ftOqyI)F37~8zqzns@=sxCE99kx;b;wn!6aMe z>rJ|5L|#=n8DAh{QlQ9`Ml3Z;Z1rigIY2iDdU+>z{j0#02APvI;%>(Sx~gq>Q< zr&uPi_k_w}T<5r{q>N^GdkjV06$5dHg(_@#%^RzA3Zi;Xswm^_DTu+?cM}sY{4h;c zC95sOV|9_m@egD%{o|khi7OW}4zl|urHgEX@{UCVyLcBa!wv? zDp_0{YEDVRQjk0ZGlQE-KykwO7R06Hv#7FB#;G}wP8*BnQJQ36IiWDP9H8E(QwR9G z!q!nnp0DAoNaDFbHi`evIg5oSuE1a^6ct48aUuN7g)Zk!@yY~Fx-`MiO#EIK-9gA} zl8tG_4|d^_%UG~W#pA>BIdyQ1;kB&656iIoE|4cIJ?uO7B2nF@p`T!C$L7aB3n|Q# zTfd9t7+!YV*oLcpi=_*_CyGa*|H31OqVa9$0NgVR|2T9+Hupr7P5PzCc(ir3x51Q) zVqhbV$1d(K%nEohwYP*zH_3`c6dfFzNOaDWtq{YDjR{3WcZ_A)$)k$&9YwINEmlfo z11^#oH^CQ)2>YQ}cAan;FN!A{XsTbLqYK=uohgWIxp4W0Z4p0mEku%>o9#1(;lw3F z*3#NKHxgobvDvjl>>(?YaZ2V`NuMCm5>E|jW@ey!mBOVb3=|^qb&XiJqC-VsL6;L) zq`L_gWRjYysr)`4UI-7SxCe)bONbX&rtn@&5fd!P0EKa^kDB3MT-a1T5HZilrtP*( zlrA+b3sNSGpfD=o1*tgx!y~C_TPTDuq`i@>8Y$}v!`Zyc!iliKOe=!%n}?HbW!JLP zDH!i5!2y6DAhQ1B@-cqNN(iw{GSoe~k)K1D?;v7YVXee!I$q*kH0ek}lTcRR66Nq% z24_;Wu(Ie17Ph$g?KHwSBdj%1bV@}{mIGrKToT3o6P-AU;0*zu65v_5wZ0=X-O}QS z4j`#d;Xc_Ic3(kMY-B1H14GHexWsgpi4ChDA@iaynle&yQiY~AM9K^R)}ts}a5Us- zVSsuy*4G3qmRJQWEvZHk0(*_1STZG`!0bz)s23z*@y=>CuoP7&kTR582n7Z*dmc?P z$p0ttz7ESx<_f#ih-F(Cm6%|J>J}uREvHr>4ZD&)nB;dU@sfEsS)Xi6W-|y<7W0mC zM%)e@ju@pBmkNao*8@Wf)&rp_g_=H33rmVVI}_)UsFo))KZPb!zoVMVQW4dhfjLj_~AhNYA95J7q0o0X(tza5@&w)F2}3Cbh5<7i!e5c=tyzvtzqA@&*#!5tqG;rCRfmfJ*bP)D7$#(?PHpDl@<~%C zmRFV5l$Rw~xmm?abmoai!=`)56-(-LJBeEI}X9^ zh+Mi8V)}K3FtoU~9!?vabTNET>iIhjV*Q-f=6d}68h&b`9_f<^{$tv05LH+@TFhD6 zS-3m_6J-&8+qy$SpaH+5lLW|JZ*d!TKZ@dSD!t;Djnl~ph?8|JXcq!qv%&!C&&O|6 z1+K2*!xLlC_{Bgt=#TMbzO0bEQVfG0$dGdtv zQX!o%hhn1eCk85xEibFVM`KALVMI35apk3D2a#cmm41TV_$37E-yI^oSz^HK< zXJvA$4ngeBYw_b-Mo69`6=Nz!gKMx;po;Qpj>FTStO5oE_Jijf!|jFOHPHmu0bA>NP_fh83Ke!M^_f55ggbT0O@qm zk6a{VxIiSG5dgXsklL00If?}0KQ1AJ`AxAhtUAiee-b=2w*qG;|qx66AMrCt-9k9R#KTx?NfX!YiTEP~2UtWPZDInu4xs z77=#NkS;8_L^&bE?B*9Hi%@jqFUO+0J6R~cWHSme(^nXXugc_M+@FB&muVE}yI_2o zOgBx5;plQJ5eu)H5}{}fgt>$ZfPZToJ5uk!=VuZNl z@)rT5ZiJ+j)P@24W|j;Z->D+tVheH02VddTK)VS0$l@Y-`nrm^gzU8xVtLuPRCZ~? zI4X0=1TQDPMnVWi7esKVyE_$xSnhqm0e(9i>r?JL5Z8tWqw2&QmM4pYF~b!)F-nu# zHrUrNEHQfvS8(FG&Z0;YieI=}Y$nL(HdDmuGk4|)E0Ew0P-+W{k9;&U2)ht8A;R(% z2ykUx5``T(UfeuKAW{FsK-gLqj(ydVTw+M5dAv`sM9kBL`D7)j$X!GTC8NYrM7u~7 z$W#;2>1q-nRx>f=nJ` zkw_W?p~xJELm3SUQGs$1V@W2^C<~Pdx^a#vnu0QsV6ifhK%p`b1F4FKd1aM}m^iIW z#Biug#NkAlNFcEHu~0Z-fGHDkDDIg^Z5EY@m@3vBl5Aoq?#nO-QYPYri87Huq$MRG zQYPY1R&_`sLe)V4V$~tW(yBuYb2Whli>e9f7_KG|R;UvYT1+Qkct$56EUOc6EYS(V zaHvPHZpi8cj3lKK6d;U$6rx}N5g0S~5QubwbWqGE61S5~nA{&G2z3GqB{~5QRgM=_ zfDlS_f)I#zBv!+e_)k16OGW&UV`9Y<4IoLAsWyIx1L9cC493G*4uv`a!6}^}3skeR z6D1%MWU@V_;S`ZhkU~hl$^z+hu}%<^MLK~9&_)x7X#ujItxKR#Cx}VHpO<3jV_a=masuR!14jHLDXOG)yOmgP~3kha;Up1ei`B0Fh3R zf|yQ_LLj)L!b~R+kVGelK|v=-uvjM$pjanhSgaFJDA5VR5Z4KKAkhg}nCk?|E7u8x zaI6yuSfmpOP_zaTogj*|SRXL$AiNh-05Hp{W>oUo$w`33IzgO8BBLizp-zy*;g>|m z2&D)rLP8U&2pJ$$5z=U};>89t6(LF@s0bDGS+hu(jSCq|R)gp!NyLY;(?n)sq z&Q!9DLK0UxjiRZ` zB$9bZnzDd5tDQX4ShQVOL{MLt-SpD{`Wyb3>>kYU)_!*HTMItwVZY5S(OWD1zGUXtf zd)GXIsFwT>pBVIx3lj*#!CLr-&b-0*+FQ8x&BDPbuYHw#p=WFiSQ{Qs4ItKaAsSGCv2{iIjk>?hqRU_P)< zfxRzatAP!EtDiJsTatD&uw}qH1?-+r`boC{n~wC+zZZdB_;x?3O~A(etDm$6Sa<*W zztc||j%OsE=wBt?kH@nZ&xLrdz_SL=op>I@^CF)2@kIZ=!F#WF`$+@w48}78&qzF# zcxK{h!*ed4EAVWGXjr|rwmUep5yT};Az8iDxP!ktiW>( zo?GzTiDx68r}4ak=Y2fe@kk${Kk)2>XDFT#cx*gnc%pxmcyGXS2A(Sf{1&`##IqUC z`*^;?v+GC53(sIYG9Dk#1U$#%X~ENp=Ttnu#dA5HYw)bWa~qy}@NC5MG@du`e2gdh z_rLSzf9K8r*LicURED2UoQ>OA8r#e1a^&jPu68)0+|i?|5G|FY2Y{1L6{AIXS7}sp z=O|oignvV%(d^sf(R4d)XY;I)JY`J1ESFQ7cK>yGJ$iR*BO0kV+dGN;_NU zA$FKFnl23*2e%VkrYuRfNpP+SBiFNc7BAh--p4ezcXW=ywaYBuzcXwS+?qJ_yfg;; z{eJVSnpE3@ zo3!T=K2pMWV)UDj5|d@6`4X4EDQ>7#Tieir``Q{8<6{R&k`bOai~PRvQzj5sS|$9Z z3!D@w?sAFz_U5-zx(}q<=GIw~^b!7c)U$g^q}e@c+rn4$D+yz$Flu>kkJ^PD^Kn`- zzq5(b?pabdiv+O)OCX;%OVZ&byznDRn&NiJB~9#dDx%j)n$X4$$u4Q4tEnWXq$$qK z#XDW_P0 z9d0GUzspJ>s^YUCdcT~#^Lnjf?@%c4?+@&q*YQev4{LKZy|p3O;lK{UnN;iiyV=6Iq?GL@4qY>CZhTV)fR|ZXDH$ z)h0>%NXJx{j;8g~GKzfsa81Q%QX>a3oZn?ib=a4}$W~wp(t(7fmzwkohSB}MP+suw zV2S@2F})9!W|8(K9U`%*+JWNOU=NevemI}*@sXs%B+RQhtsR}S*pE+1M^P9}Sr~@d znI5HV#cvehpC--eY@OdC>Fh7&xzyZR-`Nu9?MQTs6CW>En%~(vr$zGE-wr8|@T(@6 z!8!JqesctKUZNk8m83HEx09{cF?jD3${Z`j7h_1{q_`+aB6&W1O3S8|R#s^0k!5g| z!@q&R|0mDbGD-xlf;7XC=Kt0+9+$$EPl$_>e3bQ5&piAdB+WCsT-~(f|JYf1wBZOVUi#b7y%ES&=8m*U1~@=j7d$!OAG5 zQaMk#Ub$KMt8%yUfbxX$g7S*;uJWn!t@5MNNA0gFYN`63YG{VOLI21YVc+b`a36Kg z@$UBy3@#2H3697izDXZoOf?=dT=RJIIBTo- zTOWiVK7;7xJLI1$^~%{w9;v=m_tDPKcGgGhf774Q-_<|XD~(HyD~(%?=Z#*bZ_YPg zH}|qmw^msvI1SFPo#oC(r@yziCwr!MlJ|+>7)@8=;zN#CLT!{r)zuG}WCl|PlgluMOq%3|eFrH9%_9j5+L z9j{iZeYAyIjlM`)McA6{94d!O^Gqaa9 z)GD(YtfkgP)@o~`^|sZ^9%AcujooRlu-Dle?YHe-&QPb+sc|};70w3d8Ru=Mmpjxg zbL-qrcZIvb-Ryqm_VR{$WnP1~)LY?g@HTtfy#fAEzszs&m-*NF8~n}wc7I@?1f@Yu z&>5@&MQ%fGbMCWTul&$_S-v5^G=EY4+Wfk_R4HMPz`lZc z@T&Z-yk7Z6=~OqNCBHCdTPy6xZPO`nr@2qN1HDVU|9DIN>-}EA$HDyEn%uhF+4+0& zU*~_wBZHZeM6&4_@^bkSd6Ke0`9iruJzATk{Z@NWdsZvaFVMH?IpcO?KXb0R#@yAa zu-dH^)@#-X`)Kdvj0a-pq~7ze;7aNzyg= z(_cPNK1^v=mMd3cPVS|SRcqDd>RR<-b({LR+EY7R8;{vGU)!z?(tn{JrBBi4=sk@x z<7nep<5c4kLo$!X>{)K!Xg-87ded~QIoA2sCD!%UdG=AxRnA}0;(_jguHs(qj`!wx z?cQ15z1~aS+uqmSe!lJ3`Yry2{y+VnqrWEwTZ1QZzr#GD#?!tmN$v8^>TvZg^+mN= z`;B&(K2E<*|GWO0zLOyvn~c3t-Urrl`!MH9XO+9$GyPqIRl$C_^K&Oq9v4bd4gPGx ziaba;UTIQJQ|?tBLT?UI4_9^dc(p-2Sv^zzoq82oyg}WlZdN~3f1xkX|Dr#t_c3zD zbH>BwH)grD7&GpV*1nh})M@)8&uz+g%3f-jdb$0my~P>rKI47tLGgo(B}t#D3(N)f zS@yO5-IzzW<)!;2i3Ef5<@NFoZD`OXPglU`Q<~H+7)9~K&UiKSZP z$tm-dv(zut)3h?ZLO)I~F~%6z8m}0m%(Kk9%qPr)+-CQ4*YUpd4)Did?(QCJ494W1 zL|=cBmp&!^iTKV%%4qcy^(pO3tx8{_U!%LmJ;n(0Uh_a}ruA!khkc@Ry!)zqn)hq3 z$)D>#6MTa_kWlIYnNgAkfoCk&UeP|&jt779j49^*=56*cXBVRB&uMytyQ<1WWubDJ zGC)1mxG$*8O#>(Dm(S;=!966Brw*1E$v1%y4_8KMQ?-MPu||Von)T-S7|-v`eXU4BvVU&xX%Dl<*~i%(_SyE|?T_p}&cV)M?n&+@ca^uv z>+k!)Uvj1S=kk)w>(eMVE31?y^=kDM^--hByv5uHd}^w-iu!nD52-)3OCRX{K>WFq zhu?R1&TXLhnLNBw-osiOU}d)PJm1#V=zm80M`4X0WSUlBdG;uKjbphvS2}~Ic}r1^ zp42ZF_F(hwO8qQzv^CM1XFXsa<6Iv|*YsfXzsbDRoB{r@!Rn70w$dK%ob5d140ETu zXS#=Y$9i4fTJK?RFW>WT^w;~(`~UK%1+#)1f|r8Ba^<=6a!=&;${&)Sm)}bDy{(7z zHvUw|P4X@BTk4t^fCHf`t$m(#vtQRqrzBaY%@MHdYF5f zhnR+0YECg5%`S7Pxzb#1zHEMA_O=Pu^OxsWgMYu2|D5yR`_aEW zV26-@Ascd;JXxMD&yg3)m&$A8yX6<{}Q3EB$NyKlyk1FZe(ByP*flv1ff1?3&v>cTn!=Tr0-$hTJ1qtxxBk$DaL0 z?%mwSxzBT7<-W@uk{^?=%uhpaH04|J3-hOS|>Ogg{ zIzl~Gou#&`OVn%CC)Ibq-a4>ELP zrZLBO)cB|ImhmC@*&*gsbGF$6uJDxkocWIViTQ)s+u9Y9!Ex3p)-vll^xHeucB_wl zh5c9iPN%;+)opeE>VDw$%iH<7{MGpz^S9=|%70JodZULlowdu9=gHT|zf@L%bM32D zpgwE0t(u~*(g$HJ+tzk_oU_ci+xfte-TCef?q1%0UWHfb&Gb(4uks)Bw_xA-I_St< znR_@l0K5=u81rY4yh`3pv6W-7-+0(*u22VQS7{$$CtalvHBCr2Q_z}Pvkjxa%KW2w zhxwBEKBSzTtv#)M(V`=*aaOan$U4_rZ{1^UvA(qS#4b^8SJ~6-nKtb(H`ou`@7iD5 zB~Blwzca)!oT*NibE$KKv);MgxgYY+ht4<7KzERPhZ#!M;DexF?tq+{87?Bv`9xs|yabNA=|i8=Op?wj1s`9t$TeggXb%>4P7 zQ~!kg@gMYliS$1DeizKC{p3UBg_uc?$h{Q@`&g%Psj^yG2f6w0%0D1655rzvs+Oyh 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�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

vzSOwr$JF8yftkS%wjj+^HfQnO2H+? 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 literal 0 HcmV?d00001 diff --git a/license.txt b/license.txt new file mode 100644 index 000000000..3844dfb42 --- /dev/null +++ b/license.txt @@ -0,0 +1,19 @@ +Copyright (c) 2009 Satoshi Nakamoto + +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. diff --git a/main.cpp b/main.cpp new file mode 100644 index 000000000..97000db38 --- /dev/null +++ b/main.cpp @@ -0,0 +1,2692 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" +#include "sha.h" + + + + + +// +// Global state +// + +CCriticalSection cs_main; + +map mapTransactions; +CCriticalSection cs_mapTransactions; +unsigned int nTransactionsUpdated = 0; +map mapNextTx; + +map mapBlockIndex; +const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); +CBlockIndex* pindexGenesisBlock = NULL; +int nBestHeight = -1; +uint256 hashBestChain = 0; +CBlockIndex* pindexBest = NULL; + +map mapOrphanBlocks; +multimap mapOrphanBlocksByPrev; + +map mapOrphanTransactions; +multimap mapOrphanTransactionsByPrev; + +map mapWallet; +vector > vWalletUpdated; +CCriticalSection cs_mapWallet; + +map, CPrivKey> mapKeys; +map > mapPubKeys; +CCriticalSection cs_mapKeys; +CKey keyUser; + +string strSetDataDir; +int nDropMessagesTest = 0; + +// Settings +int fGenerateBitcoins; +int64 nTransactionFee = 0; +CAddress addrIncoming; + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// mapKeys +// + +bool AddKey(const CKey& key) +{ + CRITICAL_BLOCK(cs_mapKeys) + { + mapKeys[key.GetPubKey()] = key.GetPrivKey(); + mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey(); + } + return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey()); +} + +vector GenerateNewKey() +{ + CKey key; + key.MakeNewKey(); + if (!AddKey(key)) + throw runtime_error("GenerateNewKey() : AddKey failed\n"); + return key.GetPubKey(); +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// mapWallet +// + +bool AddToWallet(const CWalletTx& wtxIn) +{ + uint256 hash = wtxIn.GetHash(); + CRITICAL_BLOCK(cs_mapWallet) + { + // Inserts only if not already there, returns tx inserted or tx found + pair::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); + CWalletTx& wtx = (*ret.first).second; + bool fInsertedNew = ret.second; + if (fInsertedNew) + wtx.nTimeReceived = GetAdjustedTime(); + + //// debug print + printf("AddToWallet %s %s\n", wtxIn.GetHash().ToString().substr(0,6).c_str(), fInsertedNew ? "new" : "update"); + + if (!fInsertedNew) + { + // Merge + bool fUpdated = false; + if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock) + { + wtx.hashBlock = wtxIn.hashBlock; + fUpdated = true; + } + if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex)) + { + wtx.vMerkleBranch = wtxIn.vMerkleBranch; + wtx.nIndex = wtxIn.nIndex; + fUpdated = true; + } + if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) + { + wtx.fFromMe = wtxIn.fFromMe; + fUpdated = true; + } + if (wtxIn.fSpent && wtxIn.fSpent != wtx.fSpent) + { + wtx.fSpent = wtxIn.fSpent; + fUpdated = true; + } + if (!fUpdated) + return true; + } + + // Write to disk + if (!wtx.WriteToDisk()) + return false; + + // Notify UI + vWalletUpdated.push_back(make_pair(hash, fInsertedNew)); + } + + // Refresh UI + MainFrameRepaint(); + return true; +} + +bool AddToWalletIfMine(const CTransaction& tx, const CBlock* pblock) +{ + if (tx.IsMine() || mapWallet.count(tx.GetHash())) + { + CWalletTx wtx(tx); + // Get merkle branch if transaction was found in a block + if (pblock) + wtx.SetMerkleBranch(pblock); + return AddToWallet(wtx); + } + return true; +} + +bool EraseFromWallet(uint256 hash) +{ + CRITICAL_BLOCK(cs_mapWallet) + { + if (mapWallet.erase(hash)) + CWalletDB().EraseTx(hash); + } + return true; +} + + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// mapOrphanTransactions +// + +void AddOrphanTx(const CDataStream& vMsg) +{ + CTransaction tx; + CDataStream(vMsg) >> tx; + uint256 hash = tx.GetHash(); + if (mapOrphanTransactions.count(hash)) + return; + CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg); + foreach(const CTxIn& txin, tx.vin) + mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); +} + +void EraseOrphanTx(uint256 hash) +{ + if (!mapOrphanTransactions.count(hash)) + return; + const CDataStream* pvMsg = mapOrphanTransactions[hash]; + CTransaction tx; + CDataStream(*pvMsg) >> tx; + foreach(const CTxIn& txin, tx.vin) + { + for (multimap::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash); + mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);) + { + if ((*mi).second == pvMsg) + mapOrphanTransactionsByPrev.erase(mi++); + else + mi++; + } + } + delete pvMsg; + mapOrphanTransactions.erase(hash); +} + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CTransaction +// + +bool CTxIn::IsMine() const +{ + CRITICAL_BLOCK(cs_mapWallet) + { + map::iterator mi = mapWallet.find(prevout.hash); + if (mi != mapWallet.end()) + { + const CWalletTx& prev = (*mi).second; + if (prevout.n < prev.vout.size()) + if (prev.vout[prevout.n].IsMine()) + return true; + } + } + return false; +} + +int64 CTxIn::GetDebit() const +{ + CRITICAL_BLOCK(cs_mapWallet) + { + map::iterator mi = mapWallet.find(prevout.hash); + if (mi != mapWallet.end()) + { + const CWalletTx& prev = (*mi).second; + if (prevout.n < prev.vout.size()) + if (prev.vout[prevout.n].IsMine()) + return prev.vout[prevout.n].nValue; + } + } + return 0; +} + +int64 CWalletTx::GetTxTime() const +{ + if (!fTimeReceivedIsTxTime && hashBlock != 0) + { + // If we did not receive the transaction directly, we rely on the block's + // time to figure out when it happened. We use the median over a range + // of blocks to try to filter out inaccurate block times. + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex) + return pindex->GetMedianTime(); + } + } + return nTimeReceived; +} + + + + + + +int CMerkleTx::SetMerkleBranch(const CBlock* pblock) +{ + if (fClient) + { + if (hashBlock == 0) + return 0; + } + else + { + CBlock blockTmp; + if (pblock == NULL) + { + // Load the block this tx is in + CTxIndex txindex; + if (!CTxDB("r").ReadTxIndex(GetHash(), txindex)) + return 0; + if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, true)) + return 0; + pblock = &blockTmp; + } + + // Update the tx's hashBlock + hashBlock = pblock->GetHash(); + + // Locate the transaction + for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++) + if (pblock->vtx[nIndex] == *(CTransaction*)this) + break; + if (nIndex == pblock->vtx.size()) + { + vMerkleBranch.clear(); + nIndex = -1; + printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n"); + return 0; + } + + // Fill in merkle branch + vMerkleBranch = pblock->GetMerkleBranch(nIndex); + } + + // Is the tx in a block that's in the main chain + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !pindex->IsInMainChain()) + return 0; + + return pindexBest->nHeight - pindex->nHeight + 1; +} + + + +void CWalletTx::AddSupportingTransactions(CTxDB& txdb) +{ + vtxPrev.clear(); + + const int COPY_DEPTH = 3; + if (SetMerkleBranch() < COPY_DEPTH) + { + vector vWorkQueue; + foreach(const CTxIn& txin, vin) + vWorkQueue.push_back(txin.prevout.hash); + + // This critsect is OK because txdb is already open + CRITICAL_BLOCK(cs_mapWallet) + { + map mapWalletPrev; + set setAlreadyDone; + for (int i = 0; i < vWorkQueue.size(); i++) + { + uint256 hash = vWorkQueue[i]; + if (setAlreadyDone.count(hash)) + continue; + setAlreadyDone.insert(hash); + + CMerkleTx tx; + if (mapWallet.count(hash)) + { + tx = mapWallet[hash]; + foreach(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev) + mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev; + } + else if (mapWalletPrev.count(hash)) + { + tx = *mapWalletPrev[hash]; + } + else if (!fClient && txdb.ReadDiskTx(hash, tx)) + { + ; + } + else + { + printf("ERROR: AddSupportingTransactions() : unsupported transaction\n"); + continue; + } + + int nDepth = tx.SetMerkleBranch(); + vtxPrev.push_back(tx); + + if (nDepth < COPY_DEPTH) + foreach(const CTxIn& txin, tx.vin) + vWorkQueue.push_back(txin.prevout.hash); + } + } + } + + reverse(vtxPrev.begin(), vtxPrev.end()); +} + + + + + + + + + + + +bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs) +{ + if (pfMissingInputs) + *pfMissingInputs = false; + + // Coinbase is only valid in a block, not as a loose transaction + if (IsCoinBase()) + return error("AcceptTransaction() : coinbase as individual tx"); + + if (!CheckTransaction()) + return error("AcceptTransaction() : CheckTransaction failed"); + + // Do we already have it? + uint256 hash = GetHash(); + CRITICAL_BLOCK(cs_mapTransactions) + if (mapTransactions.count(hash)) + return false; + if (fCheckInputs) + if (txdb.ContainsTx(hash)) + return false; + + // Check for conflicts with in-memory transactions + CTransaction* ptxOld = NULL; + for (int i = 0; i < vin.size(); i++) + { + COutPoint outpoint = vin[i].prevout; + if (mapNextTx.count(outpoint)) + { + // Allow replacing with a newer version of the same transaction + if (i != 0) + return false; + ptxOld = mapNextTx[outpoint].ptx; + if (!IsNewerThan(*ptxOld)) + return false; + for (int i = 0; i < vin.size(); i++) + { + COutPoint outpoint = vin[i].prevout; + if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld) + return false; + } + break; + } + } + + // Check against previous transactions + map mapUnused; + int64 nFees = 0; + if (fCheckInputs && !ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), 0, nFees, false, false)) + { + if (pfMissingInputs) + *pfMissingInputs = true; + return error("AcceptTransaction() : ConnectInputs failed %s", hash.ToString().substr(0,6).c_str()); + } + + // Store transaction in memory + CRITICAL_BLOCK(cs_mapTransactions) + { + if (ptxOld) + { + printf("mapTransaction.erase(%s) replacing with new version\n", ptxOld->GetHash().ToString().c_str()); + mapTransactions.erase(ptxOld->GetHash()); + } + AddToMemoryPool(); + } + + ///// are we sure this is ok when loading transactions or restoring block txes + // If updated, erase old tx from wallet + if (ptxOld) + EraseFromWallet(ptxOld->GetHash()); + + printf("AcceptTransaction(): accepted %s\n", hash.ToString().substr(0,6).c_str()); + return true; +} + + +bool CTransaction::AddToMemoryPool() +{ + // Add to memory pool without checking anything. Don't call this directly, + // call AcceptTransaction to properly check the transaction first. + CRITICAL_BLOCK(cs_mapTransactions) + { + uint256 hash = GetHash(); + mapTransactions[hash] = *this; + for (int i = 0; i < vin.size(); i++) + mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i); + nTransactionsUpdated++; + } + return true; +} + + +bool CTransaction::RemoveFromMemoryPool() +{ + // Remove transaction from memory pool + CRITICAL_BLOCK(cs_mapTransactions) + { + foreach(const CTxIn& txin, vin) + mapNextTx.erase(txin.prevout); + mapTransactions.erase(GetHash()); + nTransactionsUpdated++; + } + return true; +} + + + + + + +int CMerkleTx::GetDepthInMainChain() const +{ + if (hashBlock == 0 || nIndex == -1) + return 0; + + // Find the block it claims to be in + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !pindex->IsInMainChain()) + return 0; + + // Make sure the merkle branch connects to this block + if (!fMerkleVerified) + { + if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot) + return 0; + fMerkleVerified = true; + } + + return pindexBest->nHeight - pindex->nHeight + 1; +} + + +int CMerkleTx::GetBlocksToMaturity() const +{ + if (!IsCoinBase()) + return 0; + return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain()); +} + + +bool CMerkleTx::AcceptTransaction(CTxDB& txdb, bool fCheckInputs) +{ + if (fClient) + { + if (!IsInMainChain() && !ClientConnectInputs()) + return false; + return CTransaction::AcceptTransaction(txdb, false); + } + else + { + return CTransaction::AcceptTransaction(txdb, fCheckInputs); + } +} + + + +bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) +{ + CRITICAL_BLOCK(cs_mapTransactions) + { + foreach(CMerkleTx& tx, vtxPrev) + { + if (!tx.IsCoinBase()) + { + uint256 hash = tx.GetHash(); + if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash)) + tx.AcceptTransaction(txdb, fCheckInputs); + } + } + if (!IsCoinBase()) + return AcceptTransaction(txdb, fCheckInputs); + } + return true; +} + +void ReacceptWalletTransactions() +{ + // Reaccept any txes of ours that aren't already in a block + CTxDB txdb("r"); + CRITICAL_BLOCK(cs_mapWallet) + { + foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) + { + CWalletTx& wtx = item.second; + if (!wtx.IsCoinBase() && !txdb.ContainsTx(wtx.GetHash())) + wtx.AcceptWalletTransaction(txdb, false); + } + } +} + + +void CWalletTx::RelayWalletTransaction(CTxDB& txdb) +{ + foreach(const CMerkleTx& tx, vtxPrev) + { + if (!tx.IsCoinBase()) + { + uint256 hash = tx.GetHash(); + if (!txdb.ContainsTx(hash)) + RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx); + } + } + if (!IsCoinBase()) + { + uint256 hash = GetHash(); + if (!txdb.ContainsTx(hash)) + { + printf("Relaying wtx %s\n", hash.ToString().substr(0,6).c_str()); + RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this); + } + } +} + +void RelayWalletTransactions() +{ + static int64 nLastTime; + if (GetTime() - nLastTime < 10 * 60) + return; + nLastTime = GetTime(); + + // Rebroadcast any of our txes that aren't in a block yet + printf("RelayWalletTransactions()\n"); + CTxDB txdb("r"); + CRITICAL_BLOCK(cs_mapWallet) + { + // Sort them in chronological order + multimap mapSorted; + foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) + { + CWalletTx& wtx = item.second; + mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); + } + foreach(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) + { + CWalletTx& wtx = *item.second; + wtx.RelayWalletTransaction(txdb); + } + } +} + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CBlock and CBlockIndex +// + +bool CBlock::ReadFromDisk(const CBlockIndex* pblockindex, bool fReadTransactions) +{ + return ReadFromDisk(pblockindex->nFile, pblockindex->nBlockPos, fReadTransactions); +} + +uint256 GetOrphanRoot(const CBlock* pblock) +{ + // Work back to the first block in the orphan chain + while (mapOrphanBlocks.count(pblock->hashPrevBlock)) + pblock = mapOrphanBlocks[pblock->hashPrevBlock]; + return pblock->GetHash(); +} + +int64 CBlock::GetBlockValue(int64 nFees) const +{ + int64 nSubsidy = 50 * COIN; + + // Subsidy is cut in half every 4 years + nSubsidy >>= (nBestHeight / 210000); + + return nSubsidy + nFees; +} + +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast) +{ + const unsigned int nTargetTimespan = 14 * 24 * 60 * 60; // two weeks + const unsigned int nTargetSpacing = 10 * 60; + const unsigned int nInterval = nTargetTimespan / nTargetSpacing; + + // Genesis block + if (pindexLast == NULL) + return bnProofOfWorkLimit.GetCompact(); + + // Only change once per interval + if ((pindexLast->nHeight+1) % nInterval != 0) + return pindexLast->nBits; + + // Go back by what we want to be 14 days worth of blocks + const CBlockIndex* pindexFirst = pindexLast; + for (int i = 0; pindexFirst && i < nInterval-1; i++) + pindexFirst = pindexFirst->pprev; + assert(pindexFirst); + + // Limit adjustment step + unsigned int nActualTimespan = pindexLast->nTime - pindexFirst->nTime; + printf(" nActualTimespan = %d before bounds\n", nActualTimespan); + if (nActualTimespan < nTargetTimespan/4) + nActualTimespan = nTargetTimespan/4; + if (nActualTimespan > nTargetTimespan*4) + nActualTimespan = nTargetTimespan*4; + + // Retarget + CBigNum bnNew; + bnNew.SetCompact(pindexLast->nBits); + bnNew *= nActualTimespan; + bnNew /= nTargetTimespan; + + if (bnNew > bnProofOfWorkLimit) + bnNew = bnProofOfWorkLimit; + + /// debug print + printf("\n\n\nGetNextWorkRequired RETARGET *****\n"); + printf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan); + printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str()); + printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str()); + + return bnNew.GetCompact(); +} + + + + + + + + + +bool CTransaction::DisconnectInputs(CTxDB& txdb) +{ + // Relinquish previous transactions' spent pointers + if (!IsCoinBase()) + { + foreach(const CTxIn& txin, vin) + { + COutPoint prevout = txin.prevout; + + // Get prev txindex from disk + CTxIndex txindex; + if (!txdb.ReadTxIndex(prevout.hash, txindex)) + return error("DisconnectInputs() : ReadTxIndex failed"); + + if (prevout.n >= txindex.vSpent.size()) + return error("DisconnectInputs() : prevout.n out of range"); + + // Mark outpoint as not spent + txindex.vSpent[prevout.n].SetNull(); + + // Write back + txdb.UpdateTxIndex(prevout.hash, txindex); + } + } + + // Remove transaction from index + if (!txdb.EraseTxIndex(*this)) + return error("DisconnectInputs() : EraseTxPos failed"); + + return true; +} + + +bool CTransaction::ConnectInputs(CTxDB& txdb, map& mapTestPool, CDiskTxPos posThisTx, int nHeight, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee) +{ + // Take over previous transactions' spent pointers + if (!IsCoinBase()) + { + int64 nValueIn = 0; + for (int i = 0; i < vin.size(); i++) + { + COutPoint prevout = vin[i].prevout; + + // Read txindex + CTxIndex txindex; + bool fFound = true; + if (fMiner && mapTestPool.count(prevout.hash)) + { + // Get txindex from current proposed changes + txindex = mapTestPool[prevout.hash]; + } + else + { + // Read txindex from txdb + fFound = txdb.ReadTxIndex(prevout.hash, txindex); + } + if (!fFound && (fBlock || fMiner)) + return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str()); + + // Read txPrev + CTransaction txPrev; + if (!fFound || txindex.pos == CDiskTxPos(1,1,1)) + { + // Get prev tx from single transactions in memory + CRITICAL_BLOCK(cs_mapTransactions) + { + if (!mapTransactions.count(prevout.hash)) + return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str()); + txPrev = mapTransactions[prevout.hash]; + } + if (!fFound) + txindex.vSpent.resize(txPrev.vout.size()); + } + else + { + // Get prev tx from disk + if (!txPrev.ReadFromDisk(txindex.pos)) + return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str()); + } + + if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) + return error("ConnectInputs() : %s prevout.n out of range %d %d %d", GetHash().ToString().substr(0,6).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size()); + + // If prev is coinbase, check that it's matured + if (txPrev.IsCoinBase()) + for (CBlockIndex* pindex = pindexBest; pindex && nBestHeight - pindex->nHeight < COINBASE_MATURITY-1; pindex = pindex->pprev) + if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) + return error("ConnectInputs() : tried to spend coinbase at depth %d", nBestHeight - pindex->nHeight); + + // Verify signature + if (!VerifySignature(txPrev, *this, i)) + return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,6).c_str()); + + // Check for conflicts + if (!txindex.vSpent[prevout.n].IsNull()) + return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,6).c_str(), txindex.vSpent[prevout.n].ToString().c_str()); + + // Mark outpoints as spent + txindex.vSpent[prevout.n] = posThisTx; + + // Write back + if (fBlock) + txdb.UpdateTxIndex(prevout.hash, txindex); + else if (fMiner) + mapTestPool[prevout.hash] = txindex; + + nValueIn += txPrev.vout[prevout.n].nValue; + } + + // Tally transaction fees + int64 nTxFee = nValueIn - GetValueOut(); + if (nTxFee < 0) + return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,6).c_str()); + if (nTxFee < nMinFee) + return false; + nFees += nTxFee; + } + + if (fBlock) + { + // Add transaction to disk index + if (!txdb.AddTxIndex(*this, posThisTx, nHeight)) + return error("ConnectInputs() : AddTxPos failed"); + } + else if (fMiner) + { + // Add transaction to test pool + mapTestPool[GetHash()] = CTxIndex(CDiskTxPos(1,1,1), vout.size()); + } + + return true; +} + + +bool CTransaction::ClientConnectInputs() +{ + if (IsCoinBase()) + return false; + + // Take over previous transactions' spent pointers + CRITICAL_BLOCK(cs_mapTransactions) + { + int64 nValueIn = 0; + for (int i = 0; i < vin.size(); i++) + { + // Get prev tx from single transactions in memory + COutPoint prevout = vin[i].prevout; + if (!mapTransactions.count(prevout.hash)) + return false; + CTransaction& txPrev = mapTransactions[prevout.hash]; + + if (prevout.n >= txPrev.vout.size()) + return false; + + // Verify signature + if (!VerifySignature(txPrev, *this, i)) + return error("ConnectInputs() : VerifySignature failed"); + + ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of + ///// this has to go away now that posNext is gone + // // Check for conflicts + // if (!txPrev.vout[prevout.n].posNext.IsNull()) + // return error("ConnectInputs() : prev tx already used"); + // + // // Flag outpoints as used + // txPrev.vout[prevout.n].posNext = posThisTx; + + nValueIn += txPrev.vout[prevout.n].nValue; + } + if (GetValueOut() > nValueIn) + return false; + } + + return true; +} + + + + +bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) +{ + // Disconnect in reverse order + for (int i = vtx.size()-1; i >= 0; i--) + if (!vtx[i].DisconnectInputs(txdb)) + return false; + + // Update block index on disk without changing it in memory. + // The memory index structure will be changed after the db commits. + if (pindex->pprev) + { + CDiskBlockIndex blockindexPrev(pindex->pprev); + blockindexPrev.hashNext = 0; + txdb.WriteBlockIndex(blockindexPrev); + } + + return true; +} + +bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) +{ + //// issue here: it doesn't know the version + unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size()); + + map mapUnused; + int64 nFees = 0; + foreach(CTransaction& tx, vtx) + { + CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); + nTxPos += ::GetSerializeSize(tx, SER_DISK); + + if (!tx.ConnectInputs(txdb, mapUnused, posThisTx, pindex->nHeight, nFees, true, false)) + return false; + } + + if (vtx[0].GetValueOut() > GetBlockValue(nFees)) + return false; + + // Update block index on disk without changing it in memory. + // The memory index structure will be changed after the db commits. + if (pindex->pprev) + { + CDiskBlockIndex blockindexPrev(pindex->pprev); + blockindexPrev.hashNext = pindex->GetBlockHash(); + txdb.WriteBlockIndex(blockindexPrev); + } + + // Watch for transactions paying to me + foreach(CTransaction& tx, vtx) + AddToWalletIfMine(tx, this); + + return true; +} + + + +bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) +{ + printf("*** REORGANIZE ***\n"); + + // Find the fork + CBlockIndex* pfork = pindexBest; + CBlockIndex* plonger = pindexNew; + while (pfork != plonger) + { + if (!(pfork = pfork->pprev)) + return error("Reorganize() : pfork->pprev is null"); + while (plonger->nHeight > pfork->nHeight) + if (!(plonger = plonger->pprev)) + return error("Reorganize() : plonger->pprev is null"); + } + + // List of what to disconnect + vector vDisconnect; + for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev) + vDisconnect.push_back(pindex); + + // List of what to connect + vector vConnect; + for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev) + vConnect.push_back(pindex); + reverse(vConnect.begin(), vConnect.end()); + + // Disconnect shorter branch + vector vResurrect; + foreach(CBlockIndex* pindex, vDisconnect) + { + CBlock block; + if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos, true)) + return error("Reorganize() : ReadFromDisk for disconnect failed"); + if (!block.DisconnectBlock(txdb, pindex)) + return error("Reorganize() : DisconnectBlock failed"); + + // Queue memory transactions to resurrect + foreach(const CTransaction& tx, block.vtx) + if (!tx.IsCoinBase()) + vResurrect.push_back(tx); + } + + // Connect longer branch + vector vDelete; + for (int i = 0; i < vConnect.size(); i++) + { + CBlockIndex* pindex = vConnect[i]; + CBlock block; + if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos, true)) + return error("Reorganize() : ReadFromDisk for connect failed"); + if (!block.ConnectBlock(txdb, pindex)) + { + // Invalid block, delete the rest of this branch + txdb.TxnAbort(); + for (int j = i; j < vConnect.size(); j++) + { + CBlockIndex* pindex = vConnect[j]; + pindex->EraseBlockFromDisk(); + txdb.EraseBlockIndex(pindex->GetBlockHash()); + mapBlockIndex.erase(pindex->GetBlockHash()); + delete pindex; + } + return error("Reorganize() : ConnectBlock failed"); + } + + // Queue memory transactions to delete + foreach(const CTransaction& tx, block.vtx) + vDelete.push_back(tx); + } + if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash())) + return error("Reorganize() : WriteHashBestChain failed"); + + // Commit now because resurrecting could take some time + txdb.TxnCommit(); + + // Disconnect shorter branch + foreach(CBlockIndex* pindex, vDisconnect) + if (pindex->pprev) + pindex->pprev->pnext = NULL; + + // Connect longer branch + foreach(CBlockIndex* pindex, vConnect) + if (pindex->pprev) + pindex->pprev->pnext = pindex; + + // Resurrect memory transactions that were in the disconnected branch + foreach(CTransaction& tx, vResurrect) + tx.AcceptTransaction(txdb, false); + + // Delete redundant memory transactions that are in the connected branch + foreach(CTransaction& tx, vDelete) + tx.RemoveFromMemoryPool(); + + return true; +} + + +bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) +{ + // Check for duplicate + uint256 hash = GetHash(); + if (mapBlockIndex.count(hash)) + return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,14).c_str()); + + // Construct new block index object + CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this); + if (!pindexNew) + return error("AddToBlockIndex() : new CBlockIndex failed"); + map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + map::iterator miPrev = mapBlockIndex.find(hashPrevBlock); + if (miPrev != mapBlockIndex.end()) + { + pindexNew->pprev = (*miPrev).second; + pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + } + + CTxDB txdb; + txdb.TxnBegin(); + txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); + + // New best + if (pindexNew->nHeight > nBestHeight) + { + if (pindexGenesisBlock == NULL && hash == hashGenesisBlock) + { + pindexGenesisBlock = pindexNew; + txdb.WriteHashBestChain(hash); + } + else if (hashPrevBlock == hashBestChain) + { + // Adding to current best branch + if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) + { + txdb.TxnAbort(); + pindexNew->EraseBlockFromDisk(); + mapBlockIndex.erase(pindexNew->GetBlockHash()); + delete pindexNew; + return error("AddToBlockIndex() : ConnectBlock failed"); + } + txdb.TxnCommit(); + pindexNew->pprev->pnext = pindexNew; + + // Delete redundant memory transactions + foreach(CTransaction& tx, vtx) + tx.RemoveFromMemoryPool(); + } + else + { + // New best branch + if (!Reorganize(txdb, pindexNew)) + { + txdb.TxnAbort(); + return error("AddToBlockIndex() : Reorganize failed"); + } + } + + // New best link + hashBestChain = hash; + pindexBest = pindexNew; + nBestHeight = pindexBest->nHeight; + nTransactionsUpdated++; + printf("AddToBlockIndex: new best=%s height=%d\n", hashBestChain.ToString().substr(0,14).c_str(), nBestHeight); + } + + txdb.TxnCommit(); + txdb.Close(); + + // Relay wallet transactions that haven't gotten in yet + if (pindexNew == pindexBest) + RelayWalletTransactions(); + + MainFrameRepaint(); + return true; +} + + + + +bool CBlock::CheckBlock() const +{ + // These are checks that are independent of context + // that can be verified before saving an orphan block. + + // Size limits + if (vtx.empty() || vtx.size() > MAX_SIZE || ::GetSerializeSize(*this, SER_DISK) > MAX_SIZE) + return error("CheckBlock() : size limits failed"); + + // Check timestamp + if (nTime > GetAdjustedTime() + 2 * 60 * 60) + return error("CheckBlock() : block timestamp too far in the future"); + + // First transaction must be coinbase, the rest must not be + if (vtx.empty() || !vtx[0].IsCoinBase()) + return error("CheckBlock() : first tx is not coinbase"); + for (int i = 1; i < vtx.size(); i++) + if (vtx[i].IsCoinBase()) + return error("CheckBlock() : more than one coinbase"); + + // Check transactions + foreach(const CTransaction& tx, vtx) + if (!tx.CheckTransaction()) + return error("CheckBlock() : CheckTransaction failed"); + + // Check proof of work matches claimed amount + if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit) + return error("CheckBlock() : nBits below minimum work"); + if (GetHash() > CBigNum().SetCompact(nBits).getuint256()) + return error("CheckBlock() : hash doesn't match nBits"); + + // Check merkleroot + if (hashMerkleRoot != BuildMerkleTree()) + return error("CheckBlock() : hashMerkleRoot mismatch"); + + return true; +} + +bool CBlock::AcceptBlock() +{ + // Check for duplicate + uint256 hash = GetHash(); + if (mapBlockIndex.count(hash)) + return error("AcceptBlock() : block already in mapBlockIndex"); + + // Get prev block index + map::iterator mi = mapBlockIndex.find(hashPrevBlock); + if (mi == mapBlockIndex.end()) + return error("AcceptBlock() : prev block not found"); + CBlockIndex* pindexPrev = (*mi).second; + + // Check timestamp against prev + if (nTime <= pindexPrev->GetMedianTimePast()) + return error("AcceptBlock() : block's timestamp is too early"); + + // Check proof of work + if (nBits != GetNextWorkRequired(pindexPrev)) + return error("AcceptBlock() : incorrect proof of work"); + + // Write block to history file + if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK))) + return error("AcceptBlock() : out of disk space"); + unsigned int nFile; + unsigned int nBlockPos; + if (!WriteToDisk(!fClient, nFile, nBlockPos)) + return error("AcceptBlock() : WriteToDisk failed"); + if (!AddToBlockIndex(nFile, nBlockPos)) + return error("AcceptBlock() : AddToBlockIndex failed"); + + if (hashBestChain == hash) + RelayInventory(CInv(MSG_BLOCK, hash)); + + // // Add atoms to user reviews for coins created + // vector vchPubKey; + // if (ExtractPubKey(vtx[0].vout[0].scriptPubKey, false, vchPubKey)) + // { + // unsigned short nAtom = GetRand(USHRT_MAX - 100) + 100; + // vector vAtoms(1, nAtom); + // AddAtomsAndPropagate(Hash(vchPubKey.begin(), vchPubKey.end()), vAtoms, true); + // } + + return true; +} + +bool ProcessBlock(CNode* pfrom, CBlock* pblock) +{ + // Check for duplicate + uint256 hash = pblock->GetHash(); + if (mapBlockIndex.count(hash)) + return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,14).c_str()); + if (mapOrphanBlocks.count(hash)) + return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,14).c_str()); + + // Preliminary checks + if (!pblock->CheckBlock()) + { + delete pblock; + return error("ProcessBlock() : CheckBlock FAILED"); + } + + // If don't already have its previous block, shunt it off to holding area until we get it + if (!mapBlockIndex.count(pblock->hashPrevBlock)) + { + printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,14).c_str()); + mapOrphanBlocks.insert(make_pair(hash, pblock)); + mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock)); + + // Ask this guy to fill in what we're missing + if (pfrom) + pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(pblock)); + return true; + } + + // Store to disk + if (!pblock->AcceptBlock()) + { + delete pblock; + return error("ProcessBlock() : AcceptBlock FAILED"); + } + delete pblock; + + // Recursively process any orphan blocks that depended on this one + vector vWorkQueue; + vWorkQueue.push_back(hash); + for (int i = 0; i < vWorkQueue.size(); i++) + { + uint256 hashPrev = vWorkQueue[i]; + for (multimap::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev); + mi != mapOrphanBlocksByPrev.upper_bound(hashPrev); + ++mi) + { + CBlock* pblockOrphan = (*mi).second; + if (pblockOrphan->AcceptBlock()) + vWorkQueue.push_back(pblockOrphan->GetHash()); + mapOrphanBlocks.erase(pblockOrphan->GetHash()); + delete pblockOrphan; + } + mapOrphanBlocksByPrev.erase(hashPrev); + } + + printf("ProcessBlock: ACCEPTED\n"); + return true; +} + + + + + + + + +template +bool ScanMessageStart(Stream& s) +{ + // Scan ahead to the next pchMessageStart, which should normally be immediately + // at the file pointer. Leaves file pointer at end of pchMessageStart. + s.clear(0); + short prevmask = s.exceptions(0); + const char* p = BEGIN(pchMessageStart); + try + { + loop + { + char c; + s.read(&c, 1); + if (s.fail()) + { + s.clear(0); + s.exceptions(prevmask); + return false; + } + if (*p != c) + p = BEGIN(pchMessageStart); + if (*p == c) + { + if (++p == END(pchMessageStart)) + { + s.clear(0); + s.exceptions(prevmask); + return true; + } + } + } + } + catch (...) + { + s.clear(0); + s.exceptions(prevmask); + return false; + } +} + +string GetAppDir() +{ + string strDir; + if (!strSetDataDir.empty()) + { + strDir = strSetDataDir; + } + else if (getenv("APPDATA")) + { + strDir = strprintf("%s\\Bitcoin", getenv("APPDATA")); + } + else if (getenv("USERPROFILE")) + { + string strAppData = strprintf("%s\\Application Data", getenv("USERPROFILE")); + static bool fMkdirDone; + if (!fMkdirDone) + { + fMkdirDone = true; + _mkdir(strAppData.c_str()); + } + strDir = strprintf("%s\\Bitcoin", strAppData.c_str()); + } + else + { + return "."; + } + static bool fMkdirDone; + if (!fMkdirDone) + { + fMkdirDone = true; + _mkdir(strDir.c_str()); + } + return strDir; +} + +bool CheckDiskSpace(int64 nAdditionalBytes) +{ + uint64 nFreeBytesAvailable = 0; // bytes available to caller + uint64 nTotalNumberOfBytes = 0; // bytes on disk + uint64 nTotalNumberOfFreeBytes = 0; // free bytes on disk + + if (!GetDiskFreeSpaceEx(GetAppDir().c_str(), + (PULARGE_INTEGER)&nFreeBytesAvailable, + (PULARGE_INTEGER)&nTotalNumberOfBytes, + (PULARGE_INTEGER)&nTotalNumberOfFreeBytes)) + { + printf("ERROR: GetDiskFreeSpaceEx() failed\n"); + return true; + } + + // Check for 15MB because database could create another 10MB log file at any time + if ((int64)nFreeBytesAvailable < 15000000 + nAdditionalBytes) + { + fShutdown = true; + wxMessageBox("Warning: Your disk space is low ", "Bitcoin", wxICON_EXCLAMATION); + _beginthread(Shutdown, 0, NULL); + return false; + } + return true; +} + +FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode) +{ + if (nFile == -1) + return NULL; + FILE* file = fopen(strprintf("%s\\blk%04d.dat", GetAppDir().c_str(), nFile).c_str(), pszMode); + if (!file) + return NULL; + if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w')) + { + if (fseek(file, nBlockPos, SEEK_SET) != 0) + { + fclose(file); + return NULL; + } + } + return file; +} + +static unsigned int nCurrentBlockFile = 1; + +FILE* AppendBlockFile(unsigned int& nFileRet) +{ + nFileRet = 0; + loop + { + FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab"); + if (!file) + return NULL; + if (fseek(file, 0, SEEK_END) != 0) + return NULL; + // FAT32 filesize max 4GB, fseek and ftell max 2GB, so we must stay under 2GB + if (ftell(file) < 0x7F000000 - MAX_SIZE) + { + nFileRet = nCurrentBlockFile; + return file; + } + fclose(file); + nCurrentBlockFile++; + } +} + +bool LoadBlockIndex(bool fAllowNew) +{ + // + // Load block index + // + CTxDB txdb("cr"); + if (!txdb.LoadBlockIndex()) + return false; + txdb.Close(); + + // + // Init with genesis block + // + if (mapBlockIndex.empty()) + { + if (!fAllowNew) + return false; + + + // Genesis Block: + // GetHash() = 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f + // hashMerkleRoot = 0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + // txNew.vin[0].scriptSig = 486604799 4 0x736B6E616220726F662074756F6C69616220646E6F63657320666F206B6E697262206E6F20726F6C6C65636E61684320393030322F6E614A2F33302073656D695420656854 + // txNew.vout[0].nValue = 5000000000 + // txNew.vout[0].scriptPubKey = 0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704 OP_CHECKSIG + // block.nVersion = 1 + // block.nTime = 1231006505 + // block.nBits = 0x1d00ffff + // block.nNonce = 2083236893 + // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) + // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) + // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) + // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) + // vMerkleTree: 4a5e1e + + // Genesis block + char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; + CTransaction txNew; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector((unsigned char*)pszTimestamp, (unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].nValue = 50 * COIN; + txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG; + CBlock block; + block.vtx.push_back(txNew); + block.hashPrevBlock = 0; + block.hashMerkleRoot = block.BuildMerkleTree(); + block.nVersion = 1; + block.nTime = 1231006505; + block.nBits = 0x1d00ffff; + block.nNonce = 2083236893; + + //// debug print, delete this later + printf("%s\n", block.GetHash().ToString().c_str()); + printf("%s\n", block.hashMerkleRoot.ToString().c_str()); + printf("%s\n", hashGenesisBlock.ToString().c_str()); + txNew.vout[0].scriptPubKey.print(); + block.print(); + assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + + assert(block.GetHash() == hashGenesisBlock); + + // Start new block file + unsigned int nFile; + unsigned int nBlockPos; + if (!block.WriteToDisk(!fClient, nFile, nBlockPos)) + return error("LoadBlockIndex() : writing genesis block to disk failed"); + if (!block.AddToBlockIndex(nFile, nBlockPos)) + return error("LoadBlockIndex() : genesis block not accepted"); + } + + return true; +} + + + +void PrintBlockTree() +{ + // precompute tree structure + map > mapNext; + for (map::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) + { + CBlockIndex* pindex = (*mi).second; + mapNext[pindex->pprev].push_back(pindex); + // test + //while (rand() % 3 == 0) + // mapNext[pindex->pprev].push_back(pindex); + } + + vector > vStack; + vStack.push_back(make_pair(0, pindexGenesisBlock)); + + int nPrevCol = 0; + while (!vStack.empty()) + { + int nCol = vStack.back().first; + CBlockIndex* pindex = vStack.back().second; + vStack.pop_back(); + + // print split or gap + if (nCol > nPrevCol) + { + for (int i = 0; i < nCol-1; i++) + printf("| "); + printf("|\\\n"); + } + else if (nCol < nPrevCol) + { + for (int i = 0; i < nCol; i++) + printf("| "); + printf("|\n"); + } + nPrevCol = nCol; + + // print columns + for (int i = 0; i < nCol; i++) + printf("| "); + + // print item + CBlock block; + block.ReadFromDisk(pindex, true); + printf("%d (%u,%u) %s %s tx %d", + pindex->nHeight, + pindex->nFile, + pindex->nBlockPos, + block.GetHash().ToString().substr(0,14).c_str(), + DateTimeStr(block.nTime).c_str(), + block.vtx.size()); + + CRITICAL_BLOCK(cs_mapWallet) + { + if (mapWallet.count(block.vtx[0].GetHash())) + { + CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; + printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + } + } + printf("\n"); + + + // put the main timechain first + vector& vNext = mapNext[pindex]; + for (int i = 0; i < vNext.size(); i++) + { + if (vNext[i]->pnext) + { + swap(vNext[0], vNext[i]); + break; + } + } + + // iterate children + for (int i = 0; i < vNext.size(); i++) + vStack.push_back(make_pair(nCol+i, vNext[i])); + } +} + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Messages +// + + +bool AlreadyHave(CTxDB& txdb, const CInv& inv) +{ + switch (inv.type) + { + case MSG_TX: return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash); + case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash); + case MSG_REVIEW: return true; + case MSG_PRODUCT: return mapProducts.count(inv.hash); + } + // Don't know what it is, just say we already got one + return true; +} + + + + + + + +bool ProcessMessages(CNode* pfrom) +{ + CDataStream& vRecv = pfrom->vRecv; + if (vRecv.empty()) + return true; + printf("ProcessMessages(%d bytes)\n", vRecv.size()); + + // + // Message format + // (4) message start + // (12) command + // (4) size + // (x) data + // + + loop + { + // Scan for message start + CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); + if (vRecv.end() - pstart < sizeof(CMessageHeader)) + { + if (vRecv.size() > sizeof(CMessageHeader)) + { + printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n"); + vRecv.erase(vRecv.begin(), vRecv.end() - sizeof(CMessageHeader)); + } + break; + } + if (pstart - vRecv.begin() > 0) + printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin()); + vRecv.erase(vRecv.begin(), pstart); + + // Read header + CMessageHeader hdr; + vRecv >> hdr; + if (!hdr.IsValid()) + { + printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str()); + continue; + } + string strCommand = hdr.GetCommand(); + + // Message size + unsigned int nMessageSize = hdr.nMessageSize; + if (nMessageSize > vRecv.size()) + { + // Rewind and wait for rest of message + ///// need a mechanism to give up waiting for overlong message size error + printf("MESSAGE-BREAK\n"); + vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr)); + Sleep(100); + break; + } + + // Copy message to its own buffer + CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); + vRecv.ignore(nMessageSize); + + // Process message + bool fRet = false; + try + { + CheckForShutdown(2); + CRITICAL_BLOCK(cs_main) + fRet = ProcessMessage(pfrom, strCommand, vMsg); + CheckForShutdown(2); + } + CATCH_PRINT_EXCEPTION("ProcessMessage()") + if (!fRet) + printf("ProcessMessage(%s, %d bytes) from %s to %s FAILED\n", strCommand.c_str(), nMessageSize, pfrom->addr.ToString().c_str(), addrLocalHost.ToString().c_str()); + } + + vRecv.Compact(); + return true; +} + + + + +bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) +{ + static map > mapReuseKey; + printf("received: %-12s (%d bytes) ", strCommand.c_str(), vRecv.size()); + for (int i = 0; i < min(vRecv.size(), (unsigned int)20); i++) + printf("%02x ", vRecv[i] & 0xff); + printf("\n"); + if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) + { + printf("dropmessages DROPPING RECV MESSAGE\n"); + return true; + } + + + + if (strCommand == "version") + { + // Can only do this once + if (pfrom->nVersion != 0) + return false; + + int64 nTime; + CAddress addrMe; + vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; + if (pfrom->nVersion == 0) + return false; + + pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION)); + pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION)); + + pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); + if (pfrom->fClient) + { + pfrom->vSend.nType |= SER_BLOCKHEADERONLY; + pfrom->vRecv.nType |= SER_BLOCKHEADERONLY; + } + + AddTimeData(pfrom->addr.ip, nTime); + + // Ask the first connected node for block updates + static bool fAskedForBlocks; + if (!fAskedForBlocks && !pfrom->fClient) + { + fAskedForBlocks = true; + pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), uint256(0)); + } + + printf("version message: %s has version %d, addrMe=%s\n", pfrom->addr.ToString().c_str(), pfrom->nVersion, addrMe.ToString().c_str()); + } + + + else if (pfrom->nVersion == 0) + { + // Must have a version message before anything else + return false; + } + + + else if (strCommand == "addr") + { + vector vAddr; + vRecv >> vAddr; + + // Store the new addresses + CAddrDB addrdb; + foreach(const CAddress& addr, vAddr) + { + if (fShutdown) + return true; + if (AddAddress(addrdb, addr)) + { + // Put on lists to send to other nodes + pfrom->setAddrKnown.insert(addr); + CRITICAL_BLOCK(cs_vNodes) + foreach(CNode* pnode, vNodes) + if (!pnode->setAddrKnown.count(addr)) + pnode->vAddrToSend.push_back(addr); + } + } + } + + + else if (strCommand == "inv") + { + vector vInv; + vRecv >> vInv; + + CTxDB txdb("r"); + foreach(const CInv& inv, vInv) + { + if (fShutdown) + return true; + pfrom->AddInventoryKnown(inv); + + bool fAlreadyHave = AlreadyHave(txdb, inv); + printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new"); + + if (!fAlreadyHave) + pfrom->AskFor(inv); + else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) + pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(mapOrphanBlocks[inv.hash])); + } + } + + + else if (strCommand == "getdata") + { + vector vInv; + vRecv >> vInv; + + foreach(const CInv& inv, vInv) + { + if (fShutdown) + return true; + printf("received getdata for: %s\n", inv.ToString().c_str()); + + if (inv.type == MSG_BLOCK) + { + // Send block from disk + map::iterator mi = mapBlockIndex.find(inv.hash); + if (mi != mapBlockIndex.end()) + { + //// could optimize this to send header straight from blockindex for client + CBlock block; + block.ReadFromDisk((*mi).second, !pfrom->fClient); + pfrom->PushMessage("block", block); + } + } + else if (inv.IsKnownType()) + { + // Send stream from relay memory + CRITICAL_BLOCK(cs_mapRelay) + { + map::iterator mi = mapRelay.find(inv); + if (mi != mapRelay.end()) + pfrom->PushMessage(inv.GetCommand(), (*mi).second); + } + } + } + } + + + else if (strCommand == "getblocks") + { + CBlockLocator locator; + uint256 hashStop; + vRecv >> locator >> hashStop; + + // Find the first block the caller has in the main chain + CBlockIndex* pindex = locator.GetBlockIndex(); + + // Send the rest of the chain + if (pindex) + pindex = pindex->pnext; + printf("getblocks %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,14).c_str()); + for (; pindex; pindex = pindex->pnext) + { + if (pindex->GetBlockHash() == hashStop) + { + printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,14).c_str()); + break; + } + + // Bypass setInventoryKnown in case an inventory message got lost + CRITICAL_BLOCK(pfrom->cs_inventory) + { + CInv inv(MSG_BLOCK, pindex->GetBlockHash()); + // returns true if wasn't already contained in the set + if (pfrom->setInventoryKnown2.insert(inv).second) + { + pfrom->setInventoryKnown.erase(inv); + pfrom->vInventoryToSend.push_back(inv); + } + } + } + } + + + else if (strCommand == "tx") + { + vector vWorkQueue; + CDataStream vMsg(vRecv); + CTransaction tx; + vRecv >> tx; + + CInv inv(MSG_TX, tx.GetHash()); + pfrom->AddInventoryKnown(inv); + + bool fMissingInputs = false; + if (tx.AcceptTransaction(true, &fMissingInputs)) + { + AddToWalletIfMine(tx, NULL); + RelayMessage(inv, vMsg); + mapAlreadyAskedFor.erase(inv); + vWorkQueue.push_back(inv.hash); + + // Recursively process any orphan transactions that depended on this one + for (int i = 0; i < vWorkQueue.size(); i++) + { + uint256 hashPrev = vWorkQueue[i]; + for (multimap::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev); + mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev); + ++mi) + { + const CDataStream& vMsg = *((*mi).second); + CTransaction tx; + CDataStream(vMsg) >> tx; + CInv inv(MSG_TX, tx.GetHash()); + + if (tx.AcceptTransaction(true)) + { + printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str()); + AddToWalletIfMine(tx, NULL); + RelayMessage(inv, vMsg); + mapAlreadyAskedFor.erase(inv); + vWorkQueue.push_back(inv.hash); + } + } + } + + foreach(uint256 hash, vWorkQueue) + EraseOrphanTx(hash); + } + else if (fMissingInputs) + { + printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str()); + AddOrphanTx(vMsg); + } + } + + + else if (strCommand == "review") + { + CDataStream vMsg(vRecv); + CReview review; + vRecv >> review; + + CInv inv(MSG_REVIEW, review.GetHash()); + pfrom->AddInventoryKnown(inv); + + if (review.AcceptReview()) + { + // Relay the original message as-is in case it's a higher version than we know how to parse + RelayMessage(inv, vMsg); + mapAlreadyAskedFor.erase(inv); + } + } + + + else if (strCommand == "block") + { + auto_ptr pblock(new CBlock); + vRecv >> *pblock; + + //// debug print + printf("received block:\n"); pblock->print(); + + CInv inv(MSG_BLOCK, pblock->GetHash()); + pfrom->AddInventoryKnown(inv); + + if (ProcessBlock(pfrom, pblock.release())) + mapAlreadyAskedFor.erase(inv); + } + + + else if (strCommand == "getaddr") + { + pfrom->vAddrToSend.clear(); + int64 nSince = GetAdjustedTime() - 5 * 24 * 60 * 60; // in the last 5 days + CRITICAL_BLOCK(cs_mapAddresses) + { + unsigned int nSize = mapAddresses.size(); + foreach(const PAIRTYPE(vector, CAddress)& item, mapAddresses) + { + if (fShutdown) + return true; + const CAddress& addr = item.second; + //// will need this if we lose IRC + //if (addr.nTime > nSince || (rand() % nSize) < 500) + if (addr.nTime > nSince) + pfrom->vAddrToSend.push_back(addr); + } + } + } + + + else if (strCommand == "checkorder") + { + uint256 hashReply; + CWalletTx order; + vRecv >> hashReply >> order; + + /// we have a chance to check the order here + + // Keep giving the same key to the same ip until they use it + if (!mapReuseKey.count(pfrom->addr.ip)) + mapReuseKey[pfrom->addr.ip] = GenerateNewKey(); + + // Send back approval of order and pubkey to use + CScript scriptPubKey; + scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG; + pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey); + } + + + else if (strCommand == "submitorder") + { + uint256 hashReply; + CWalletTx wtxNew; + vRecv >> hashReply >> wtxNew; + + // Broadcast + if (!wtxNew.AcceptWalletTransaction()) + { + pfrom->PushMessage("reply", hashReply, (int)1); + return error("submitorder AcceptWalletTransaction() failed, returning error 1"); + } + wtxNew.fTimeReceivedIsTxTime = true; + AddToWallet(wtxNew); + wtxNew.RelayWalletTransaction(); + mapReuseKey.erase(pfrom->addr.ip); + + // Send back confirmation + pfrom->PushMessage("reply", hashReply, (int)0); + } + + + else if (strCommand == "reply") + { + uint256 hashReply; + vRecv >> hashReply; + + CRequestTracker tracker; + CRITICAL_BLOCK(pfrom->cs_mapRequests) + { + map::iterator mi = pfrom->mapRequests.find(hashReply); + if (mi != pfrom->mapRequests.end()) + { + tracker = (*mi).second; + pfrom->mapRequests.erase(mi); + } + } + if (!tracker.IsNull()) + tracker.fn(tracker.param1, vRecv); + } + + + else + { + // Ignore unknown commands for extensibility + printf("ProcessMessage(%s) : Ignored unknown message\n", strCommand.c_str()); + } + + + if (!vRecv.empty()) + printf("ProcessMessage(%s) : %d extra bytes\n", strCommand.c_str(), vRecv.size()); + + return true; +} + + + + + + + + + +bool SendMessages(CNode* pto) +{ + CheckForShutdown(2); + CRITICAL_BLOCK(cs_main) + { + // Don't send anything until we get their version message + if (pto->nVersion == 0) + return true; + + + // + // Message: addr + // + vector vAddrToSend; + vAddrToSend.reserve(pto->vAddrToSend.size()); + foreach(const CAddress& addr, pto->vAddrToSend) + if (!pto->setAddrKnown.count(addr)) + vAddrToSend.push_back(addr); + pto->vAddrToSend.clear(); + if (!vAddrToSend.empty()) + pto->PushMessage("addr", vAddrToSend); + + + // + // Message: inventory + // + vector vInventoryToSend; + CRITICAL_BLOCK(pto->cs_inventory) + { + vInventoryToSend.reserve(pto->vInventoryToSend.size()); + foreach(const CInv& inv, pto->vInventoryToSend) + { + // returns true if wasn't already contained in the set + if (pto->setInventoryKnown.insert(inv).second) + vInventoryToSend.push_back(inv); + } + pto->vInventoryToSend.clear(); + pto->setInventoryKnown2.clear(); + } + if (!vInventoryToSend.empty()) + pto->PushMessage("inv", vInventoryToSend); + + + // + // Message: getdata + // + vector vAskFor; + int64 nNow = GetTime() * 1000000; + CTxDB txdb("r"); + while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow) + { + const CInv& inv = (*pto->mapAskFor.begin()).second; + printf("sending getdata: %s\n", inv.ToString().c_str()); + if (!AlreadyHave(txdb, inv)) + vAskFor.push_back(inv); + pto->mapAskFor.erase(pto->mapAskFor.begin()); + } + if (!vAskFor.empty()) + pto->PushMessage("getdata", vAskFor); + + } + return true; +} + + + + + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// BitcoinMiner +// + +int FormatHashBlocks(void* pbuffer, unsigned int len) +{ + unsigned char* pdata = (unsigned char*)pbuffer; + unsigned int blocks = 1 + ((len + 8) / 64); + unsigned char* pend = pdata + 64 * blocks; + memset(pdata + len, 0, 64 * blocks - len); + pdata[len] = 0x80; + unsigned int bits = len * 8; + pend[-1] = (bits >> 0) & 0xff; + pend[-2] = (bits >> 8) & 0xff; + pend[-3] = (bits >> 16) & 0xff; + pend[-4] = (bits >> 24) & 0xff; + return blocks; +} + +using CryptoPP::ByteReverse; +static int detectlittleendian = 1; + +void BlockSHA256(const void* pin, unsigned int nBlocks, void* pout) +{ + unsigned int* pinput = (unsigned int*)pin; + unsigned int* pstate = (unsigned int*)pout; + + CryptoPP::SHA256::InitState(pstate); + + if (*(char*)&detectlittleendian != 0) + { + for (int n = 0; n < nBlocks; n++) + { + unsigned int pbuf[16]; + for (int i = 0; i < 16; i++) + pbuf[i] = ByteReverse(pinput[n * 16 + i]); + CryptoPP::SHA256::Transform(pstate, pbuf); + } + for (int i = 0; i < 8; i++) + pstate[i] = ByteReverse(pstate[i]); + } + else + { + for (int n = 0; n < nBlocks; n++) + CryptoPP::SHA256::Transform(pstate, pinput + n * 16); + } +} + + +bool BitcoinMiner() +{ + printf("BitcoinMiner started\n"); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST); + + CKey key; + key.MakeNewKey(); + CBigNum bnExtraNonce = 0; + while (fGenerateBitcoins) + { + Sleep(50); + CheckForShutdown(3); + while (vNodes.empty()) + { + Sleep(1000); + CheckForShutdown(3); + } + + unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrev = pindexBest; + unsigned int nBits = GetNextWorkRequired(pindexPrev); + + + // + // Create coinbase tx + // + CTransaction txNew; + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vin[0].scriptSig << nBits << ++bnExtraNonce; + txNew.vout.resize(1); + txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG; + + + // + // Create new block + // + auto_ptr pblock(new CBlock()); + if (!pblock.get()) + return false; + + // Add our coinbase tx as first transaction + pblock->vtx.push_back(txNew); + + // Collect the latest transactions into the block + int64 nFees = 0; + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_mapTransactions) + { + CTxDB txdb("r"); + map mapTestPool; + vector vfAlreadyAdded(mapTransactions.size()); + bool fFoundSomething = true; + unsigned int nBlockSize = 0; + while (fFoundSomething && nBlockSize < MAX_SIZE/2) + { + fFoundSomething = false; + unsigned int n = 0; + for (map::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n) + { + if (vfAlreadyAdded[n]) + continue; + CTransaction& tx = (*mi).second; + if (tx.IsCoinBase() || !tx.IsFinal()) + continue; + + // Transaction fee requirements, mainly only needed for flood control + // Under 10K (about 80 inputs) is free for first 100 transactions + // Base rate is 0.01 per KB + int64 nMinFee = tx.GetMinFee(pblock->vtx.size() < 100); + + map mapTestPoolTmp(mapTestPool); + if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), 0, nFees, false, true, nMinFee)) + continue; + swap(mapTestPool, mapTestPoolTmp); + + pblock->vtx.push_back(tx); + nBlockSize += ::GetSerializeSize(tx, SER_NETWORK); + vfAlreadyAdded[n] = true; + fFoundSomething = true; + } + } + } + pblock->nBits = nBits; + pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nFees); + printf("\n\nRunning BitcoinMiner with %d transactions in block\n", pblock->vtx.size()); + + + // + // Prebuild hash buffer + // + struct unnamed1 + { + struct unnamed2 + { + int nVersion; + uint256 hashPrevBlock; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + } + block; + unsigned char pchPadding0[64]; + uint256 hash1; + unsigned char pchPadding1[64]; + } + tmp; + + tmp.block.nVersion = pblock->nVersion; + tmp.block.hashPrevBlock = pblock->hashPrevBlock = (pindexPrev ? pindexPrev->GetBlockHash() : 0); + tmp.block.hashMerkleRoot = pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + tmp.block.nTime = pblock->nTime = max((pindexPrev ? pindexPrev->GetMedianTimePast()+1 : 0), GetAdjustedTime()); + tmp.block.nBits = pblock->nBits = nBits; + tmp.block.nNonce = pblock->nNonce = 1; + + unsigned int nBlocks0 = FormatHashBlocks(&tmp.block, sizeof(tmp.block)); + unsigned int nBlocks1 = FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1)); + + + // + // Search + // + unsigned int nStart = GetTime(); + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hash; + loop + { + BlockSHA256(&tmp.block, nBlocks0, &tmp.hash1); + BlockSHA256(&tmp.hash1, nBlocks1, &hash); + + + if (hash <= hashTarget) + { + pblock->nNonce = tmp.block.nNonce; + assert(hash == pblock->GetHash()); + + //// debug print + printf("BitcoinMiner:\n"); + printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + pblock->print(); + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + CRITICAL_BLOCK(cs_main) + { + // Save key + if (!AddKey(key)) + return false; + key.MakeNewKey(); + + // Process this block the same as if we had received it from another node + if (!ProcessBlock(NULL, pblock.release())) + printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n"); + } + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST); + + Sleep(500); + break; + } + + // Update nTime every few seconds + if ((++tmp.block.nNonce & 0x3ffff) == 0) + { + CheckForShutdown(3); + if (tmp.block.nNonce == 0) + break; + if (pindexPrev != pindexBest) + break; + if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (!fGenerateBitcoins) + break; + tmp.block.nTime = pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + } + } + } + + return true; +} + + + + + + + + + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Actions +// + + +int64 GetBalance() +{ + int64 nStart, nEnd; + QueryPerformanceCounter((LARGE_INTEGER*)&nStart); + + int64 nTotal = 0; + CRITICAL_BLOCK(cs_mapWallet) + { + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx* pcoin = &(*it).second; + if (!pcoin->IsFinal() || pcoin->fSpent) + continue; + nTotal += pcoin->GetCredit(); + } + } + + QueryPerformanceCounter((LARGE_INTEGER*)&nEnd); + ///printf(" GetBalance() time = %16I64d\n", nEnd - nStart); + return nTotal; +} + + + +bool SelectCoins(int64 nTargetValue, set& setCoinsRet) +{ + setCoinsRet.clear(); + + // List of values less than target + int64 nLowestLarger = _I64_MAX; + CWalletTx* pcoinLowestLarger = NULL; + vector > vValue; + int64 nTotalLower = 0; + + CRITICAL_BLOCK(cs_mapWallet) + { + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx* pcoin = &(*it).second; + if (!pcoin->IsFinal() || pcoin->fSpent) + continue; + int64 n = pcoin->GetCredit(); + if (n <= 0) + continue; + if (n < nTargetValue) + { + vValue.push_back(make_pair(n, pcoin)); + nTotalLower += n; + } + else if (n == nTargetValue) + { + setCoinsRet.insert(pcoin); + return true; + } + else if (n < nLowestLarger) + { + nLowestLarger = n; + pcoinLowestLarger = pcoin; + } + } + } + + if (nTotalLower < nTargetValue) + { + if (pcoinLowestLarger == NULL) + return false; + setCoinsRet.insert(pcoinLowestLarger); + return true; + } + + // Solve subset sum by stochastic approximation + sort(vValue.rbegin(), vValue.rend()); + vector vfIncluded; + vector vfBest(vValue.size(), true); + int64 nBest = nTotalLower; + + for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++) + { + vfIncluded.assign(vValue.size(), false); + int64 nTotal = 0; + bool fReachedTarget = false; + for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) + { + for (int i = 0; i < vValue.size(); i++) + { + if (nPass == 0 ? rand() % 2 : !vfIncluded[i]) + { + nTotal += vValue[i].first; + vfIncluded[i] = true; + if (nTotal >= nTargetValue) + { + fReachedTarget = true; + if (nTotal < nBest) + { + nBest = nTotal; + vfBest = vfIncluded; + } + nTotal -= vValue[i].first; + vfIncluded[i] = false; + } + } + } + } + } + + // If the next larger is still closer, return it + if (pcoinLowestLarger && nLowestLarger - nTargetValue <= nBest - nTargetValue) + setCoinsRet.insert(pcoinLowestLarger); + else + { + for (int i = 0; i < vValue.size(); i++) + if (vfBest[i]) + setCoinsRet.insert(vValue[i].second); + + //// debug print + printf("SelectCoins() best subset: "); + for (int i = 0; i < vValue.size(); i++) + if (vfBest[i]) + printf("%s ", FormatMoney(vValue[i].first).c_str()); + printf("total %s\n", FormatMoney(nBest).c_str()); + } + + return true; +} + + + + +bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, int64& nFeeRequiredRet) +{ + nFeeRequiredRet = 0; + CRITICAL_BLOCK(cs_main) + { + // txdb must be opened before the mapWallet lock + CTxDB txdb("r"); + CRITICAL_BLOCK(cs_mapWallet) + { + int64 nFee = nTransactionFee; + loop + { + wtxNew.vin.clear(); + wtxNew.vout.clear(); + if (nValue < 0) + return false; + int64 nValueOut = nValue; + nValue += nFee; + + // Choose coins to use + set setCoins; + if (!SelectCoins(nValue, setCoins)) + return false; + int64 nValueIn = 0; + foreach(CWalletTx* pcoin, setCoins) + nValueIn += pcoin->GetCredit(); + + // Fill vout[0] to the payee + wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey)); + + // Fill vout[1] back to self with any change + if (nValueIn > nValue) + { + /// todo: for privacy, should randomize the order of outputs, + // would also have to use a new key for the change. + // Use the same key as one of the coins + vector vchPubKey; + CTransaction& txFirst = *(*setCoins.begin()); + foreach(const CTxOut& txout, txFirst.vout) + if (txout.IsMine()) + if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) + break; + if (vchPubKey.empty()) + return false; + + // Fill vout[1] to ourself + CScript scriptPubKey; + scriptPubKey << vchPubKey << OP_CHECKSIG; + wtxNew.vout.push_back(CTxOut(nValueIn - nValue, scriptPubKey)); + } + + // Fill vin + foreach(CWalletTx* pcoin, setCoins) + for (int nOut = 0; nOut < pcoin->vout.size(); nOut++) + if (pcoin->vout[nOut].IsMine()) + wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut)); + + // Sign + int nIn = 0; + foreach(CWalletTx* pcoin, setCoins) + for (int nOut = 0; nOut < pcoin->vout.size(); nOut++) + if (pcoin->vout[nOut].IsMine()) + SignSignature(*pcoin, wtxNew, nIn++); + + // Check that enough fee is included + if (nFee < wtxNew.GetMinFee(true)) + { + nFee = nFeeRequiredRet = wtxNew.GetMinFee(true); + continue; + } + + // Fill vtxPrev by copying from previous transactions vtxPrev + wtxNew.AddSupportingTransactions(txdb); + wtxNew.fTimeReceivedIsTxTime = true; + + break; + } + } + } + return true; +} + +// Call after CreateTransaction unless you want to abort +bool CommitTransactionSpent(const CWalletTx& wtxNew) +{ + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_mapWallet) + { + //// todo: make this transactional, never want to add a transaction + //// without marking spent transactions + + // Add tx to wallet, because if it has change it's also ours, + // otherwise just for transaction history. + AddToWallet(wtxNew); + + // Mark old coins as spent + set setCoins; + foreach(const CTxIn& txin, wtxNew.vin) + setCoins.insert(&mapWallet[txin.prevout.hash]); + foreach(CWalletTx* pcoin, setCoins) + { + pcoin->fSpent = true; + pcoin->WriteToDisk(); + vWalletUpdated.push_back(make_pair(pcoin->GetHash(), false)); + } + } + MainFrameRepaint(); + return true; +} + + + + +bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew) +{ + CRITICAL_BLOCK(cs_main) + { + int64 nFeeRequired; + if (!CreateTransaction(scriptPubKey, nValue, wtxNew, nFeeRequired)) + { + string strError; + if (nValue + nFeeRequired > GetBalance()) + strError = strprintf("Error: This is an oversized transaction that requires a transaction fee of %s ", FormatMoney(nFeeRequired).c_str()); + else + strError = "Error: Transaction creation failed "; + wxMessageBox(strError, "Sending..."); + return error("SendMoney() : %s\n", strError.c_str()); + } + if (!CommitTransactionSpent(wtxNew)) + { + wxMessageBox("Error finalizing transaction ", "Sending..."); + return error("SendMoney() : Error finalizing transaction"); + } + + printf("SendMoney: %s\n", wtxNew.GetHash().ToString().substr(0,6).c_str()); + + // Broadcast + if (!wtxNew.AcceptTransaction()) + { + // This must not fail. The transaction has already been signed and recorded. + throw runtime_error("SendMoney() : wtxNew.AcceptTransaction() failed\n"); + wxMessageBox("Error: Transaction not valid ", "Sending..."); + return error("SendMoney() : Error: Transaction not valid"); + } + wtxNew.RelayWalletTransaction(); + } + MainFrameRepaint(); + return true; +} diff --git a/main.h b/main.h new file mode 100644 index 000000000..3432b316e --- /dev/null +++ b/main.h @@ -0,0 +1,1329 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +class COutPoint; +class CInPoint; +class CDiskTxPos; +class CCoinBase; +class CTxIn; +class CTxOut; +class CTransaction; +class CBlock; +class CBlockIndex; +class CWalletTx; +class CKeyItem; + +static const unsigned int MAX_SIZE = 0x02000000; +static const int64 COIN = 100000000; +static const int64 CENT = 1000000; +static const int COINBASE_MATURITY = 100; + +static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); + + + + + + +extern CCriticalSection cs_main; +extern map mapBlockIndex; +extern const uint256 hashGenesisBlock; +extern CBlockIndex* pindexGenesisBlock; +extern int nBestHeight; +extern uint256 hashBestChain; +extern CBlockIndex* pindexBest; +extern unsigned int nTransactionsUpdated; +extern string strSetDataDir; +extern int nDropMessagesTest; + +// Settings +extern int fGenerateBitcoins; +extern int64 nTransactionFee; +extern CAddress addrIncoming; + + + + + + + +string GetAppDir(); +bool CheckDiskSpace(int64 nAdditionalBytes=0); +FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); +FILE* AppendBlockFile(unsigned int& nFileRet); +bool AddKey(const CKey& key); +vector GenerateNewKey(); +bool AddToWallet(const CWalletTx& wtxIn); +void ReacceptWalletTransactions(); +void RelayWalletTransactions(); +bool LoadBlockIndex(bool fAllowNew=true); +void PrintBlockTree(); +bool BitcoinMiner(); +bool ProcessMessages(CNode* pfrom); +bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv); +bool SendMessages(CNode* pto); +int64 GetBalance(); +bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& txNew, int64& nFeeRequiredRet); +bool CommitTransactionSpent(const CWalletTx& wtxNew); +bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew); + + + + + + + + + + + +class CDiskTxPos +{ +public: + unsigned int nFile; + unsigned int nBlockPos; + unsigned int nTxPos; + + CDiskTxPos() + { + SetNull(); + } + + CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn) + { + nFile = nFileIn; + nBlockPos = nBlockPosIn; + nTxPos = nTxPosIn; + } + + IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) + void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; } + bool IsNull() const { return (nFile == -1); } + + friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b) + { + return (a.nFile == b.nFile && + a.nBlockPos == b.nBlockPos && + a.nTxPos == b.nTxPos); + } + + friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b) + { + return !(a == b); + } + + string ToString() const + { + if (IsNull()) + return strprintf("null"); + else + return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos); + } + + void print() const + { + printf("%s", ToString().c_str()); + } +}; + + + + +class CInPoint +{ +public: + CTransaction* ptx; + unsigned int n; + + CInPoint() { SetNull(); } + CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; } + void SetNull() { ptx = NULL; n = -1; } + bool IsNull() const { return (ptx == NULL && n == -1); } +}; + + + + +class COutPoint +{ +public: + uint256 hash; + unsigned int n; + + COutPoint() { SetNull(); } + COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; } + IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) + void SetNull() { hash = 0; n = -1; } + bool IsNull() const { return (hash == 0 && n == -1); } + + friend bool operator<(const COutPoint& a, const COutPoint& b) + { + return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); + } + + friend bool operator==(const COutPoint& a, const COutPoint& b) + { + return (a.hash == b.hash && a.n == b.n); + } + + friend bool operator!=(const COutPoint& a, const COutPoint& b) + { + return !(a == b); + } + + string ToString() const + { + return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,6).c_str(), n); + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + +// +// An input of a transaction. It contains the location of the previous +// transaction's output that it claims and a signature that matches the +// output's public key. +// +class CTxIn +{ +public: + COutPoint prevout; + CScript scriptSig; + unsigned int nSequence; + + CTxIn() + { + nSequence = UINT_MAX; + } + + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX) + { + prevout = prevoutIn; + scriptSig = scriptSigIn; + nSequence = nSequenceIn; + } + + CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX) + { + prevout = COutPoint(hashPrevTx, nOut); + scriptSig = scriptSigIn; + nSequence = nSequenceIn; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(prevout); + READWRITE(scriptSig); + READWRITE(nSequence); + ) + + bool IsFinal() const + { + return (nSequence == UINT_MAX); + } + + friend bool operator==(const CTxIn& a, const CTxIn& b) + { + return (a.prevout == b.prevout && + a.scriptSig == b.scriptSig && + a.nSequence == b.nSequence); + } + + friend bool operator!=(const CTxIn& a, const CTxIn& b) + { + return !(a == b); + } + + string ToString() const + { + string str; + str += strprintf("CTxIn("); + str += prevout.ToString(); + if (prevout.IsNull()) + str += strprintf(", coinbase %s", HexStr(scriptSig.begin(), scriptSig.end(), false).c_str()); + else + str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); + if (nSequence != UINT_MAX) + str += strprintf(", nSequence=%u", nSequence); + str += ")"; + return str; + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } + + bool IsMine() const; + int64 GetDebit() const; +}; + + + + +// +// An output of a transaction. It contains the public key that the next input +// must be able to sign with to claim it. +// +class CTxOut +{ +public: + int64 nValue; + CScript scriptPubKey; + +public: + CTxOut() + { + SetNull(); + } + + CTxOut(int64 nValueIn, CScript scriptPubKeyIn) + { + nValue = nValueIn; + scriptPubKey = scriptPubKeyIn; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(nValue); + READWRITE(scriptPubKey); + ) + + void SetNull() + { + nValue = -1; + scriptPubKey.clear(); + } + + bool IsNull() + { + return (nValue == -1); + } + + uint256 GetHash() const + { + return SerializeHash(*this); + } + + bool IsMine() const + { + return ::IsMine(scriptPubKey); + } + + int64 GetCredit() const + { + if (IsMine()) + return nValue; + return 0; + } + + friend bool operator==(const CTxOut& a, const CTxOut& b) + { + return (a.nValue == b.nValue && + a.scriptPubKey == b.scriptPubKey); + } + + friend bool operator!=(const CTxOut& a, const CTxOut& b) + { + return !(a == b); + } + + string ToString() const + { + if (scriptPubKey.size() < 6) + return "CTxOut(error)"; + return strprintf("CTxOut(nValue=%I64d.%08I64d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,24).c_str()); + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + +// +// The basic transaction that is broadcasted on the network and contained in +// blocks. A transaction can contain multiple inputs and outputs. +// +class CTransaction +{ +public: + int nVersion; + vector vin; + vector vout; + int nLockTime; + + + CTransaction() + { + SetNull(); + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(vin); + READWRITE(vout); + READWRITE(nLockTime); + ) + + void SetNull() + { + nVersion = 1; + vin.clear(); + vout.clear(); + nLockTime = 0; + } + + bool IsNull() const + { + return (vin.empty() && vout.empty()); + } + + uint256 GetHash() const + { + return SerializeHash(*this); + } + + bool IsFinal() const + { + if (nLockTime == 0 || nLockTime < nBestHeight) + return true; + foreach(const CTxIn& txin, vin) + if (!txin.IsFinal()) + return false; + return true; + } + + bool IsNewerThan(const CTransaction& old) const + { + if (vin.size() != old.vin.size()) + return false; + for (int i = 0; i < vin.size(); i++) + if (vin[i].prevout != old.vin[i].prevout) + return false; + + bool fNewer = false; + unsigned int nLowest = UINT_MAX; + for (int i = 0; i < vin.size(); i++) + { + if (vin[i].nSequence != old.vin[i].nSequence) + { + if (vin[i].nSequence <= nLowest) + { + fNewer = false; + nLowest = vin[i].nSequence; + } + if (old.vin[i].nSequence < nLowest) + { + fNewer = true; + nLowest = old.vin[i].nSequence; + } + } + } + return fNewer; + } + + bool IsCoinBase() const + { + return (vin.size() == 1 && vin[0].prevout.IsNull()); + } + + bool CheckTransaction() const + { + // Basic checks that don't depend on any context + if (vin.empty() || vout.empty()) + return error("CTransaction::CheckTransaction() : vin or vout empty"); + + // Check for negative values + foreach(const CTxOut& txout, vout) + if (txout.nValue < 0) + return error("CTransaction::CheckTransaction() : txout.nValue negative"); + + if (IsCoinBase()) + { + if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100) + return error("CTransaction::CheckTransaction() : coinbase script size"); + } + else + { + foreach(const CTxIn& txin, vin) + if (txin.prevout.IsNull()) + return error("CTransaction::CheckTransaction() : prevout is null"); + } + + return true; + } + + bool IsMine() const + { + foreach(const CTxOut& txout, vout) + if (txout.IsMine()) + return true; + return false; + } + + int64 GetDebit() const + { + int64 nDebit = 0; + foreach(const CTxIn& txin, vin) + nDebit += txin.GetDebit(); + return nDebit; + } + + int64 GetCredit() const + { + int64 nCredit = 0; + foreach(const CTxOut& txout, vout) + nCredit += txout.GetCredit(); + return nCredit; + } + + int64 GetValueOut() const + { + int64 nValueOut = 0; + foreach(const CTxOut& txout, vout) + { + if (txout.nValue < 0) + throw runtime_error("CTransaction::GetValueOut() : negative value"); + nValueOut += txout.nValue; + } + return nValueOut; + } + + int64 GetMinFee(bool fDiscount=false) const + { + // Base fee is 1 cent per kilobyte + unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK); + int64 nMinFee = (1 + (int64)nBytes / 1000) * CENT; + + // First 100 transactions in a block are free + if (fDiscount && nBytes < 10000) + nMinFee = 0; + + // To limit dust spam, require a 0.01 fee if any output is less than 0.01 + if (nMinFee < CENT) + foreach(const CTxOut& txout, vout) + if (txout.nValue < CENT) + nMinFee = CENT; + + return nMinFee; + } + + + + bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL) + { + CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"); + if (!filein) + return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); + + // Read transaction + if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) + return error("CTransaction::ReadFromDisk() : fseek failed"); + filein >> *this; + + // Return file pointer + if (pfileRet) + { + if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) + return error("CTransaction::ReadFromDisk() : second fseek failed"); + *pfileRet = filein.release(); + } + return true; + } + + + friend bool operator==(const CTransaction& a, const CTransaction& b) + { + return (a.nVersion == b.nVersion && + a.vin == b.vin && + a.vout == b.vout && + a.nLockTime == b.nLockTime); + } + + friend bool operator!=(const CTransaction& a, const CTransaction& b) + { + return !(a == b); + } + + + string ToString() const + { + string str; + str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n", + GetHash().ToString().substr(0,6).c_str(), + nVersion, + vin.size(), + vout.size(), + nLockTime); + for (int i = 0; i < vin.size(); i++) + str += " " + vin[i].ToString() + "\n"; + for (int i = 0; i < vout.size(); i++) + str += " " + vout[i].ToString() + "\n"; + return str; + } + + void print() const + { + printf("%s", ToString().c_str()); + } + + + + bool DisconnectInputs(CTxDB& txdb); + bool ConnectInputs(CTxDB& txdb, map& mapTestPool, CDiskTxPos posThisTx, int nHeight, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0); + bool ClientConnectInputs(); + + bool AcceptTransaction(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL); + + bool AcceptTransaction(bool fCheckInputs=true, bool* pfMissingInputs=NULL) + { + CTxDB txdb("r"); + return AcceptTransaction(txdb, fCheckInputs, pfMissingInputs); + } + +protected: + bool AddToMemoryPool(); +public: + bool RemoveFromMemoryPool(); +}; + + + + + +// +// A transaction with a merkle branch linking it to the block chain +// +class CMerkleTx : public CTransaction +{ +public: + uint256 hashBlock; + vector vMerkleBranch; + int nIndex; + + // memory only + mutable bool fMerkleVerified; + + + CMerkleTx() + { + Init(); + } + + CMerkleTx(const CTransaction& txIn) : CTransaction(txIn) + { + Init(); + } + + void Init() + { + hashBlock = 0; + nIndex = -1; + fMerkleVerified = false; + } + + int64 GetCredit() const + { + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + return CTransaction::GetCredit(); + } + + IMPLEMENT_SERIALIZE + ( + nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action); + nVersion = this->nVersion; + READWRITE(hashBlock); + READWRITE(vMerkleBranch); + READWRITE(nIndex); + ) + + + int SetMerkleBranch(const CBlock* pblock=NULL); + int GetDepthInMainChain() const; + bool IsInMainChain() const { return GetDepthInMainChain() > 0; } + int GetBlocksToMaturity() const; + bool AcceptTransaction(CTxDB& txdb, bool fCheckInputs=true); + bool AcceptTransaction() { CTxDB txdb("r"); return AcceptTransaction(txdb); } +}; + + + + +// +// A transaction with a bunch of additional info that only the owner cares +// about. It includes any unrecorded transactions needed to link it back +// to the block chain. +// +class CWalletTx : public CMerkleTx +{ +public: + vector vtxPrev; + map mapValue; + vector > vOrderForm; + unsigned int fTimeReceivedIsTxTime; + unsigned int nTimeReceived; // time received by this node + char fFromMe; + char fSpent; + //// probably need to sign the order info so know it came from payer + + // memory only + mutable unsigned int nTimeDisplayed; + + + CWalletTx() + { + Init(); + } + + CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn) + { + Init(); + } + + CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn) + { + Init(); + } + + void Init() + { + fTimeReceivedIsTxTime = false; + nTimeReceived = 0; + fFromMe = false; + fSpent = false; + nTimeDisplayed = 0; + } + + IMPLEMENT_SERIALIZE + ( + nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action); + nVersion = this->nVersion; + READWRITE(vtxPrev); + READWRITE(mapValue); + READWRITE(vOrderForm); + READWRITE(fTimeReceivedIsTxTime); + READWRITE(nTimeReceived); + READWRITE(fFromMe); + READWRITE(fSpent); + ) + + bool WriteToDisk() + { + return CWalletDB().WriteTx(GetHash(), *this); + } + + + int64 GetTxTime() const; + + void AddSupportingTransactions(CTxDB& txdb); + + bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true); + bool AcceptWalletTransaction() { CTxDB txdb("r"); return AcceptWalletTransaction(txdb); } + + void RelayWalletTransaction(CTxDB& txdb); + void RelayWalletTransaction() { CTxDB txdb("r"); RelayWalletTransaction(txdb); } +}; + + + + +// +// A txdb record that contains the disk location of a transaction and the +// locations of transactions that spend its outputs. vSpent is really only +// used as a flag, but having the location is very helpful for debugging. +// +class CTxIndex +{ +public: + CDiskTxPos pos; + vector vSpent; + + CTxIndex() + { + SetNull(); + } + + CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs) + { + pos = posIn; + vSpent.resize(nOutputs); + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(pos); + READWRITE(vSpent); + ) + + void SetNull() + { + pos.SetNull(); + vSpent.clear(); + } + + bool IsNull() + { + return pos.IsNull(); + } + + friend bool operator==(const CTxIndex& a, const CTxIndex& b) + { + if (a.pos != b.pos || a.vSpent.size() != b.vSpent.size()) + return false; + for (int i = 0; i < a.vSpent.size(); i++) + if (a.vSpent[i] != b.vSpent[i]) + return false; + return true; + } + + friend bool operator!=(const CTxIndex& a, const CTxIndex& b) + { + return !(a == b); + } +}; + + + + + +// +// Nodes collect new transactions into a block, hash them into a hash tree, +// and scan through nonce values to make the block's hash satisfy proof-of-work +// requirements. When they solve the proof-of-work, they broadcast the block +// to everyone and the block is added to the block chain. The first transaction +// in the block is a special one that creates a new coin owned by the creator +// of the block. +// +// Blocks are appended to blk0001.dat files on disk. Their location on disk +// is indexed by CBlockIndex objects in memory. +// +class CBlock +{ +public: + // header + int nVersion; + uint256 hashPrevBlock; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + + // network and disk + vector vtx; + + // memory only + mutable vector vMerkleTree; + + + CBlock() + { + SetNull(); + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(hashPrevBlock); + READWRITE(hashMerkleRoot); + READWRITE(nTime); + READWRITE(nBits); + READWRITE(nNonce); + + // ConnectBlock depends on vtx being last so it can calculate offset + if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY))) + READWRITE(vtx); + else if (fRead) + const_cast(this)->vtx.clear(); + ) + + void SetNull() + { + nVersion = 1; + hashPrevBlock = 0; + hashMerkleRoot = 0; + nTime = 0; + nBits = 0; + nNonce = 0; + vtx.clear(); + vMerkleTree.clear(); + } + + bool IsNull() const + { + return (nBits == 0); + } + + uint256 GetHash() const + { + return Hash(BEGIN(nVersion), END(nNonce)); + } + + + uint256 BuildMerkleTree() const + { + vMerkleTree.clear(); + foreach(const CTransaction& tx, vtx) + vMerkleTree.push_back(tx.GetHash()); + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = min(i+1, nSize-1); + vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), + BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); + } + j += nSize; + } + return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); + } + + vector GetMerkleBranch(int nIndex) const + { + if (vMerkleTree.empty()) + BuildMerkleTree(); + vector vMerkleBranch; + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = min(nIndex^1, nSize-1); + vMerkleBranch.push_back(vMerkleTree[j+i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; + } + + static uint256 CheckMerkleBranch(uint256 hash, const vector& vMerkleBranch, int nIndex) + { + if (nIndex == -1) + return 0; + foreach(const uint256& otherside, vMerkleBranch) + { + if (nIndex & 1) + hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + else + hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + nIndex >>= 1; + } + return hash; + } + + + bool WriteToDisk(bool fWriteTransactions, unsigned int& nFileRet, unsigned int& nBlockPosRet) + { + // Open history file to append + CAutoFile fileout = AppendBlockFile(nFileRet); + if (!fileout) + return error("CBlock::WriteToDisk() : AppendBlockFile failed"); + if (!fWriteTransactions) + fileout.nType |= SER_BLOCKHEADERONLY; + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(*this); + fileout << FLATDATA(pchMessageStart) << nSize; + + // Write block + nBlockPosRet = ftell(fileout); + if (nBlockPosRet == -1) + return error("CBlock::WriteToDisk() : ftell failed"); + fileout << *this; + + return true; + } + + bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions) + { + SetNull(); + + // Open history file to read + CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb"); + if (!filein) + return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); + if (!fReadTransactions) + filein.nType |= SER_BLOCKHEADERONLY; + + // Read block + filein >> *this; + + // Check the header + if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit) + return error("CBlock::ReadFromDisk() : nBits errors in block header"); + if (GetHash() > CBigNum().SetCompact(nBits).getuint256()) + return error("CBlock::ReadFromDisk() : GetHash() errors in block header"); + + return true; + } + + + + void print() const + { + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n", + GetHash().ToString().substr(0,14).c_str(), + nVersion, + hashPrevBlock.ToString().substr(0,14).c_str(), + hashMerkleRoot.ToString().substr(0,6).c_str(), + nTime, nBits, nNonce, + vtx.size()); + for (int i = 0; i < vtx.size(); i++) + { + printf(" "); + vtx[i].print(); + } + printf(" vMerkleTree: "); + for (int i = 0; i < vMerkleTree.size(); i++) + printf("%s ", vMerkleTree[i].ToString().substr(0,6).c_str()); + printf("\n"); + } + + + int64 GetBlockValue(int64 nFees) const; + bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); + bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex); + bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions); + bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); + bool CheckBlock() const; + bool AcceptBlock(); +}; + + + + + + +// +// The block chain is a tree shaped structure starting with the +// genesis block at the root, with each block potentially having multiple +// candidates to be the next block. pprev and pnext link a path through the +// main/longest chain. A blockindex may have multiple pprev pointing back +// to it, but pnext will only point forward to the longest branch, or will +// be null if the block is not part of the longest chain. +// +class CBlockIndex +{ +public: + const uint256* phashBlock; + CBlockIndex* pprev; + CBlockIndex* pnext; + unsigned int nFile; + unsigned int nBlockPos; + int nHeight; + + // block header + int nVersion; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + + + CBlockIndex() + { + phashBlock = NULL; + pprev = NULL; + pnext = NULL; + nFile = 0; + nBlockPos = 0; + nHeight = 0; + + nVersion = 0; + hashMerkleRoot = 0; + nTime = 0; + nBits = 0; + nNonce = 0; + } + + CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block) + { + phashBlock = NULL; + pprev = NULL; + pnext = NULL; + nFile = nFileIn; + nBlockPos = nBlockPosIn; + nHeight = 0; + + nVersion = block.nVersion; + hashMerkleRoot = block.hashMerkleRoot; + nTime = block.nTime; + nBits = block.nBits; + nNonce = block.nNonce; + } + + uint256 GetBlockHash() const + { + return *phashBlock; + } + + bool IsInMainChain() const + { + return (pnext || this == pindexBest); + } + + bool EraseBlockFromDisk() + { + // Open history file + CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+"); + if (!fileout) + return false; + + // Overwrite with empty null block + CBlock block; + block.SetNull(); + fileout << block; + + return true; + } + + enum { nMedianTimeSpan=11 }; + + int64 GetMedianTimePast() const + { + unsigned int pmedian[nMedianTimeSpan]; + unsigned int* pbegin = &pmedian[nMedianTimeSpan]; + unsigned int* pend = &pmedian[nMedianTimeSpan]; + + const CBlockIndex* pindex = this; + for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) + *(--pbegin) = pindex->nTime; + + sort(pbegin, pend); + return pbegin[(pend - pbegin)/2]; + } + + int64 GetMedianTime() const + { + const CBlockIndex* pindex = this; + for (int i = 0; i < nMedianTimeSpan/2; i++) + { + if (!pindex->pnext) + return nTime; + pindex = pindex->pnext; + } + return pindex->GetMedianTimePast(); + } + + + + string ToString() const + { + return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)", + pprev, pnext, nFile, nBlockPos, nHeight, + hashMerkleRoot.ToString().substr(0,6).c_str(), + GetBlockHash().ToString().substr(0,14).c_str()); + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + +// +// Used to marshal pointers into hashes for db storage. +// +class CDiskBlockIndex : public CBlockIndex +{ +public: + uint256 hashPrev; + uint256 hashNext; + + CDiskBlockIndex() + { + hashPrev = 0; + hashNext = 0; + } + + explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) + { + hashPrev = (pprev ? pprev->GetBlockHash() : 0); + hashNext = (pnext ? pnext->GetBlockHash() : 0); + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + + READWRITE(hashNext); + READWRITE(nFile); + READWRITE(nBlockPos); + READWRITE(nHeight); + + // block header + READWRITE(this->nVersion); + READWRITE(hashPrev); + READWRITE(hashMerkleRoot); + READWRITE(nTime); + READWRITE(nBits); + READWRITE(nNonce); + ) + + uint256 GetBlockHash() const + { + CBlock block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrev; + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block.GetHash(); + } + + + string ToString() const + { + string str = "CDiskBlockIndex("; + str += CBlockIndex::ToString(); + str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)", + GetBlockHash().ToString().c_str(), + hashPrev.ToString().substr(0,14).c_str(), + hashNext.ToString().substr(0,14).c_str()); + return str; + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + + + + + +// +// Describes a place in the block chain to another node such that if the +// other node doesn't have the same branch, it can find a recent common trunk. +// The further back it is, the further before the fork it may be. +// +class CBlockLocator +{ +protected: + vector vHave; +public: + + CBlockLocator() + { + } + + explicit CBlockLocator(const CBlockIndex* pindex) + { + Set(pindex); + } + + explicit CBlockLocator(uint256 hashBlock) + { + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end()) + Set((*mi).second); + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(vHave); + ) + + void Set(const CBlockIndex* pindex) + { + vHave.clear(); + int nStep = 1; + while (pindex) + { + vHave.push_back(pindex->GetBlockHash()); + + // Exponentially larger steps back + for (int i = 0; pindex && i < nStep; i++) + pindex = pindex->pprev; + if (vHave.size() > 10) + nStep *= 2; + } + vHave.push_back(hashGenesisBlock); + } + + CBlockIndex* GetBlockIndex() + { + // Find the first block the caller has in the main chain + foreach(const uint256& hash, vHave) + { + map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return pindex; + } + } + return pindexGenesisBlock; + } + + uint256 GetBlockHash() + { + // Find the first block the caller has in the main chain + foreach(const uint256& hash, vHave) + { + map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return hash; + } + } + return hashGenesisBlock; + } + + int GetHeight() + { + CBlockIndex* pindex = GetBlockIndex(); + if (!pindex) + return 0; + return pindex->nHeight; + } +}; + + + + + + + + + + + + +extern map mapTransactions; +extern map mapWallet; +extern vector > vWalletUpdated; +extern CCriticalSection cs_mapWallet; +extern map, CPrivKey> mapKeys; +extern map > mapPubKeys; +extern CCriticalSection cs_mapKeys; +extern CKey keyUser; diff --git a/makefile b/makefile new file mode 100644 index 000000000..534eb521e --- /dev/null +++ b/makefile @@ -0,0 +1,83 @@ +# Copyright (c) 2009 Satoshi Nakamoto +# Distributed under the MIT/X11 software license, see the accompanying +# file license.txt or http://www.opensource.org/licenses/mit-license.php. + + +ifneq "$(BUILD)" "debug" +ifneq "$(BUILD)" "release" +BUILD=debug +endif +endif +ifeq "$(BUILD)" "debug" +D=d +# note: gcc 3.x profile doesn't work +#DEBUGFLAGS=-O0 -g -pg -D__WXDEBUG__ +DEBUGFLAGS=-g -D__WXDEBUG__ +endif + + + +INCLUDEPATHS=-I"/boost" -I"/DB/build_unix" -I"/OpenSSL/include" -I"/wxWidgets/lib/vc_lib/mswd" -I"/wxWidgets/include" +LIBPATHS=-L"/DB/build_unix" -L"/OpenSSL/out" -L"/wxWidgets/lib/gcc_lib" +LIBS= \ + -l db_cxx \ + -l eay32 \ + -l wxmsw28$(D)_richtext -l wxmsw28$(D)_html -l wxmsw28$(D)_core -l wxbase28$(D) -l wxtiff$(D) -l wxjpeg$(D) -l wxpng$(D) -l wxzlib$(D) -l wxregex$(D) -l wxexpat$(D) \ + -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 +WXDEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH +CFLAGS=-mthreads -O0 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS) +HEADERS=headers.h util.h main.h serialize.h uint256.h key.h bignum.h script.h db.h base58.h + + + +all: bitcoin.exe + + +headers.h.gch: headers.h $(HEADERS) net.h irc.h market.h uibase.h ui.h + g++ -c $(CFLAGS) -o $@ $< + +obj/util.o: util.cpp $(HEADERS) + g++ -c $(CFLAGS) -o $@ $< + +obj/script.o: script.cpp $(HEADERS) + g++ -c $(CFLAGS) -o $@ $< + +obj/db.o: db.cpp $(HEADERS) market.h + g++ -c $(CFLAGS) -o $@ $< + +obj/net.o: net.cpp $(HEADERS) net.h + g++ -c $(CFLAGS) -o $@ $< + +obj/main.o: main.cpp $(HEADERS) net.h market.h sha.h + g++ -c $(CFLAGS) -o $@ $< + +obj/market.o: market.cpp $(HEADERS) market.h + g++ -c $(CFLAGS) -o $@ $< + +obj/ui.o: ui.cpp $(HEADERS) net.h uibase.h ui.h market.h + g++ -c $(CFLAGS) -o $@ $< + +obj/uibase.o: uibase.cpp uibase.h + g++ -c $(CFLAGS) -o $@ $< + +obj/sha.o: sha.cpp sha.h + g++ -c $(CFLAGS) -O3 -o $@ $< + +obj/irc.o: irc.cpp $(HEADERS) + g++ -c $(CFLAGS) -o $@ $< + +obj/ui_res.o: ui.rc rc/bitcoin.ico rc/check.ico rc/send16.bmp rc/send16mask.bmp rc/send16masknoshadow.bmp rc/send20.bmp rc/send20mask.bmp rc/addressbook16.bmp rc/addressbook16mask.bmp rc/addressbook20.bmp rc/addressbook20mask.bmp + windres $(WXDEFS) $(INCLUDEPATHS) -o $@ -i $< + + + +OBJS=obj/util.o obj/script.o obj/db.o obj/net.o obj/main.o obj/market.o \ + obj/ui.o obj/uibase.o obj/sha.o obj/irc.o obj/ui_res.o + +bitcoin.exe: headers.h.gch $(OBJS) + -kill /f bitcoin.exe + g++ $(CFLAGS) -mwindows -Wl,--subsystem,windows -o $@ $(LIBPATHS) $(OBJS) $(LIBS) + +clean: + -del /Q obj\* + -del /Q headers.h.gch diff --git a/makefile.vc b/makefile.vc new file mode 100644 index 000000000..bf7e9bc58 --- /dev/null +++ b/makefile.vc @@ -0,0 +1,77 @@ +# Copyright (c) 2009 Satoshi Nakamoto +# Distributed under the MIT/X11 software license, see the accompanying +# file license.txt or http://www.opensource.org/licenses/mit-license.php. + + +!IF "$(BUILD)" != "debug" && "$(BUILD)" != "release" +BUILD=debug +!ENDIF +!IF "$(BUILD)" == "debug" +D=d +DEBUGFLAGS=/Zi /Od /D__WXDEBUG__ +!ENDIF + + + +INCLUDEPATHS=/I"/boost" /I"/DB/build_windows" /I"/OpenSSL/include" /I"/wxWidgets/lib/vc_lib/mswd" /I"/wxWidgets/include" +LIBPATHS=/LIBPATH:"/DB/build_windows/$(BUILD)" /LIBPATH:"/OpenSSL/out" /LIBPATH:"/wxWidgets/lib/vc_lib" +LIBS= \ + libdb47s$(D).lib \ + libeay32.lib \ + wxmsw28$(D)_richtext.lib wxmsw28$(D)_html.lib wxmsw28$(D)_core.lib wxbase28$(D).lib wxtiff$(D).lib wxjpeg$(D).lib wxpng$(D).lib wxzlib$(D).lib wxregex$(D).lib wxexpat$(D).lib \ + kernel32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib shell32.lib comctl32.lib ole32.lib oleaut32.lib uuid.lib rpcrt4.lib advapi32.lib ws2_32.lib +WXDEFS=/DWIN32 /D__WXMSW__ /D_WINDOWS /DNOPCH +CFLAGS=/c /nologo /Ob0 /MD$(D) /EHsc /GR /Zm300 /YX /Fpobj/headers.pch $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS) +HEADERS=headers.h util.h main.h serialize.h uint256.h key.h bignum.h script.h db.h base58.h + + + +all: bitcoin.exe + + +obj\util.obj: util.cpp $(HEADERS) + cl $(CFLAGS) /Fo$@ %s + +obj\script.obj: script.cpp $(HEADERS) + cl $(CFLAGS) /Fo$@ %s + +obj\db.obj: db.cpp $(HEADERS) market.h + cl $(CFLAGS) /Fo$@ %s + +obj\net.obj: net.cpp $(HEADERS) net.h + cl $(CFLAGS) /Fo$@ %s + +obj\main.obj: main.cpp $(HEADERS) net.h market.h + cl $(CFLAGS) /Fo$@ %s + +obj\market.obj: market.cpp $(HEADERS) market.h + cl $(CFLAGS) /Fo$@ %s + +obj\ui.obj: ui.cpp $(HEADERS) net.h uibase.h ui.h market.h + cl $(CFLAGS) /Fo$@ %s + +obj\uibase.obj: uibase.cpp uibase.h + cl $(CFLAGS) /Fo$@ %s + +obj\sha.obj: sha.cpp sha.h + cl $(CFLAGS) /O2 /Fo$@ %s + +obj\irc.obj: irc.cpp $(HEADERS) + cl $(CFLAGS) /Fo$@ %s + +obj\ui.res: ui.rc rc/bitcoin.ico rc/check.ico rc/send16.bmp rc/send16mask.bmp rc/send16masknoshadow.bmp rc/send20.bmp rc/send20mask.bmp rc/addressbook16.bmp rc/addressbook16mask.bmp rc/addressbook20.bmp rc/addressbook20mask.bmp + rc $(INCLUDEPATHS) $(WXDEFS) /Fo$@ %s + + + +OBJS=obj\util.obj obj\script.obj obj\db.obj obj\net.obj obj\main.obj obj\market.obj \ + obj\ui.obj obj\uibase.obj obj\sha.obj obj\irc.obj obj\ui.res + +bitcoin.exe: $(OBJS) + -kill /f bitcoin.exe & sleep 1 + link /nologo /DEBUG /SUBSYSTEM:WINDOWS /OUT:$@ $(LIBPATHS) $** $(LIBS) + +clean: + -del /Q obj\* + -del *.ilk + -del *.pdb diff --git a/market.cpp b/market.cpp new file mode 100644 index 000000000..22b5365fa --- /dev/null +++ b/market.cpp @@ -0,0 +1,264 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" + + + + + + + + + + +// +// Global state variables +// + +//// later figure out how these are persisted +map mapMyProducts; + + + + +map mapProducts; +CCriticalSection cs_mapProducts; + +bool AdvertInsert(const CProduct& product) +{ + uint256 hash = product.GetHash(); + bool fNew = false; + bool fUpdated = false; + + CRITICAL_BLOCK(cs_mapProducts) + { + // Insert or find existing product + pair::iterator, bool> item = mapProducts.insert(make_pair(hash, product)); + CProduct* pproduct = &(*(item.first)).second; + fNew = item.second; + + // Update if newer + if (product.nSequence > pproduct->nSequence) + { + *pproduct = product; + fUpdated = true; + } + } + + //if (fNew) + // NotifyProductAdded(hash); + //else if (fUpdated) + // NotifyProductUpdated(hash); + + return (fNew || fUpdated); +} + +void AdvertErase(const CProduct& product) +{ + uint256 hash = product.GetHash(); + CRITICAL_BLOCK(cs_mapProducts) + mapProducts.erase(hash); + //NotifyProductDeleted(hash); +} + + + + + + + + + + + + + + + + + + + +template +unsigned int Union(T& v1, T& v2) +{ + // v1 = v1 union v2 + // v1 and v2 must be sorted + // returns the number of elements added to v1 + + ///// need to check that this is equivalent, then delete this comment + //vector vUnion(v1.size() + v2.size()); + //vUnion.erase(set_union(v1.begin(), v1.end(), + // v2.begin(), v2.end(), + // vUnion.begin()), + // vUnion.end()); + + T vUnion; + vUnion.reserve(v1.size() + v2.size()); + set_union(v1.begin(), v1.end(), + v2.begin(), v2.end(), + back_inserter(vUnion)); + unsigned int nAdded = vUnion.size() - v1.size(); + if (nAdded > 0) + v1 = vUnion; + return nAdded; +} + +void CUser::AddAtom(unsigned short nAtom, bool fOrigin) +{ + // Ignore duplicates + if (binary_search(vAtomsIn.begin(), vAtomsIn.end(), nAtom) || + find(vAtomsNew.begin(), vAtomsNew.end(), nAtom) != vAtomsNew.end()) + return; + + //// instead of zero atom, should change to free atom that propagates, + //// limited to lower than a certain value like 5 so conflicts quickly + // The zero atom never propagates, + // new atoms always propagate through the user that created them + if (nAtom == 0 || fOrigin) + { + vector vTmp(1, nAtom); + Union(vAtomsIn, vTmp); + if (fOrigin) + vAtomsOut.push_back(nAtom); + return; + } + + vAtomsNew.push_back(nAtom); + + if (vAtomsNew.size() >= nFlowthroughRate || vAtomsOut.empty()) + { + // Select atom to flow through to vAtomsOut + vAtomsOut.push_back(vAtomsNew[GetRand(vAtomsNew.size())]); + + // Merge vAtomsNew into vAtomsIn + sort(vAtomsNew.begin(), vAtomsNew.end()); + Union(vAtomsIn, vAtomsNew); + vAtomsNew.clear(); + } +} + +bool AddAtomsAndPropagate(uint256 hashUserStart, const vector& vAtoms, bool fOrigin) +{ + CReviewDB reviewdb; + map > pmapPropagate[2]; + pmapPropagate[0][hashUserStart] = vAtoms; + + for (int side = 0; !pmapPropagate[side].empty(); side = 1 - side) + { + map >& mapFrom = pmapPropagate[side]; + map >& mapTo = pmapPropagate[1 - side]; + + for (map >::iterator mi = mapFrom.begin(); mi != mapFrom.end(); ++mi) + { + const uint256& hashUser = (*mi).first; + const vector& vReceived = (*mi).second; + + ///// this would be a lot easier on the database if it put the new atom at the beginning of the list, + ///// so the change would be right next to the vector size. + + // Read user + CUser user; + reviewdb.ReadUser(hashUser, user); + unsigned int nIn = user.vAtomsIn.size(); + unsigned int nNew = user.vAtomsNew.size(); + unsigned int nOut = user.vAtomsOut.size(); + + // Add atoms received + foreach(unsigned short nAtom, vReceived) + user.AddAtom(nAtom, fOrigin); + fOrigin = false; + + // Don't bother writing to disk if no changes + if (user.vAtomsIn.size() == nIn && user.vAtomsNew.size() == nNew) + continue; + + // Propagate + if (user.vAtomsOut.size() > nOut) + foreach(const uint256& hash, user.vLinksOut) + mapTo[hash].insert(mapTo[hash].end(), user.vAtomsOut.begin() + nOut, user.vAtomsOut.end()); + + // Write back + if (!reviewdb.WriteUser(hashUser, user)) + return false; + } + mapFrom.clear(); + } + return true; +} + + + + + + +bool CReview::AcceptReview() +{ + // Timestamp + nTime = GetTime(); + + // Check signature + if (!CKey::Verify(vchPubKeyFrom, GetSigHash(), vchSig)) + return false; + + CReviewDB reviewdb; + + // Add review text to recipient + vector vReviews; + reviewdb.ReadReviews(hashTo, vReviews); + vReviews.push_back(*this); + if (!reviewdb.WriteReviews(hashTo, vReviews)) + return false; + + // Add link from sender + CUser user; + uint256 hashFrom = Hash(vchPubKeyFrom.begin(), vchPubKeyFrom.end()); + reviewdb.ReadUser(hashFrom, user); + user.vLinksOut.push_back(hashTo); + if (!reviewdb.WriteUser(hashFrom, user)) + return false; + + reviewdb.Close(); + + // Propagate atoms to recipient + vector vZeroAtom(1, 0); + if (!AddAtomsAndPropagate(hashTo, user.vAtomsOut.size() ? user.vAtomsOut : vZeroAtom, false)) + return false; + + return true; +} + + + + + +bool CProduct::CheckSignature() +{ + return (CKey::Verify(vchPubKeyFrom, GetSigHash(), vchSig)); +} + +bool CProduct::CheckProduct() +{ + if (!CheckSignature()) + return false; + + // Make sure it's a summary product + if (!mapDetails.empty() || !vOrderForm.empty()) + return false; + + // Look up seller's atom count + CReviewDB reviewdb("r"); + CUser user; + reviewdb.ReadUser(GetUserHash(), user); + nAtoms = user.GetAtomCount(); + reviewdb.Close(); + + ////// delme, this is now done by AdvertInsert + //// Store to memory + //CRITICAL_BLOCK(cs_mapProducts) + // mapProducts[GetHash()] = *this; + + return true; +} diff --git a/market.h b/market.h new file mode 100644 index 000000000..271478730 --- /dev/null +++ b/market.h @@ -0,0 +1,182 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +class CUser; +class CReview; +class CProduct; + +static const unsigned int nFlowthroughRate = 2; + + + + +bool AdvertInsert(const CProduct& product); +void AdvertErase(const CProduct& product); +bool AddAtomsAndPropagate(uint256 hashUserStart, const vector& vAtoms, bool fOrigin); + + + + + + + + +class CUser +{ +public: + vector vAtomsIn; + vector vAtomsNew; + vector vAtomsOut; + vector vLinksOut; + + CUser() + { + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(vAtomsIn); + READWRITE(vAtomsNew); + READWRITE(vAtomsOut); + READWRITE(vLinksOut); + ) + + void SetNull() + { + vAtomsIn.clear(); + vAtomsNew.clear(); + vAtomsOut.clear(); + vLinksOut.clear(); + } + + uint256 GetHash() const { return SerializeHash(*this); } + + + int GetAtomCount() const + { + return (vAtomsIn.size() + vAtomsNew.size()); + } + + void AddAtom(unsigned short nAtom, bool fOrigin); +}; + + + + + + + +class CReview +{ +public: + int nVersion; + uint256 hashTo; + map mapValue; + vector vchPubKeyFrom; + vector vchSig; + + // memory only + unsigned int nTime; + int nAtoms; + + + CReview() + { + nVersion = 1; + hashTo = 0; + nTime = 0; + nAtoms = 0; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + if (!(nType & SER_DISK)) + READWRITE(hashTo); + READWRITE(mapValue); + READWRITE(vchPubKeyFrom); + if (!(nType & SER_GETHASH)) + READWRITE(vchSig); + ) + + uint256 GetHash() const { return SerializeHash(*this); } + uint256 GetSigHash() const { return SerializeHash(*this, SER_GETHASH|SER_SKIPSIG); } + uint256 GetUserHash() const { return Hash(vchPubKeyFrom.begin(), vchPubKeyFrom.end()); } + + + bool AcceptReview(); +}; + + + + + + + +class CProduct +{ +public: + int nVersion; + CAddress addr; + map mapValue; + map mapDetails; + vector > vOrderForm; + unsigned int nSequence; + vector vchPubKeyFrom; + vector vchSig; + + // disk only + int nAtoms; + + // memory only + set setSources; + + CProduct() + { + nVersion = 1; + nAtoms = 0; + nSequence = 0; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(addr); + READWRITE(mapValue); + if (!(nType & SER_GETHASH)) + { + READWRITE(mapDetails); + READWRITE(vOrderForm); + READWRITE(nSequence); + } + READWRITE(vchPubKeyFrom); + if (!(nType & SER_GETHASH)) + READWRITE(vchSig); + if (nType & SER_DISK) + READWRITE(nAtoms); + ) + + uint256 GetHash() const { return SerializeHash(*this); } + uint256 GetSigHash() const { return SerializeHash(*this, SER_GETHASH|SER_SKIPSIG); } + uint256 GetUserHash() const { return Hash(vchPubKeyFrom.begin(), vchPubKeyFrom.end()); } + + + bool CheckSignature(); + bool CheckProduct(); +}; + + + + + + + + +extern map mapProducts; +extern CCriticalSection cs_mapProducts; +extern map mapMyProducts; diff --git a/mingwm10.dll b/mingwm10.dll new file mode 100644 index 0000000000000000000000000000000000000000..bf8544ce13ad82018a4aa13abc1594297e4d891b GIT binary patch literal 11673 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 x4(UFf=#(JFDkOW?G&iQ|nyfl8)l*8X1Z) + +void ThreadMessageHandler2(void* parg); +void ThreadSocketHandler2(void* parg); +void ThreadOpenConnections2(void* parg); + + + + + + +// +// Global state variables +// +bool fClient = false; +uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); +CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices); +CNode nodeLocalHost(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices)); +CNode* pnodeLocalHost = &nodeLocalHost; +bool fShutdown = false; +array vfThreadRunning; +vector vNodes; +CCriticalSection cs_vNodes; +map, CAddress> mapAddresses; +CCriticalSection cs_mapAddresses; +map mapRelay; +deque > vRelayExpiration; +CCriticalSection cs_mapRelay; +map mapAlreadyAskedFor; + + + +CAddress addrProxy; + +bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) +{ + hSocketRet = INVALID_SOCKET; + + SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (hSocket == INVALID_SOCKET) + return false; + + bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168)); + bool fProxy = (addrProxy.ip && fRoutable); + struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr()); + + if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) + { + closesocket(hSocket); + return false; + } + + if (fProxy) + { + printf("Proxy connecting to %s\n", addrConnect.ToString().c_str()); + char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; + memcpy(pszSocks4IP + 2, &addrConnect.port, 2); + memcpy(pszSocks4IP + 4, &addrConnect.ip, 4); + char* pszSocks4 = pszSocks4IP; + int nSize = sizeof(pszSocks4IP); + + int ret = send(hSocket, pszSocks4, nSize, 0); + if (ret != nSize) + { + closesocket(hSocket); + return error("Error sending to proxy\n"); + } + char pchRet[8]; + if (recv(hSocket, pchRet, 8, 0) != 8) + { + closesocket(hSocket); + return error("Error reading proxy response\n"); + } + if (pchRet[1] != 0x5a) + { + closesocket(hSocket); + return error("Proxy returned error %d\n", pchRet[1]); + } + printf("Proxy connection established %s\n", addrConnect.ToString().c_str()); + } + + hSocketRet = hSocket; + return true; +} + + + +bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet) +{ + SOCKET hSocket; + if (!ConnectSocket(addrConnect, hSocket)) + return error("GetMyExternalIP() : connection to %s failed\n", addrConnect.ToString().c_str()); + + send(hSocket, pszGet, strlen(pszGet), 0); + + string strLine; + while (RecvLine(hSocket, strLine)) + { + if (strLine.empty()) + { + loop + { + if (!RecvLine(hSocket, strLine)) + { + closesocket(hSocket); + return false; + } + if (strLine.find(pszKeyword) != -1) + { + strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword)); + break; + } + } + closesocket(hSocket); + if (strLine.find("<")) + strLine = strLine.substr(0, strLine.find("<")); + strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); + strLine = wxString(strLine).Trim(); + CAddress addr(strLine.c_str()); + printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); + if (addr.ip == 0 || !addr.IsRoutable()) + return false; + ipRet = addr.ip; + return true; + } + } + closesocket(hSocket); + return error("GetMyExternalIP() : connection closed\n"); +} + + +bool GetMyExternalIP(unsigned int& ipRet) +{ + CAddress addrConnect; + char* pszGet; + char* pszKeyword; + + for (int nLookup = 0; nLookup <= 1; nLookup++) + for (int nHost = 1; nHost <= 2; nHost++) + { + if (nHost == 1) + { + addrConnect = CAddress("70.86.96.218:80"); // www.ipaddressworld.com + + if (nLookup == 1) + { + struct hostent* phostent = gethostbyname("www.ipaddressworld.com"); + if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) + addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80)); + } + + pszGet = "GET /ip.php HTTP/1.1\r\n" + "Host: www.ipaddressworld.com\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" + "Connection: close\r\n" + "\r\n"; + + pszKeyword = "IP:"; + } + else if (nHost == 2) + { + addrConnect = CAddress("208.78.68.70:80"); // checkip.dyndns.org + + if (nLookup == 1) + { + struct hostent* phostent = gethostbyname("checkip.dyndns.org"); + if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) + addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80)); + } + + pszGet = "GET / HTTP/1.1\r\n" + "Host: checkip.dyndns.org\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" + "Connection: close\r\n" + "\r\n"; + + pszKeyword = "Address:"; + } + + if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet)) + return true; + } + + return false; +} + + + + + +bool AddAddress(CAddrDB& addrdb, const CAddress& addr) +{ + if (!addr.IsRoutable()) + return false; + if (addr.ip == addrLocalHost.ip) + return false; + CRITICAL_BLOCK(cs_mapAddresses) + { + map, CAddress>::iterator it = mapAddresses.find(addr.GetKey()); + if (it == mapAddresses.end()) + { + // New address + mapAddresses.insert(make_pair(addr.GetKey(), addr)); + addrdb.WriteAddress(addr); + return true; + } + else + { + CAddress& addrFound = (*it).second; + if ((addrFound.nServices | addr.nServices) != addrFound.nServices) + { + // Services have been added + addrFound.nServices |= addr.nServices; + addrdb.WriteAddress(addrFound); + return true; + } + } + } + return false; +} + + + + + +void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1) +{ + // If the dialog might get closed before the reply comes back, + // call this in the destructor so it doesn't get called after it's deleted. + CRITICAL_BLOCK(cs_vNodes) + { + foreach(CNode* pnode, vNodes) + { + CRITICAL_BLOCK(pnode->cs_mapRequests) + { + for (map::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();) + { + CRequestTracker& tracker = (*mi).second; + if (tracker.fn == fn && tracker.param1 == param1) + pnode->mapRequests.erase(mi++); + else + mi++; + } + } + } + } +} + + + + + + + +// +// Subscription methods for the broadcast and subscription system. +// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT. +// +// The subscription system uses a meet-in-the-middle strategy. +// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers +// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through. +// + +bool AnySubscribed(unsigned int nChannel) +{ + if (pnodeLocalHost->IsSubscribed(nChannel)) + return true; + CRITICAL_BLOCK(cs_vNodes) + foreach(CNode* pnode, vNodes) + if (pnode->IsSubscribed(nChannel)) + return true; + return false; +} + +bool CNode::IsSubscribed(unsigned int nChannel) +{ + if (nChannel >= vfSubscribe.size()) + return false; + return vfSubscribe[nChannel]; +} + +void CNode::Subscribe(unsigned int nChannel, unsigned int nHops) +{ + if (nChannel >= vfSubscribe.size()) + return; + + if (!AnySubscribed(nChannel)) + { + // Relay subscribe + CRITICAL_BLOCK(cs_vNodes) + foreach(CNode* pnode, vNodes) + if (pnode != this) + pnode->PushMessage("subscribe", nChannel, nHops); + } + + vfSubscribe[nChannel] = true; +} + +void CNode::CancelSubscribe(unsigned int nChannel) +{ + if (nChannel >= vfSubscribe.size()) + return; + + // Prevent from relaying cancel if wasn't subscribed + if (!vfSubscribe[nChannel]) + return; + vfSubscribe[nChannel] = false; + + if (!AnySubscribed(nChannel)) + { + // Relay subscription cancel + CRITICAL_BLOCK(cs_vNodes) + foreach(CNode* pnode, vNodes) + if (pnode != this) + pnode->PushMessage("sub-cancel", nChannel); + + // Clear memory, no longer subscribed + if (nChannel == MSG_PRODUCT) + CRITICAL_BLOCK(cs_mapProducts) + mapProducts.clear(); + } +} + + + + + + + + + +CNode* FindNode(unsigned int ip) +{ + CRITICAL_BLOCK(cs_vNodes) + { + foreach(CNode* pnode, vNodes) + if (pnode->addr.ip == ip) + return (pnode); + } + return NULL; +} + +CNode* FindNode(CAddress addr) +{ + CRITICAL_BLOCK(cs_vNodes) + { + foreach(CNode* pnode, vNodes) + if (pnode->addr == addr) + return (pnode); + } + return NULL; +} + +CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) +{ + if (addrConnect.ip == addrLocalHost.ip) + return NULL; + + // Look for an existing connection + CNode* pnode = FindNode(addrConnect.ip); + if (pnode) + { + if (nTimeout != 0) + pnode->AddRef(nTimeout); + else + pnode->AddRef(); + return pnode; + } + + /// debug print + printf("trying %s\n", addrConnect.ToString().c_str()); + + // Connect + SOCKET hSocket; + if (ConnectSocket(addrConnect, hSocket)) + { + /// debug print + printf("connected %s\n", addrConnect.ToString().c_str()); + + // Set to nonblocking + u_long nOne = 1; + if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) + printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError()); + + // Add node + CNode* pnode = new CNode(hSocket, addrConnect, false); + if (nTimeout != 0) + pnode->AddRef(nTimeout); + else + pnode->AddRef(); + CRITICAL_BLOCK(cs_vNodes) + vNodes.push_back(pnode); + + CRITICAL_BLOCK(cs_mapAddresses) + mapAddresses[addrConnect.GetKey()].nLastFailed = 0; + return pnode; + } + else + { + CRITICAL_BLOCK(cs_mapAddresses) + mapAddresses[addrConnect.GetKey()].nLastFailed = GetTime(); + return NULL; + } +} + +void CNode::Disconnect() +{ + printf("disconnecting node %s\n", addr.ToString().c_str()); + + closesocket(hSocket); + + // If outbound and never got version message, mark address as failed + if (!fInbound && nVersion == 0) + CRITICAL_BLOCK(cs_mapAddresses) + mapAddresses[addr.GetKey()].nLastFailed = GetTime(); + + // All of a nodes broadcasts and subscriptions are automatically torn down + // when it goes down, so a node has to stay up to keep its broadcast going. + + CRITICAL_BLOCK(cs_mapProducts) + for (map::iterator mi = mapProducts.begin(); mi != mapProducts.end();) + AdvertRemoveSource(this, MSG_PRODUCT, 0, (*(mi++)).second); + + // Cancel subscriptions + for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++) + if (vfSubscribe[nChannel]) + CancelSubscribe(nChannel); +} + + + + + + + + + + + + + +void ThreadSocketHandler(void* parg) +{ + IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg)); + + loop + { + vfThreadRunning[0] = true; + CheckForShutdown(0); + try + { + ThreadSocketHandler2(parg); + } + CATCH_PRINT_EXCEPTION("ThreadSocketHandler()") + vfThreadRunning[0] = false; + Sleep(5000); + } +} + +void ThreadSocketHandler2(void* parg) +{ + printf("ThreadSocketHandler started\n"); + SOCKET hListenSocket = *(SOCKET*)parg; + list vNodesDisconnected; + int nPrevNodeCount = 0; + + loop + { + // + // Disconnect nodes + // + CRITICAL_BLOCK(cs_vNodes) + { + // Disconnect unused nodes + vector vNodesCopy = vNodes; + foreach(CNode* pnode, vNodesCopy) + { + if (pnode->ReadyToDisconnect() && pnode->vRecv.empty() && pnode->vSend.empty()) + { + // remove from vNodes + vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); + pnode->Disconnect(); + + // hold in disconnected pool until all refs are released + pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 5 * 60); + if (pnode->fNetworkNode) + pnode->Release(); + vNodesDisconnected.push_back(pnode); + } + } + + // Delete disconnected nodes + list vNodesDisconnectedCopy = vNodesDisconnected; + foreach(CNode* pnode, vNodesDisconnectedCopy) + { + // wait until threads are done using it + if (pnode->GetRefCount() <= 0) + { + bool fDelete = false; + TRY_CRITICAL_BLOCK(pnode->cs_vSend) + TRY_CRITICAL_BLOCK(pnode->cs_vRecv) + TRY_CRITICAL_BLOCK(pnode->cs_mapRequests) + TRY_CRITICAL_BLOCK(pnode->cs_inventory) + fDelete = true; + if (fDelete) + { + vNodesDisconnected.remove(pnode); + delete pnode; + } + } + } + } + if (vNodes.size() != nPrevNodeCount) + { + nPrevNodeCount = vNodes.size(); + MainFrameRepaint(); + } + + + // + // Find which sockets have data to receive + // + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // frequency to poll pnode->vSend + + struct fd_set fdsetRecv; + struct fd_set fdsetSend; + FD_ZERO(&fdsetRecv); + FD_ZERO(&fdsetSend); + SOCKET hSocketMax = 0; + FD_SET(hListenSocket, &fdsetRecv); + hSocketMax = max(hSocketMax, hListenSocket); + CRITICAL_BLOCK(cs_vNodes) + { + foreach(CNode* pnode, vNodes) + { + FD_SET(pnode->hSocket, &fdsetRecv); + hSocketMax = max(hSocketMax, pnode->hSocket); + TRY_CRITICAL_BLOCK(pnode->cs_vSend) + if (!pnode->vSend.empty()) + FD_SET(pnode->hSocket, &fdsetSend); + } + } + + vfThreadRunning[0] = false; + int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, NULL, &timeout); + vfThreadRunning[0] = true; + CheckForShutdown(0); + if (nSelect == SOCKET_ERROR) + { + int nErr = WSAGetLastError(); + printf("select failed: %d\n", nErr); + for (int i = 0; i <= hSocketMax; i++) + { + FD_SET(i, &fdsetRecv); + FD_SET(i, &fdsetSend); + } + Sleep(timeout.tv_usec/1000); + } + RandAddSeed(); + + //// debug print + //foreach(CNode* pnode, vNodes) + //{ + // printf("vRecv = %-5d ", pnode->vRecv.size()); + // printf("vSend = %-5d ", pnode->vSend.size()); + //} + //printf("\n"); + + + // + // Accept new connections + // + if (FD_ISSET(hListenSocket, &fdsetRecv)) + { + struct sockaddr_in sockaddr; + int len = sizeof(sockaddr); + SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); + CAddress addr(sockaddr); + if (hSocket == INVALID_SOCKET) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + printf("ERROR ThreadSocketHandler accept failed: %d\n", WSAGetLastError()); + } + else + { + printf("accepted connection from %s\n", addr.ToString().c_str()); + CNode* pnode = new CNode(hSocket, addr, true); + pnode->AddRef(); + CRITICAL_BLOCK(cs_vNodes) + vNodes.push_back(pnode); + } + } + + + // + // Service each socket + // + vector vNodesCopy; + CRITICAL_BLOCK(cs_vNodes) + vNodesCopy = vNodes; + foreach(CNode* pnode, vNodesCopy) + { + CheckForShutdown(0); + SOCKET hSocket = pnode->hSocket; + + // + // Receive + // + if (FD_ISSET(hSocket, &fdsetRecv)) + { + TRY_CRITICAL_BLOCK(pnode->cs_vRecv) + { + CDataStream& vRecv = pnode->vRecv; + unsigned int nPos = vRecv.size(); + + // typical socket buffer is 8K-64K + const unsigned int nBufSize = 0x10000; + vRecv.resize(nPos + nBufSize); + int nBytes = recv(hSocket, &vRecv[nPos], nBufSize, 0); + vRecv.resize(nPos + max(nBytes, 0)); + if (nBytes == 0) + { + // socket closed gracefully + if (!pnode->fDisconnect) + printf("recv: socket closed\n"); + pnode->fDisconnect = true; + } + else if (nBytes < 0) + { + // socket error + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + { + if (!pnode->fDisconnect) + printf("recv failed: %d\n", nErr); + pnode->fDisconnect = true; + } + } + } + } + + // + // Send + // + if (FD_ISSET(hSocket, &fdsetSend)) + { + TRY_CRITICAL_BLOCK(pnode->cs_vSend) + { + CDataStream& vSend = pnode->vSend; + if (!vSend.empty()) + { + int nBytes = send(hSocket, &vSend[0], vSend.size(), 0); + if (nBytes > 0) + { + vSend.erase(vSend.begin(), vSend.begin() + nBytes); + } + else if (nBytes == 0) + { + if (pnode->ReadyToDisconnect()) + pnode->vSend.clear(); + } + else + { + printf("send error %d\n", nBytes); + if (pnode->ReadyToDisconnect()) + pnode->vSend.clear(); + } + } + } + } + } + + + Sleep(10); + } +} + + + + + + + + + + +void ThreadOpenConnections(void* parg) +{ + IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg)); + + loop + { + vfThreadRunning[1] = true; + CheckForShutdown(1); + try + { + ThreadOpenConnections2(parg); + } + CATCH_PRINT_EXCEPTION("ThreadOpenConnections()") + vfThreadRunning[1] = false; + Sleep(5000); + } +} + +void ThreadOpenConnections2(void* parg) +{ + printf("ThreadOpenConnections started\n"); + + // Initiate network connections + int nTry = 0; + bool fIRCOnly = false; + const int nMaxConnections = 15; + loop + { + // Wait + vfThreadRunning[1] = false; + Sleep(500); + while (vNodes.size() >= nMaxConnections || vNodes.size() >= mapAddresses.size()) + { + CheckForShutdown(1); + Sleep(2000); + } + vfThreadRunning[1] = true; + CheckForShutdown(1); + + + // + // The IP selection process is designed to limit vulnerability to address flooding. + // Any class C (a.b.c.?) has an equal chance of being chosen, then an IP is + // chosen within the class C. An attacker may be able to allocate many IPs, but + // they would normally be concentrated in blocks of class C's. They can hog the + // attention within their class C, but not the whole IP address space overall. + // A lone node in a class C will get as much attention as someone holding all 255 + // IPs in another class C. + // + + // Every other try is with IRC addresses only + fIRCOnly = !fIRCOnly; + if (mapIRCAddresses.empty()) + fIRCOnly = false; + else if (nTry++ < 30 && vNodes.size() < nMaxConnections/2) + fIRCOnly = true; + + // Make a list of unique class C's + unsigned char pchIPCMask[4] = { 0xff, 0xff, 0xff, 0x00 }; + unsigned int nIPCMask = *(unsigned int*)pchIPCMask; + vector vIPC; + CRITICAL_BLOCK(cs_mapIRCAddresses) + CRITICAL_BLOCK(cs_mapAddresses) + { + vIPC.reserve(mapAddresses.size()); + unsigned int nPrev = 0; + foreach(const PAIRTYPE(vector, CAddress)& item, mapAddresses) + { + const CAddress& addr = item.second; + if (!addr.IsIPv4()) + continue; + if (fIRCOnly && !mapIRCAddresses.count(item.first)) + continue; + + // Taking advantage of mapAddresses being in sorted order, + // with IPs of the same class C grouped together. + unsigned int ipC = addr.ip & nIPCMask; + if (ipC != nPrev) + vIPC.push_back(nPrev = ipC); + } + } + if (vIPC.empty()) + continue; + + // Choose a random class C + unsigned int ipC = vIPC[GetRand(vIPC.size())]; + + // Organize all addresses in the class C by IP + map > mapIP; + CRITICAL_BLOCK(cs_mapIRCAddresses) + CRITICAL_BLOCK(cs_mapAddresses) + { + int64 nDelay = ((30 * 60) << vNodes.size()); + if (!fIRCOnly) + { + nDelay *= 2; + if (vNodes.size() >= 3) + nDelay *= 4; + if (!mapIRCAddresses.empty()) + nDelay *= 100; + } + + for (map, CAddress>::iterator mi = mapAddresses.lower_bound(CAddress(ipC, 0).GetKey()); + mi != mapAddresses.upper_bound(CAddress(ipC | ~nIPCMask, 0xffff).GetKey()); + ++mi) + { + const CAddress& addr = (*mi).second; + if (fIRCOnly && !mapIRCAddresses.count((*mi).first)) + continue; + + int64 nRandomizer = (addr.nLastFailed * addr.ip * 7777U) % 20000; + if (GetTime() - addr.nLastFailed > nDelay * nRandomizer / 10000) + mapIP[addr.ip].push_back(addr); + } + } + if (mapIP.empty()) + continue; + + // Choose a random IP in the class C + map >::iterator mi = mapIP.begin(); + advance(mi, GetRand(mapIP.size())); + + // Once we've chosen an IP, we'll try every given port before moving on + foreach(const CAddress& addrConnect, (*mi).second) + { + // + // Initiate outbound network connection + // + CheckForShutdown(1); + if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip)) + continue; + + vfThreadRunning[1] = false; + CNode* pnode = ConnectNode(addrConnect); + vfThreadRunning[1] = true; + CheckForShutdown(1); + if (!pnode) + continue; + pnode->fNetworkNode = true; + + if (addrLocalHost.IsRoutable()) + { + // Advertise our address + vector vAddrToSend; + vAddrToSend.push_back(addrLocalHost); + pnode->PushMessage("addr", vAddrToSend); + } + + // Get as many addresses as we can + pnode->PushMessage("getaddr"); + + ////// should the one on the receiving end do this too? + // Subscribe our local subscription list + const unsigned int nHops = 0; + for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++) + if (pnodeLocalHost->vfSubscribe[nChannel]) + pnode->PushMessage("subscribe", nChannel, nHops); + + break; + } + } +} + + + + + + + + +void ThreadMessageHandler(void* parg) +{ + IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg)); + + loop + { + vfThreadRunning[2] = true; + CheckForShutdown(2); + try + { + ThreadMessageHandler2(parg); + } + CATCH_PRINT_EXCEPTION("ThreadMessageHandler()") + vfThreadRunning[2] = false; + Sleep(5000); + } +} + +void ThreadMessageHandler2(void* parg) +{ + printf("ThreadMessageHandler started\n"); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); + loop + { + // Poll the connected nodes for messages + vector vNodesCopy; + CRITICAL_BLOCK(cs_vNodes) + vNodesCopy = vNodes; + foreach(CNode* pnode, vNodesCopy) + { + pnode->AddRef(); + + // Receive messages + TRY_CRITICAL_BLOCK(pnode->cs_vRecv) + ProcessMessages(pnode); + + // Send messages + TRY_CRITICAL_BLOCK(pnode->cs_vSend) + SendMessages(pnode); + + pnode->Release(); + } + + // Wait and allow messages to bunch up + vfThreadRunning[2] = false; + Sleep(100); + vfThreadRunning[2] = true; + CheckForShutdown(2); + } +} + + + + + + + + + +//// todo: start one thread per processor, use getenv("NUMBER_OF_PROCESSORS") +void ThreadBitcoinMiner(void* parg) +{ + vfThreadRunning[3] = true; + CheckForShutdown(3); + try + { + bool fRet = BitcoinMiner(); + printf("BitcoinMiner returned %s\n\n\n", fRet ? "true" : "false"); + } + CATCH_PRINT_EXCEPTION("BitcoinMiner()") + vfThreadRunning[3] = false; +} + + + + + + + + + + + +bool StartNode(string& strError) +{ + strError = ""; + + // Sockets startup + WSADATA wsadata; + int ret = WSAStartup(MAKEWORD(2,2), &wsadata); + if (ret != NO_ERROR) + { + strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret); + printf("%s\n", strError.c_str()); + return false; + } + + // Get local host ip + char pszHostName[255]; + if (gethostname(pszHostName, 255) == SOCKET_ERROR) + { + strError = strprintf("Error: Unable to get IP address of this computer (gethostname returned error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + struct hostent* phostent = gethostbyname(pszHostName); + if (!phostent) + { + strError = strprintf("Error: Unable to get IP address of this computer (gethostbyname returned error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + addrLocalHost = CAddress(*(long*)(phostent->h_addr_list[0]), + DEFAULT_PORT, + nLocalServices); + printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); + + // Create socket for listening for incoming connections + SOCKET hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (hListenSocket == INVALID_SOCKET) + { + strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + + // Set to nonblocking, incoming connections will also inherit this + u_long nOne = 1; + if (ioctlsocket(hListenSocket, FIONBIO, &nOne) == SOCKET_ERROR) + { + strError = strprintf("Error: Couldn't set properties on socket for incoming connections (ioctlsocket returned error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + + // The sockaddr_in structure specifies the address family, + // IP address, and port for the socket that is being bound + int nRetryLimit = 15; + struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr(); + if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) + { + int nErr = WSAGetLastError(); + if (nErr == WSAEADDRINUSE) + strError = strprintf("Error: Unable to bind to port %s on this computer. The program is probably already running.", addrLocalHost.ToString().c_str()); + else + strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr); + printf("%s\n", strError.c_str()); + return false; + } + printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str()); + + // Listen for incoming connections + if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) + { + strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + + // Get our external IP address for incoming connections + if (addrIncoming.ip) + addrLocalHost.ip = addrIncoming.ip; + + if (GetMyExternalIP(addrLocalHost.ip)) + { + addrIncoming = addrLocalHost; + CWalletDB().WriteSetting("addrIncoming", addrIncoming); + } + + // Get addresses from IRC and advertise ours + if (_beginthread(ThreadIRCSeed, 0, NULL) == -1) + printf("Error: _beginthread(ThreadIRCSeed) failed\n"); + + // + // Start threads + // + if (_beginthread(ThreadSocketHandler, 0, new SOCKET(hListenSocket)) == -1) + { + strError = "Error: _beginthread(ThreadSocketHandler) failed"; + printf("%s\n", strError.c_str()); + return false; + } + + if (_beginthread(ThreadOpenConnections, 0, NULL) == -1) + { + strError = "Error: _beginthread(ThreadOpenConnections) failed"; + printf("%s\n", strError.c_str()); + return false; + } + + if (_beginthread(ThreadMessageHandler, 0, NULL) == -1) + { + strError = "Error: _beginthread(ThreadMessageHandler) failed"; + printf("%s\n", strError.c_str()); + return false; + } + + return true; +} + +bool StopNode() +{ + printf("StopNode()\n"); + fShutdown = true; + nTransactionsUpdated++; + int64 nStart = GetTime(); + while (vfThreadRunning[0] || vfThreadRunning[2] || vfThreadRunning[3]) + { + if (GetTime() - nStart > 15) + break; + Sleep(20); + } + if (vfThreadRunning[0]) printf("ThreadSocketHandler still running\n"); + if (vfThreadRunning[1]) printf("ThreadOpenConnections still running\n"); + if (vfThreadRunning[2]) printf("ThreadMessageHandler still running\n"); + if (vfThreadRunning[3]) printf("ThreadBitcoinMiner still running\n"); + while (vfThreadRunning[2]) + Sleep(20); + Sleep(50); + + // Sockets shutdown + WSACleanup(); + return true; +} + +void CheckForShutdown(int n) +{ + if (fShutdown) + { + if (n != -1) + vfThreadRunning[n] = false; + if (n == 0) + foreach(CNode* pnode, vNodes) + closesocket(pnode->hSocket); + _endthread(); + } +} diff --git a/net.h b/net.h new file mode 100644 index 000000000..cd311fc50 --- /dev/null +++ b/net.h @@ -0,0 +1,856 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +class CMessageHeader; +class CAddress; +class CInv; +class CRequestTracker; +class CNode; + + + +static const unsigned short DEFAULT_PORT = htons(8333); +static const unsigned int PUBLISH_HOPS = 5; +enum +{ + NODE_NETWORK = (1 << 0), +}; + + + + + + +bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet); +bool GetMyExternalIP(unsigned int& ipRet); +bool AddAddress(CAddrDB& addrdb, const CAddress& addr); +CNode* FindNode(unsigned int ip); +CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0); +void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); +bool AnySubscribed(unsigned int nChannel); +void ThreadBitcoinMiner(void* parg); +bool StartNode(string& strError=REF(string())); +bool StopNode(); +void CheckForShutdown(int n); + + + + + + + + + +// +// Message header +// (4) message start +// (12) command +// (4) size + +// The message start string is designed to be unlikely to occur in normal data. +// The characters are rarely used upper ascii, not valid as UTF-8, and produce +// a large 4-byte int at any alignment. +static const char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; + +class CMessageHeader +{ +public: + enum { COMMAND_SIZE=12 }; + char pchMessageStart[sizeof(::pchMessageStart)]; + char pchCommand[COMMAND_SIZE]; + unsigned int nMessageSize; + + CMessageHeader() + { + memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); + memset(pchCommand, 0, sizeof(pchCommand)); + pchCommand[1] = 1; + nMessageSize = -1; + } + + CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) + { + memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); + strncpy(pchCommand, pszCommand, COMMAND_SIZE); + nMessageSize = nMessageSizeIn; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(FLATDATA(pchMessageStart)); + READWRITE(FLATDATA(pchCommand)); + READWRITE(nMessageSize); + ) + + string GetCommand() + { + if (pchCommand[COMMAND_SIZE-1] == 0) + return string(pchCommand, pchCommand + strlen(pchCommand)); + else + return string(pchCommand, pchCommand + COMMAND_SIZE); + } + + bool IsValid() + { + // Check start string + if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) + return false; + + // Check the command string for errors + for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++) + { + if (*p1 == 0) + { + // Must be all zeros after the first zero + for (; p1 < pchCommand + COMMAND_SIZE; p1++) + if (*p1 != 0) + return false; + } + else if (*p1 < ' ' || *p1 > 0x7E) + return false; + } + + // Message size + if (nMessageSize > 0x10000000) + { + printf("CMessageHeader::IsValid() : nMessageSize too large %u\n", nMessageSize); + return false; + } + + return true; + } +}; + + + + + + +static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; + +class CAddress +{ +public: + uint64 nServices; + unsigned char pchReserved[12]; + unsigned int ip; + unsigned short port; + + // disk only + unsigned int nTime; + + // memory only + unsigned int nLastFailed; + + CAddress() + { + nServices = 0; + memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); + ip = 0; + port = DEFAULT_PORT; + nTime = GetAdjustedTime(); + nLastFailed = 0; + } + + CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=0) + { + nServices = nServicesIn; + memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); + ip = ipIn; + port = portIn; + nTime = GetAdjustedTime(); + nLastFailed = 0; + } + + explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=0) + { + nServices = nServicesIn; + memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); + ip = sockaddr.sin_addr.s_addr; + port = sockaddr.sin_port; + nTime = GetAdjustedTime(); + nLastFailed = 0; + } + + explicit CAddress(const char* pszIn, uint64 nServicesIn=0) + { + nServices = nServicesIn; + memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); + ip = 0; + port = DEFAULT_PORT; + nTime = GetAdjustedTime(); + nLastFailed = 0; + + char psz[100]; + if (strlen(pszIn) > ARRAYLEN(psz)-1) + return; + strcpy(psz, pszIn); + unsigned int a, b, c, d, e; + if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4) + return; + char* pszPort = strchr(psz, ':'); + if (pszPort) + { + *pszPort++ = '\0'; + port = htons(atoi(pszPort)); + } + ip = inet_addr(psz); + } + + IMPLEMENT_SERIALIZE + ( + if (nType & SER_DISK) + { + READWRITE(nVersion); + READWRITE(nTime); + } + READWRITE(nServices); + READWRITE(FLATDATA(pchReserved)); + READWRITE(ip); + READWRITE(port); + ) + + friend inline bool operator==(const CAddress& a, const CAddress& b) + { + return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 && + a.ip == b.ip && + a.port == b.port); + } + + friend inline bool operator<(const CAddress& a, const CAddress& b) + { + int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)); + if (ret < 0) + return true; + else if (ret == 0) + { + if (ntohl(a.ip) < ntohl(b.ip)) + return true; + else if (a.ip == b.ip) + return ntohs(a.port) < ntohs(b.port); + } + return false; + } + + vector GetKey() const + { + CDataStream ss; + ss.reserve(18); + ss << FLATDATA(pchReserved) << ip << port; + + #if defined(_MSC_VER) && _MSC_VER < 1300 + return vector((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]); + #else + return vector(ss.begin(), ss.end()); + #endif + } + + struct sockaddr_in GetSockAddr() const + { + struct sockaddr_in sockaddr; + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = ip; + sockaddr.sin_port = port; + return sockaddr; + } + + bool IsIPv4() const + { + return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0); + } + + bool IsRoutable() const + { + return !(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || GetByte(3) == 127 || GetByte(3) == 0); + } + + unsigned char GetByte(int n) const + { + return ((unsigned char*)&ip)[3-n]; + } + + string ToStringIPPort() const + { + return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port)); + } + + string ToStringIP() const + { + return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); + } + + string ToString() const + { + return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port)); + //return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); + } + + void print() const + { + printf("CAddress(%s)\n", ToString().c_str()); + } +}; + + + + + + + +enum +{ + MSG_TX = 1, + MSG_BLOCK, + MSG_REVIEW, + MSG_PRODUCT, + MSG_TABLE, +}; + +static const char* ppszTypeName[] = +{ + "ERROR", + "tx", + "block", + "review", + "product", + "table", +}; + +class CInv +{ +public: + int type; + uint256 hash; + + CInv() + { + type = 0; + hash = 0; + } + + CInv(int typeIn, const uint256& hashIn) + { + type = typeIn; + hash = hashIn; + } + + CInv(const string& strType, const uint256& hashIn) + { + int i; + for (i = 1; i < ARRAYLEN(ppszTypeName); i++) + { + if (strType == ppszTypeName[i]) + { + type = i; + break; + } + } + if (i == ARRAYLEN(ppszTypeName)) + throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str())); + hash = hashIn; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(type); + READWRITE(hash); + ) + + friend inline bool operator<(const CInv& a, const CInv& b) + { + return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); + } + + bool IsKnownType() const + { + return (type >= 1 && type < ARRAYLEN(ppszTypeName)); + } + + const char* GetCommand() const + { + if (!IsKnownType()) + throw std::out_of_range(strprintf("CInv::GetCommand() : type=% unknown type", type)); + return ppszTypeName[type]; + } + + string ToString() const + { + return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,14).c_str()); + } + + void print() const + { + printf("CInv(%s)\n", ToString().c_str()); + } +}; + + + + + +class CRequestTracker +{ +public: + void (*fn)(void*, CDataStream&); + void* param1; + + explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL) + { + fn = fnIn; + param1 = param1In; + } + + bool IsNull() + { + return fn == NULL; + } +}; + + + + + +extern bool fClient; +extern uint64 nLocalServices; +extern CAddress addrLocalHost; +extern CNode* pnodeLocalHost; +extern bool fShutdown; +extern array vfThreadRunning; +extern vector vNodes; +extern CCriticalSection cs_vNodes; +extern map, CAddress> mapAddresses; +extern CCriticalSection cs_mapAddresses; +extern map mapRelay; +extern deque > vRelayExpiration; +extern CCriticalSection cs_mapRelay; +extern map mapAlreadyAskedFor; +extern CAddress addrProxy; + + + + + +class CNode +{ +public: + // socket + uint64 nServices; + SOCKET hSocket; + CDataStream vSend; + CDataStream vRecv; + CCriticalSection cs_vSend; + CCriticalSection cs_vRecv; + unsigned int nPushPos; + CAddress addr; + int nVersion; + bool fClient; + bool fInbound; + bool fNetworkNode; + bool fDisconnect; +protected: + int nRefCount; +public: + int64 nReleaseTime; + map mapRequests; + CCriticalSection cs_mapRequests; + + // flood + vector vAddrToSend; + set setAddrKnown; + + // inventory based relay + set setInventoryKnown; + set setInventoryKnown2; + vector vInventoryToSend; + CCriticalSection cs_inventory; + multimap mapAskFor; + + // publish and subscription + vector vfSubscribe; + + + CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) + { + nServices = 0; + hSocket = hSocketIn; + vSend.SetType(SER_NETWORK); + vRecv.SetType(SER_NETWORK); + nPushPos = -1; + addr = addrIn; + nVersion = 0; + fClient = false; // set by version message + fInbound = fInboundIn; + fNetworkNode = false; + fDisconnect = false; + nRefCount = 0; + nReleaseTime = 0; + vfSubscribe.assign(256, false); + + // Push a version message + /// when NTP implemented, change to just nTime = GetAdjustedTime() + int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); + PushMessage("version", VERSION, nLocalServices, nTime, addr); + } + + ~CNode() + { + if (hSocket != INVALID_SOCKET) + closesocket(hSocket); + } + +private: + CNode(const CNode&); + void operator=(const CNode&); +public: + + + bool ReadyToDisconnect() + { + return fDisconnect || GetRefCount() <= 0; + } + + int GetRefCount() + { + return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0); + } + + void AddRef(int64 nTimeout=0) + { + if (nTimeout != 0) + nReleaseTime = max(nReleaseTime, GetTime() + nTimeout); + else + nRefCount++; + } + + void Release() + { + nRefCount--; + } + + + + void AddInventoryKnown(const CInv& inv) + { + CRITICAL_BLOCK(cs_inventory) + setInventoryKnown.insert(inv); + } + + void PushInventory(const CInv& inv) + { + CRITICAL_BLOCK(cs_inventory) + if (!setInventoryKnown.count(inv)) + vInventoryToSend.push_back(inv); + } + + void AskFor(const CInv& inv) + { + // We're using mapAskFor as a priority queue, + // the key is the earliest time the request can be sent + int64& nRequestTime = mapAlreadyAskedFor[inv]; + printf("askfor %s %I64d\n", inv.ToString().c_str(), nRequestTime); + + // Make sure not to reuse time indexes to keep things in the same order + int64 nNow = (GetTime() - 1) * 1000000; + static int64 nLastTime; + nLastTime = nNow = max(nNow, ++nLastTime); + + // Each retry is 2 minutes after the last + nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow); + mapAskFor.insert(make_pair(nRequestTime, inv)); + } + + + + void BeginMessage(const char* pszCommand) + { + EnterCriticalSection(&cs_vSend); + if (nPushPos != -1) + AbortMessage(); + nPushPos = vSend.size(); + vSend << CMessageHeader(pszCommand, 0); + printf("sending: %-12s ", pszCommand); + } + + void AbortMessage() + { + if (nPushPos == -1) + return; + vSend.resize(nPushPos); + nPushPos = -1; + LeaveCriticalSection(&cs_vSend); + printf("(aborted)\n"); + } + + void EndMessage() + { + extern int nDropMessagesTest; + if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) + { + printf("dropmessages DROPPING SEND MESSAGE\n"); + AbortMessage(); + return; + } + + if (nPushPos == -1) + return; + + // Patch in the size + unsigned int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader); + memcpy((char*)&vSend[nPushPos] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); + + printf("(%d bytes) ", nSize); + //for (int i = nPushPos+sizeof(CMessageHeader); i < min(vSend.size(), nPushPos+sizeof(CMessageHeader)+20U); i++) + // printf("%02x ", vSend[i] & 0xff); + printf("\n"); + + nPushPos = -1; + LeaveCriticalSection(&cs_vSend); + } + + void EndMessageAbortIfEmpty() + { + if (nPushPos == -1) + return; + int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader); + if (nSize > 0) + EndMessage(); + else + AbortMessage(); + } + + const char* GetMessageCommand() const + { + if (nPushPos == -1) + return ""; + return &vSend[nPushPos] + offsetof(CMessageHeader, pchCommand); + } + + + + + void PushMessage(const char* pszCommand) + { + try + { + BeginMessage(pszCommand); + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1) + { + try + { + BeginMessage(pszCommand); + vSend << a1; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + + void PushRequest(const char* pszCommand, + void (*fn)(void*, CDataStream&), void* param1) + { + uint256 hashReply; + RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); + + CRITICAL_BLOCK(cs_mapRequests) + mapRequests[hashReply] = CRequestTracker(fn, param1); + + PushMessage(pszCommand, hashReply); + } + + template + void PushRequest(const char* pszCommand, const T1& a1, + void (*fn)(void*, CDataStream&), void* param1) + { + uint256 hashReply; + RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); + + CRITICAL_BLOCK(cs_mapRequests) + mapRequests[hashReply] = CRequestTracker(fn, param1); + + PushMessage(pszCommand, hashReply, a1); + } + + template + void PushRequest(const char* pszCommand, const T1& a1, const T2& a2, + void (*fn)(void*, CDataStream&), void* param1) + { + uint256 hashReply; + RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); + + CRITICAL_BLOCK(cs_mapRequests) + mapRequests[hashReply] = CRequestTracker(fn, param1); + + PushMessage(pszCommand, hashReply, a1, a2); + } + + + + bool IsSubscribed(unsigned int nChannel); + void Subscribe(unsigned int nChannel, unsigned int nHops=0); + void CancelSubscribe(unsigned int nChannel); + void Disconnect(); +}; + + + + + + + + + + +inline void RelayInventory(const CInv& inv) +{ + // Put on lists to offer to the other nodes + CRITICAL_BLOCK(cs_vNodes) + foreach(CNode* pnode, vNodes) + pnode->PushInventory(inv); +} + +template +void RelayMessage(const CInv& inv, const T& a) +{ + CDataStream ss(SER_NETWORK); + ss.reserve(10000); + ss << a; + RelayMessage(inv, ss); +} + +template<> +inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) +{ + CRITICAL_BLOCK(cs_mapRelay) + { + // Expire old relay messages + while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) + { + mapRelay.erase(vRelayExpiration.front().second); + vRelayExpiration.pop_front(); + } + + // Save original serialized message so newer versions are preserved + mapRelay[inv] = ss; + vRelayExpiration.push_back(make_pair(GetTime() + 15 * 60, inv)); + } + + RelayInventory(inv); +} + + + + + + + + +// +// Templates for the publish and subscription system. +// The object being published as T& obj needs to have: +// a set setSources member +// specializations of AdvertInsert and AdvertErase +// Currently implemented for CTable and CProduct. +// + +template +void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) +{ + // Add to sources + obj.setSources.insert(pfrom->addr.ip); + + if (!AdvertInsert(obj)) + return; + + // Relay + CRITICAL_BLOCK(cs_vNodes) + foreach(CNode* pnode, vNodes) + if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) + pnode->PushMessage("publish", nChannel, nHops, obj); +} + +template +void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) +{ + uint256 hash = obj.GetHash(); + + CRITICAL_BLOCK(cs_vNodes) + foreach(CNode* pnode, vNodes) + if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) + pnode->PushMessage("pub-cancel", nChannel, nHops, hash); + + AdvertErase(obj); +} + +template +void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) +{ + // Remove a source + obj.setSources.erase(pfrom->addr.ip); + + // If no longer supported by any sources, cancel it + if (obj.setSources.empty()) + AdvertStopPublish(pfrom, nChannel, nHops, obj); +} diff --git a/rc/addressbook16.bmp b/rc/addressbook16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c5576910b1b6b95c23ed7c53adec399a944e610a GIT binary patch literal 1334 zcmZ9MKWrOS9LK*+iDcA*T|jP9K#EfVb%3_kxoL?Sz~+CTKo0?umkcM}a-)X~w`8y~ zWwata$wP;F^b*OVM^AaW@iN6rqzqX?CP!j;d|n(O=-qwq_kQ2^d%y4Zy_2r_Y;|6j z*XnE1Jw~M~TvK5-acvg<`*zOBxvAXL<4n`D6HQM%GM!B(AlC_)PJEuJ;Aq!F>#NkLovPNIJ5$BCNMjXNzRgQ_+*rp!g; zA@kIOH0r69ChE4y+o3w`mbys@n%a#*r9QS=N;g8a!={p`qHa`Dn3U9Rt|@8O6xBjv zRneM91uViXss*BIg-Ct1pujo>E&wqwzyhb34*>)GZGZ*v0ek=-zz6UFd;rgan8}zy z9K*-(2F}14I0I)qN3Dgo@D|R(;UVVyV|>JTi1A?2a=ck4gU;+G$Cp8$Dx%MwXb<4< zWDqq77(5xY4U>i@25o~j0eEeA^bPt3eWn2Qp2vg1gW((~M&aj7mEptAkqMyg_a@XPLPt?d zkC;5hhr8_UYhqQ@*XHJ?wzjskv$LbUy*(Wq9B6-kUx$Z>IyySi@$s=vPfvAzey)p) z3;p%C)5{kxw7tE}>9ScKn#}@lhQO)#%Jtps`s3Lw7VG>=O7B&F`?+#Qdc9t(-w6Nw z{nu~qFaPlTdHBKC%zr1p5Vd?$#kAAwEFRk42>mO|ReC~Q-`SIO_!hG=g_r>}+ss?m65uRi?;YjfP( literal 0 HcmV?d00001 diff --git a/rc/addressbook16mask.bmp b/rc/addressbook16mask.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d3a478d1ad1d4800008fda5be5d583f3d0423480 GIT binary patch literal 126 tcmZ?rtz&=yJ0PV2!~#&v$iN7eZ~&8-#Q*>Q!Giz)F))yd?S4Sa0{}e{AL0N2 literal 0 HcmV?d00001 diff --git a/rc/addressbook20.bmp b/rc/addressbook20.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2b33b228aaec9ef51fb3dd46b3eab98f3d61d7df GIT binary patch literal 1478 zcma)+J!~6g9LAp(Xj4#-1LY%>FBd2^1%kPdf|c^&f`Ee-Fy_la3iQe$IKDk(@RGsG z9usXbe`4esg7wT_5VJWhTCq&7#TB`8C#7sMrJhB7@1L`@i5T{jfVq~s9}w4E! zw_*2z22GFXsne(_Y6L`^Q&Ln9)UH?6LQUklMn%-9Rn@6^>eWhWRy~zaBdDkql+^G% zxmCM%<*{$qXH@q}s-X&AKx|alBhM=mUG_yagLz^>b>!A&$jizrda9N1+@k8GJjy9> z3#t{1s-n7^Q?J+hqv|Z8#9m33I+p%fx*CFV4wui69xl=fgy&0 zHi&!}3=9Sa0|TuQJ`4s11A_s;Fh8c5q0o@z)5B-)!(r0iHpf?1ZLO}ZYHe*z8yg$i z+}zam_O`aRwzRXequt$I?d|Ppe}7*G2M0PlJk-Dc8U1tPhSt~DIbB|sAI&C#J4GgAUy7(iLxq5=0b7wD>|14iTJ13pEig)jYa`|ijuj|Xd{$44U-+JXM>s@~B ze0F~B8Rz8vXU<$GJsqUpEY+uS&Pl@Tw=exP@s8g$^ZbVs@0%yToOqAF{OrTj+PqKh z`{=0l_^GM)#Y3On@@AKo&)K~1UcWZ2U08f)$$4~Pap8&8SARLm(^2hh-qP}ew)Tg& zy<4?!7M$E7wco$@8{Qk2Q|5D5QkK+v>=D;`4}9?ACI0Kqe*VH!_CVjizOwS^rPG<` PK3-Y5_U;`Xahmo&>vaK4 literal 0 HcmV?d00001 diff --git a/rc/addressbook20mask.bmp b/rc/addressbook20mask.bmp new file mode 100644 index 0000000000000000000000000000000000000000..56ce6125dbb83abfac437bbbcdb611f45ee57cff GIT binary patch literal 142 zcmZ?r?PGudJ0PV2#3E44$iN7e2mq2o+z`wJ7J(4||Nn>c{{KI~KrXi54>yJZ01nMB AR{#J2 literal 0 HcmV?d00001 diff --git a/rc/bitcoin.ico b/rc/bitcoin.ico new file mode 100644 index 0000000000000000000000000000000000000000..88cc240e2d4f77fa66730593a890a17aab86cbdc GIT binary patch literal 22486 zcmd^n2UJ$qw(d$aJ)W3)(oQs8V{9>M?7b#-Q4nlcKv3zucMy=GbP%NXBE9z}y*KGa z#ohsd`M$LggT~yGoO|yZZ;ZDcleNp*d(GA6n(O=KFJmvUSJ}jg4C(7k`W42GGR7uP z9=Q&Dov~8fn>Fjn^*g^c8%%%sON_Qk(O^G{}h_>Sq9qxo_DEn_o&Vr&Y&iAM~d z70N-vmcPXRJ~_sm&(!u{s~r>B2A_Pk(JPD1Gx2A$b=9F{8)EX+kJ+)3 zN05h1Jf(+yZy3mC83!=Q+?!0Hc8DF!yTR6n)v<-%#cYj#DU->%%=ByfnR-nhTYWx@ zy|qV^eXs7!q%YoPiZuiHb`4wLp2z07-eHD$ZOo_h5p%A;!JHd!v9<1LY;V{_=FxnYdA8hR(#iEqx0~1;`xy4R zh%#GlAHiI264Nfa#!L!3SlG2;ChD2QPQ;Wj|L%U~)^wX~^hjqLeR7#-WDV13ddxOO z)UelgtFdjq8O-%AG4^74OzsQsmE15=WEz?Y|V;WhPm~wg}Q%gsi*ZUt+3N57=?&c_OWqY36k?&75|oUwD;ilP+t8X#unp?~neH?skfTa!$v%nko*&H)p_8R(ahj%j5D!RgKItQ5( z+S21H-fOwbj>ML*k7TXcTcT?03wb;Ct%fW6MBbi#EN#v{*r&sYXmnQmf10MGrln^* zt$TD#Y+QUoVp6hjCm=8=I3zSIJR&mc0>9zv=I(LM)9bvqkFTFUV^-FuZEWrA&zyB| zbaHlKOjl3ez|hFp#MI2(;*{lTc?CtK4Qiq);%aK5np)aAl7|i-*>H4&l-e;F+2bcp z%Iy@{wR^(`(LHM75_|XUKX7o(+I8#IHg5P;ZPVs0TeofBF>n4a3-IcarTDXA<*L``dE9u|SbhvnBD(z=QN}pPOGNryFe2CsM0m#YLE7FS>RU#{ z?d)X8atOEQ{LqJuetL|tvrq5+FQ2^h(o1aI+Y{NVpMT5Vm^zQW_469`_TsJVt<@6j z^$myFtD9ulD_c&m@mu8}@@(8Th2LenA{z%8FNhKwzXP&UnT;1wg{ZOdyVOTyw+0&z zc?I$+~+|&Hz03fp7FUhDsSU_f|xp+ut$SU5Z7Y=kkDom_UW;I>^EQ&4;rzF zhfUc#M=aPoQdaC8X=^s|m^FJ>#)iFj+@5_Pcb0u9@5nwqbxv)=_UD)Ta z5nrgfvB_%g>>CXaHbu*W{iuD8&CvB^v-P~#9E0<0uAw)ZYwU~l%uiU;=3-r&V-mn- znFO*KCP8evNidsk7RqK=gtHl^BG^pJNI_;7QEa|-BwJ(?$(BHt*+#OZb{E(Z ztPzXO#Iaw_CbIbsDQuoo8k_Hwjx>YKb`KvAd5Zn z+2V8gY>8(9q>wH1y2zHFzsOd47qT_p1#F#n9@}_6hy9B6a+7y9+XC6J2h=hL@+Z&M0_60tXpj@^$I1iG~_JtI%gQ0~?G7JJ6FBwtH_Jxg|cG`xcCil}D0B5RpQR6W~up@Hq@65Ysl$22j~*k;)6Rwka<#>A65*xnSZJ*i#n zKw1|&i1bKWCp((n!K71L*|C&nc0A=0JDGfm$)_|i#neWooYutDGMllMv@)%nHl~~3 z$@B`knEu5cW>kEI8JF}j)AH-gtnwx^t-QsIDsMA=h;GGgrdfWQsg>ShiY2$0T+uCd z0{(*R#XFF@Os42QlPP|{WZ{RLgkK_$^;4muk11C6F{SDOrd%_~lxqi>YVBjDRyWAh zA)1YYO#9Lh(`^}I`mIA)D~FhI`yexKf6Oe~2bgtRAG2$H$n0AlFo%}=%(?YGb8COV z+&dmHkFH0|tq1GG zlyJPRuF2cd(%Q`{Df7ye+{}1yOC@P((~63y?K2inm~b-qQcIboi=(s4InOg*xw+?T zy^@o?ERTj)RA|k^2aYzhwfoxl_xJbp_4g%txn}hVr(R~26`>oaET5p((b4R~pDQHw z_dnd9hNnrEmWf_^wYAkEGnPqscXk!|p22e)XZ(?W*x#RJT@vGC;ZxGwATxXUf$*;G zq7X;^$P@3|;^bURaZHH6e`#xj_S~6rF?a73#=7Hn@5BCw&OD=CTy%J7P-t0mgW=pC z55(TPmmlMS+v(T(bL9DR+mNWpsOSr&%?8ObC$jF+O zM%B5?#oX`Sy&UJlpX1L%u^avUxd+_Lm2CW5S{skdS~fxH&YfF94tVaEgZB@6pcT?j z+vg#Tp=PpP89nbIXjMCE7P}fjbQ8zU6PRYHJS6BqCqc-7ne88}^ zr7=`TM_WfnQ$yE0BqlRAx8>fwd!5pAM~3ks|Aw|pk!Je(I$Byl1_cx$$)dgnBE{`%lhD`+=jF<_8Med#)!P6 z4>tnBxcu3nKaxktoAKn`HhhPF58s`{zdy_!7=1V@x8dO6;C{+1$N|VxKjlqaj2?f- zPkDJ9d+Cd5?B!oJvzIqYv6r{Vv6taTa2fF>xDNrp0rCobhgadtzlyyI_Yt_fDyqp| z5z}U`U|;ZxxGsA|LjS3}iu2bb^w^scx@-dcgm)#h*!z36*@y7c|9L=(~bPuOhZ5Rlc5irXW+$t(Lcu)K^7aFV@r%Y*)rqvY?+BSTW;#hR+#y* zmFE6z)u{ls#yXg-wGCtI&R$^ao#NO!=Xkc(If1Qlif60N#QAf(;|$`JQWU!U^6T)uo+e{Z06}WNIaWmo4{t1Psk)Pp<2m*g(?x;_~{Sw!lr@qPJb9rnjWSM6^TkciBR$%Y8%BP5}@hxI& zeG1un-$J$#vdK4}ZSl=z+x&9bPQM%`=9kU(_~)=af%$AV_JO;DOPEMVIolOh$##cV zGg0^#d$2c_h^k@xF4Qoo*lH#dkG*I@H9Hnx!w$#SGx7KqwkNI?zD7HIjSeP})W!Cv za37fwSJhX zH4HQL#v!KJG{m$aI?Y2&4}J&tJ&aoinMEu7j+TCA+4h)Obv$M^U4zWNdx+WhV6O^s zxH8Nfdxx15_PoyUFI*t55O??%=dKR2^OpyhPj?^lg>T}A)E^Q6A0_z8pnw%{yxT6V;Rhd2`C;k{9zK8T z=PA=?%$hZ8=Jc;V|Kx*-@Bi@p^JlIX%$>7jrHs0fshOF$%!);`zWn69i61|cW9-G| zMN6biBQh_ww6wIgwzf6ISsz_E{nI~vW5g>7rZ8-|7+Uq<$xp36Ob zJoCWgq2b}dUW)~j{-D#2)h6|gt?g~Ct<4!p@v-rVNog6q1Kh#F;k@|y7j~>NsjjW6 zYie%Diio%nn~iBN-C@BLR}-mqhq6^6Vfu$Gcq#L z(=+<|yD#^&xh|SCapJe5b@*+iLJnN8?3}X>t`T9eiSZXAViFS*<6|yFML1_R)YWBX z8qfK3;>6MXYmNo;{GsNj&$>dJq~!SM=nE0f4rkBW+1l8gFDWUym~(vk2ctc=bA>z4 z9%5>K+QB6vIw2`JIVmwF!qvgX#>7ZpSKFhosHn($2{alhV2z+nj+wdjX$R+s_#{E| zq=e{*2v=J}ZB<1@kAi}NLjBnvjTEqJ<#~L)#CDJPo;?;;ryZT6lQS9`GSU+x9IQ&6`-qNgsTH#8(Wo9*8(CMJ4#!Tc5a z1^IdT+A}}kO|)s1TX{uwt;ioojW&DEoA%(^778j z|8(L9RZ?ADmu-Id8eHy?<4&rWla*!f=;ec?m9_=>`30*d^BNyjuc@uA^R*ty z?<9Hy+3r~F-gBL2zwT^tD(*(Ilz!30i-r0#cqgy1MfN(k(4C%Dv#PAPc-5qd@9&Uq>g?`r$cfl1D1< zmzOvHKJtIOUAhkWn@00H?M6lKB+PZ@`LA!Z@%Q!h3k>x4_OC80DS|%VY?jLE>h5k1 zdGdYBS*gf)N7Rz%zjMgc>pVVw-p4Drx~w>l*LS=W9RKe2P{$GdpR~V~2(QNjOG!I7 zHydMYS;psV?XJ zHGaILct>|nPo{&Ukl%8v$#{*P_=-X&Q-(#`Ox7xN|+) z{1Wo}LVZ3VB_*&2Y;UmMv+u~^qifc!Tfb!KDtS#kGYbm~D<@}XM~gjX*&TH?l{z!u z`-tb?Dt)27wYkw-M_%sa3E?;?udbzMdO9K@DLy(pB0Ma+yR*F}c=@D>-|_t8k4QAu z*HsnSXliJvsj6zIDJdvu>FAoAjYw{|+T2)IRn^_y*-@)I>qFu5~^zmz8#CYxZ6d!2g*P|)NlKJ&$DqzpJem><}Ii7D!DqQ0FucrD!#wXu-{`bwgch7ZG2Yv@Myc?b>W3&JRKf+j10nUev2P` zpE?mTnZGam1-3pGPsjZi9qNAB@6OXZcYKP5Yx?(E?zcXbw;TNI*r_X@9WsoZA!oiF zpZ?PwuBdC=3DJOzTi}ie+!290B5+3p?ufu05x67zhnRZWI!%{Po-ccy{RJ1<%r*i? zMc}9i92J41B5+g$j*7rh5jZLWM@6siQf{2DVf)X~Z>+P6R0JFI6wji zNZ%pS}m)lfZitcuxZFN#H%{RS~rTvGBq!@T>%$mB6zK z`MD0fd~mJ8HP-=rD}iq%@T~;CmB6>sYoh88xA~+Og5xD{yabL{$PbQJNWt?8DR^E2 z&r9HW2|O=>=OysG1dgM8&6x{U;Fk&fGJ#(f@{g7eewn~8KXVTpGl63!aLgD>Y8Dz{ zxj#xKRu6&OCUDyXZkxbu6S!>xw@u)-3EVb;+a_?^1a6zaZPPyvnf5JKKm8RS1Iuh8 z-NC05_;doFPTk9wu7z;}E$duF%%>YG2X#joJTT8D)66{iAE zh?obzGqy~A&N;g_Zl|~{gS?2Z8+(uE;gW%OZo}emJ2M%w95QNW^ts{rZyb7l=^v~$ zbeH@}*3xIvF^kG~_v_yV)-?!TtpAgP`rTh1HO!c$U}>@2(sQ{U(KGG%pBBs8RN5kpoc8l2IzDTksahL#N{&N3T$KhL(;m~Mw@*y z=rh={*Y+9^FhZIjs@k;8%ys48(ZMsl_4UK&lU(MQ2MsHyl~d@gM|2+LICK#?qD*eT z-L4XOUL*3pPUHs(z+4ZxO%#5Q$i4jz?ex#04^G>rzg@bA$iC$f**D!M$L4z|>j4E^9iZs@!xY~~lr%t; zf;6#zm@KL~=sP_x8ZV|zz)goSKJ5N09V{YqCakgvFIwP~LRz(t$f#+EPQeD-b>dr% z4`Iu$l2Upbsb{v6US1EG759>P$u+VnyG3@DcL{MQl=N_rvWAJ$An}jUPCd71rdh!6 zIvg?l({|Ws7alRkHjd;=?vhINL(-^uL^`#7u;J|_ozg;b86BjS(@7fH?WC63f;Ft0 z%*$b)%Wsi+*@|c#o<@9ku^yJvTK5#%h&jIFd^YXH`Y#n-NlK~k0WMx9o4UJXQ-2?0>^A9K zyh^eumq-lntoO>Kd3JI1!>MSRaw?vd`c}}9f=AG!k0i5h)5pqgf_->fRJDcMDA<>m zSK36ji^MjOTEh@&H4c(&-WA&HnNE_yxwJnZlMV)E(_x$+4a+C#@B-T7lS;>;OX+m& zZIpkL4qz?Z<()>yv97A8)sjY99UY4*qTgH-VVlBfchXgq|B#MB7GnJZCm^)JY$eO3 zdSThWOfwB76|6xz%|u46!z30}O`?8TPuEwz?gH}^Wb|Aq0riS1M!V#}KWKmYZ1g$L z&(DuU7Sk&45|SzICz&Gn2MJyD59!lF`5*7sF+b#;tg*;7jr7}4HbkfHA?*q)C-Csk zl)u?Aiqw;uOfiL7V-uNe*N5XjT_(38|!YUKeR|Kn2Mc-68ebVN$LfrWuwoG)_dF-r1wxz1cY~ zM+1g4ohMzNCf0Qtr!3HI-3xZjU4gc_%-+aL_Ff3$s>vJaX9@F>Uxu; za<0hNhhjs&za?LR2Mi!0Rtx2!%ROum zGO3+(Ao%yPczNfV@1m}QLU{q*{d6!WOBkE{*{JOH#h6WLrXx9*Nj$lWcEv%W+iA~* zb~=`IgEUZoMU=nvT)torU)iqkc>UR!Vrlrm&hRxo9$*aAKOnixDOZ<60k z-mvxj{B(IYEw>8%L-{+;r;>PV10954C6V4kl9|19IO7_0x=JSsZj(kG3FR;G$fa?j zTHMdRwb?l~;b3wNxuWjpu+Eq_J)o0m-E=Ud@M*nxnH$eU(5U~+uU#5$()u&u&*YKB zT-X*+L$sC&SKrfn_ElHu7xN(60bBK}UjZ#X6HnXy z3utFlJ*hYLlNRQ;QvEP}XA(l=cB;|`d$rC>c_)i6JR3tU*k8F}9e2jMaU{BtB>a9a zi`VyHKnB^M-T65eSNQJJ3#6|4c6ZuT-x~IJgd;hCJoogjkf`O3RUc_p6~zBa(NkEZTD%db3DyG zlSs>5Qs_WPKAmg1_f(Iuc~8Vwl3ZaA>BE1}hX1lVsgd3~VnMHMSA3-I7xOM(1AcXg zjuwNxbVd0t@M~~D$3K^3V@gR0_D3nDnxtdPXjgDPNyJu>4R06BZB4Yn44Vr=-+#1E%X4)7(F)04 zKIc^Euu;QZvPK&jqn{)*uF?X&*Ko?BxsI9ivttI$br?x!pG~EooiZ?wa%d&io82MB zq@0004E9R4_=YLg1?}oPq*{549BvPgGauKzLxW%|4`%|KG4)iKV0S)0sB1E|Y<{j6kw5uov*24>FjkdnhDf^w zw_a!>g{sG-jJcwMIV)Gy zM_Z$tX_-$c>YPt=p~FwE&;ji*-!+p~d*#udh+2}*>=t|hWB6^xmj=lU{cYAWOgk@> z(?l5?dQ(*WlK5$#KVTeVbvfaea`;E%;K5%*Y6yHN${r*+v{G?%0 z$6BUy6zu{e|LQn1%2Cw8OJ^{dP90 zXqsW*@NC;eS_xhF_}G)&O-J&t(b4=Xv-!bd67lP!(S{y2AA7}-3887yX|aLu!K|8@pG9~f2oiE z0~P*PUZFMtT+jo)y9`+8B;dL4v;h%?jLQIYpg$t)?;KCwc`4(?u{*ph02Kf@aB!Sr z7UTfrDNgZ>WyFL3!6P^??+poC?=`a(tqi`EF^igd(xT@5eL6Q^+o?M6>Q1G{Z|_#S zKl!jh>yIbQ(`U(_Ijb%iFB{*Q_-1@O$Tw$=x>&nbQPd z9TR131>3^y%R8`dZ%bJTHg>$Yo?z$4?Nkx`{8zRq4$e4fk-NpjO$yZYzm4VkJG%W> zd3`c#KRMtUZSbv%Q~L+<4#ShQ&eL~Bf$+b9-@tEJ=aWO50t;vh+0kqJjYsN&eJkHLP7qVOv0U@4o;$FD|Elc&&NIK_`VW)>Q*FQ3^mz1@ zwl~eR2&G?rvPl}gy&l$hOROta@MkyH&eGg zW6yQwcoM`Jevu2r9e&q2_$Z!`^BhxxFBS-&-1}NT*7YV@0w48XYVN}L;+PWe3y$eb zJ#OmvKhYP#)zxqBcaIO8X%sL#&pM1WGb{-tM@64*u%- zu{ap?4uT&a48J1`dzuLNUQv+nTZ6!E8t5m>Po4Y+}Z?E2A;CI91 z5C13__;ncCJL1lWzR}o=#XbUth59FQTn!S3Yv11c*i&TC=c=wWo@0zVM&<>^Q^x^Y zzrSrcU6PBxSZ5P7CPw&zY=|c?RLz}f=jZrr4&)A$`{qtd=J48$HH54acj z5BRO>z&*9<`r*G1lIf+#qzJrED!G}CL-&*L@l}AqX@Ead&*C^}E8({Xz#p%Z6>u=i z%G+dJbr14@Y=EO#SKKD6(pz*E`;m}az)3J4yfHsKF#g=oudYZBC)Cm;*xKjf`(74^G}e(EBnv<~oot#l&c5*Yz!wY&r@ z0{a3Z@HqzXv-RO~ulLHQkK`SJDF`^TV3&S1blLo8Rj`V?ID589(7+Go5rjBP;5GLl zBeE#Z)7Dn(mFZ;Ttz7pZ4bUu4`ar#1bSlJtDzr8aaj4(R+33< zri0i+?F9}i5mrNDz+!iWR0Bt?q^DFJp{Nz!q3 z*ppon#*Q}pWrO1DWLyfY8rZoZFmzpTvFhj>1@w_L_}YEIfklGLX=^|k{f52YTI{=4 z0MlLOQAkVN3rQrdlQ^cUPyxITqJZ;*X;*2owl8eb2)@hfFztl7^7HyTW>joOtnu(X zK5l?TaJ~7s;T$pNYPSGy-s+!EI|BMS+c; zD1I!|@x2pg1kQx(|BjgY<*_(9ughNd_}p)ef`Bn~kur2v#ynH2c>rwf5s3h&Uw00e zgliJ5cS)kn?y0o%d=~9NUmQeTIDRdcR1f~Sm5fWS(rMUA`$o)F;MlxArWH3yyYLFh zrMJ+*m}>L^a3s9H%qfxPSYM!N7VwSCF9^8y%rluJo_U*&7LH)s$559;S$F75y?_yW z1pRp(W-FYM80~}L!iHJXjRMj3DWqCA2pJ&t`hL=Rf_blo|26+q2u;^LN7FQ2X}Y#M z;dj#Xv%z_qZ|p;h%=~G&We}}96G`}e7AdFI)2XT(;DR0qVpQ5oG6^-b)iafroDQX> zkPVK}wAnR|5Eo8!@&0607y1ks{MQB{wCsEt_HcayN5HZ1W8mMHfXn~KF`K9J;Io5z zNu&B7_e-(--Z%std9$zw)xcg`2ll|Ac?cM5IW4t|1~&CTz~ub89w8koeZqa;&PU`_ zf1Tuj)&J%kO>&7n>#`nj5*hS^ zc@*u!GxPTC$= zjQ$OLq5g_-CA0gjrb1Y zP>Q=~I@)p-@O{M!@Jr>7=_EJ?xw1jb5)v~7s?#Q~!aF8R~;mki9LZxw6>4E*_aGzQ-Ko$?v7Ecrb~V>A!1?{9qUd!*9t zNRGo6(+XGYd%$VQCDqa5vuW4^m4dI}YbI=IC2T3|>5k|Y`cT37sU7-wzjnfjfHd7H zW}$QtzKbEpC?T9LF=%)MJ9i1TzMOus2!3Jv9}UT+8JfSxmpg(w`+sFLUqNbXMf*-s~mK>wT-oqaI4qdE4 zGI;-BOats)nMg;o|Dl00t$_V}QTuZ}xs2+~Q+}PzS_IPGxLT4axQex@ha|wo?27M#{{R6mwHv&YSX3MB!#!dA0P|K7^dF*cjYH{` zC%(k1+Y|@H-4haig#M--56BUFBv7>;1En0JZ3R0G`pTA!mw-$KAQT;~iupYeH!RL70(PxV-g6LPzZ19Ke z@V7b;=Qbky&{q4=7m~o5_oiGXY54HE;49QHe>uM=3oLq)uHV!7`|$zo6gj_CmFbwj z$8%fA1^9p)>fnL#@6tO+idk1lD)tgB2fy^9@y~hZuNCabIKSl&q9xXW)@Q3-q z>mV7FLkrO7V&N6EKM6KEzJa#DPOtajc-KYR9fi2Y_%^IvcS#p(Dd#7Z>V|>&U!%`8 z5ibIcl-tiqhYW1B!m`%Sg8pI`O34}Xmvd#DFZ8$pjs$%wiP(=NmJu)1f1hs}eJo{$ zz2G0$C>ii>->A8eeRc02>gLsYkLDP7(c;q)v>tx#N~~Q!TZR#0Md(;8_jR*q2jWaL zn+He_Ybob9RWJ{BU_BK$MsVz0|LJlTVtLga@BLyK@^}T-6V7$ILU*n|=Nt7AAG06( zq(vBCFKYio;JO!^`e6JIJfkC@13SIaXgYA0wT^Kw^dInl;?O3iXqs#6O-o@2M{WlTk*uq(;zjgb) z5w7%!{&wyCv>*G7rGL`?Tu&}z$38!IsJlT^fz!=Dn?wr{Z?(-cg}B{$KHup3W4~bm z{qcV_Ag-a846%-KZk5+Tt7VX;T7=VU2TX*v$Jo!|y7NQYCs}Ep)@4=X?&W=9sQSENS5x_p`_9J6b1x zkJ~0y#NKWNH*OA0$q+b%7WCJKUvMbD3uFIx-(jYlxzvdEj73~*`qu)Cp`|YI;OmEk zIpB)%55$2$*WX^vSi!Dppe#=xA70tCVDTj^`WVolcd!Coqy zemavZ=)VdvMq8kdh+jVK0@l0hd>To@Z#o`bBKSe_i4}Adb43I`=sNdg+7ghDxT@=9 zhcRG^^0m?aXkYZ+%}13*(A}-(}^_GI^n6zut}ilTx=6)Hu5cS$-O&!xp=FGDQ8Cv9+K&RRV5f2Gp6t-6fwo3ur;D%tt>7ow5fS=_u z-*qHjm&fe>0^XQ&#&f~j{^XcOa~#vb=jPH<&m39?{WtpMA%3kK@od0)5L@N|+}Z_m z%dwqflKo`b0z1>#hd7!C{-E z3-wv#k&QZJ(Kf{D9ZF~vur9US%VYvP(WVx0YVfg6VV`f*)CWJakK7+Z_s1Bwz;vD9 z$DD@#M+!RW3mu=)HFtQvvdw|fHh(^K&nfwIsb%QR@4?L;Ex3W$60CjDpQn6Jd>nDg zybg=O!{Yy8pnQLm#NJ}RBK%KE&+9$*S|u<| ze1>u0@Ql-OBwYjy3qFSy`auWd3BNN&oXP-+Cc`HJX2$EV_*|h7f3N`h&wm<&kSo-M zk15_yYp|w@M%L0X_y?+az4(nl56L4I;Rxav<OY`IzDDZjJSSg=ac_ z!0|)GXTn!&Q9mF4{#afA?EHXRoD+UOPqXY2(SLUZzexq$I9~&~sG&YGrT1wAV$PQ# z25;&4Vj+G(h@lW-81fKDfj9n=kX-#&gTnpl(K2Smk{61<6U)u*O}E1kQrhc zEMQ}JteQE*tY?Te1{Kh!YKW%;pYi5yl^gp``%n8beV@PYQe6Csm~(X86mW90?UU$8 z9{kX<0mM1LCxRcM%;yC6sc zUBAM=IhfEwI`C_35dUw{jP(^*lUn5?;A8{vHHS$L>(mDDe*e<+6vq6Uu$7{g-t(W= z@!wrvC@y{zbx4|uI`DXhy=lF`G9F?c0}p^bI#GqV3DiRi{*@xel^o(GB=c_5_QXzF z8`(%JvHx2YTup1ks%i6uONblmq2m|tV9y9$fiG*L?wW|bP^m(@z^^>X<18-TMI2`a zeX0)J930F9QT0xdQ=Xj0{*R8hxW?D^d&K$i`S6`d82yHLK_1f~g|eg&Um*vqTMaf= z5%u7Gq70iQ5510|eo~n0QoxUS9LPv4$VeQ94A&LUi_{=8^OP z@P+Z>di1%Ze!8(w{C^n}^H(ZGz@;&#l@?e8_i=1`_F2U3Vvlr)$ELuh$|8p51cZ+z zRm=-b_=;+D=##3q3TZkt?9b`)pg9F`<yCJw&;P1Ue>WfR z3yZis@of%~b(~NAT0fA!2d1|W_J31&1M%1(>5KOTUHM*BliOYJWjx+Xs_-uM=hZE|Lg8;G{Zhh~Sq4AA{Gji# zFZ~+wm0>XI6d}y{pAcs`8@@32d%wngj@^8Lx%su4>%dl9~*%q9BLQP0F=1;3Qj*71cR z7Z8W=e^bZ*m&*c!%rG8=AEHj;DT0+=<7u1lvrhh)M-}~NzgHbM^7_-?hraaW8mT@$ z%SKZaAY3Emw|Rm8Td6+(@MyVX(hPoojJ|FB8Vw<&@BIFITr>}3lm6cCSCL(KL64`z IOZolyKiCZ4$N&HU literal 0 HcmV?d00001 diff --git a/rc/check.ico b/rc/check.ico new file mode 100644 index 0000000000000000000000000000000000000000..0c4e6e81473d47761346fd71e171a807bda5ec58 GIT binary patch literal 766 zcmdUtAritc5Ji7?>Oo=IK{2@m+>AIRcZlpMaugJUL?RfLzb&Fm5tZVcTcTu78nlc+X79T)o9yH~Bu18~wK99d`Ux|y2#0TZ_)l%(v!!U*NL^S< zm%;~9QW>8Y{WOqh07L_>g8?ux2p5ho`>mS)zsJ~LYQ7gH)G3saMH zyB~}P>RC^tqazJ22kKf^qtTH%)*+8HB(`iz!{JD6Ym}Tk7?DT0LLYf-R`9Lfu|hGN{Hh5!TD1R4whhJ=^V zS4W7?sJSvv_HRM}BgTY`h7z_r3!Cba8Q^tE($rUtjC@AJfm>U2Se|a=Q6{ASdcovs^b%O|_~O^A9J3 zo8Gy{cW=fyyV5$bWwCUxW^1*ko3u|Q!khV8bNYU6kCq$$b?M$c zXwEFX|G1o6qw%(MADT1u`ciJFjYp+xPCtD)5ti!rOE=q`nY3s1`n}Q>|Lf1qO_lCf Z2B?~wyHmPbfR5?STF&s_p4QyW^e;amw9xQ85j>RFfcv<;txRlgMp#`4+F#he?a^n U34{0`aiBa{9Y{S$UjqXJ0D?~%)Bpeg literal 0 HcmV?d00001 diff --git a/rc/send16masknoshadow.bmp b/rc/send16masknoshadow.bmp new file mode 100644 index 0000000000000000000000000000000000000000..faf24e0d8aa81faf80072c7807e52d749cad63c0 GIT binary patch literal 126 zcmZ?rtz&=yJ0PV2!~#&v$iN7eZ~&8-#Q*>Q!Geqp3=E71fcOCre_&wv{{x8s0P#N{ U1}Xv5AU;qWBo9^xQV-Mz01_z}*8l(j literal 0 HcmV?d00001 diff --git a/rc/send20.bmp b/rc/send20.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2b90422b38467ae30a2b6a866adbf0ad3c3f97f3 GIT binary patch literal 1478 zcmZXSKWrOi7{;GaLQNamP(c#|QaKSso$~KuQiKB~Sfms~DLR@G4onc1ZpoM-LzWCy zrW+Vekxuf^0gqWCdGvy0mVEN)Oz9FSLza-qkr-Zn=R}0i&wlRv?)Sa-KF@b{`Tn27 z8jRb|N;g@(bgCic2K=|7!F2A@wXWLMR;S-l%UasBO*O5lhBegf^^{nmZnvk{Vs*M* z)vd1NFwv^5s?+Ie*_N3*YNI7vQmfNe&1zceFR9&btA#=fRqNMS(;o#EsMUh^LuMEX z`hm(;R&W?-bCV3Ha#)dXz6w@Qv)Pnqp2A+J@_t##W}?cIic0$>h22o2HmXLWA%EXj z&T>i`iR#U|WKyYDQqT#cz7!|1>IwW%T5c>Wx1Up`g-^$q_F>7g^h631&JZt2J*nI* zs}|R!uH?1I5QkDn3gSSeMoE>pBDEzy@#Qr<`LVB3y(BO3REP`m>+sl9exSU(I()UD ze4X{Gr_uVT@~e48a>x`Fg^DObDS{W_5uDA4MHIm!cnV8lDJ+Gh8Kc(09o)ej%)xjU zk--dR4macD#A8bFIr(tUKP1JUD(39oM0*4yQ;KPdK}x0+@087yCMn)2-b^U-hU1^& zpW@FJqCVqfNXd{|mH@8e;Pen?uDkB#>=(#Rj30j=G8h?*3`Pbc1CJnjlEKJeWN>7l z4Wgb5Mg}8;k%86-P6i``k--RH_&b^z4;n=gJtFQSa@e4ERujonQ;Um>T3K1q`ue&y zHa4`qy{)aSE$!^=Xm@v4dwY92I5^PJ(UFdikM-Bzrr#ew*4o+{Zvdf^`qjovy#Co%$I+@J$@dB6B8f(^6~4>pU}%==y%-wtc z`osH^S7B4r)6+9EckZw;_raBil`&XhDx=xP?CkZot6ui($jfisni}w_EB+5zMp!mp zc<$!Ztz7BRSQc>pbPVUO41f0E-0{K-mo9vH_i9%4?^yU_=-W@Ty#E;s&wTgc|Io$i T{JW>;KP#Mn?J0D&nXUc-U3=Ry literal 0 HcmV?d00001 diff --git a/rc/send20mask.bmp b/rc/send20mask.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f124d0da084e68cac62312e9fa8a0fbf9c7c5075 GIT binary patch literal 142 zcmZ?r?PGudJ0PV2#3E44$iN7e2mq2o+z`wJ7J(4||Nm!TJix%f_yCAM0PznX{=>jv m|BrzIC + #ifndef OPENSSL_NO_RSA + #include + #endif + +Add this to crypto\err\err_all.c before the ERR_load_crypto_strings line: + void ERR_load_RSA_strings(void) { } + +Edit ms\mingw32.bat and replace the Configure line's parameters with this +no-everything list. You have to put this in the batch file because batch +files can't handle more than 9 parameters. + perl Configure mingw threads no-rc2 no-rc4 no-rc5 no-idea no-des no-bf no-cast no-aes no-camellia no-seed no-rsa no-dh + +Also REM out the following line in ms\mingw32.bat. The build fails after it's +already finished building libeay32, which is all we care about, but the +failure aborts the script before it runs dllwrap to generate libeay32.dll. + REM if errorlevel 1 goto end + +Build + ms\mingw32.bat + +If you want to use it with MSVC, generate the .lib file + lib /machine:i386 /def:ms\libeay32.def /out:out\libeay32.lib + + +Berkeley DB +----------- +MinGW with MSYS: +cd \DB\build_unix +sh ../dist/configure --enable-mingw --enable-cxx +make + + +Boost +----- +You may need Boost version 1.35 to build with MSVC 6.0. I couldn't get +version 1.37 to compile with MSVC 6.0. diff --git a/script.cpp b/script.cpp new file mode 100644 index 000000000..0e95af503 --- /dev/null +++ b/script.cpp @@ -0,0 +1,1127 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" + +bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); + + + +typedef vector valtype; +static const valtype vchFalse(0); +static const valtype vchZero(0); +static const valtype vchTrue(1, 1); +static const CBigNum bnZero(0); +static const CBigNum bnOne(1); +static const CBigNum bnFalse(0); +static const CBigNum bnTrue(1); + + +bool CastToBool(const valtype& vch) +{ + return (CBigNum(vch) != bnZero); +} + +void MakeSameSize(valtype& vch1, valtype& vch2) +{ + // Lengthen the shorter one + if (vch1.size() < vch2.size()) + vch1.resize(vch2.size(), 0); + if (vch2.size() < vch1.size()) + vch2.resize(vch1.size(), 0); +} + + + +// +// Script is a stack machine (like Forth) that evaluates a predicate +// returning a bool indicating valid or not. There are no loops. +// +#define stacktop(i) (stack.at(stack.size()+(i))) +#define altstacktop(i) (altstack.at(altstack.size()+(i))) + +bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType, + vector >* pvStackRet) +{ + CAutoBN_CTX pctx; + CScript::const_iterator pc = script.begin(); + CScript::const_iterator pend = script.end(); + CScript::const_iterator pbegincodehash = script.begin(); + vector vfExec; + vector stack; + vector altstack; + if (pvStackRet) + pvStackRet->clear(); + + + while (pc < pend) + { + bool fExec = !count(vfExec.begin(), vfExec.end(), false); + + // + // Read instruction + // + opcodetype opcode; + valtype vchPushValue; + if (!script.GetOp(pc, opcode, vchPushValue)) + return false; + + if (fExec && opcode <= OP_PUSHDATA4) + stack.push_back(vchPushValue); + else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) + switch (opcode) + { + // + // Push value + // + case OP_1NEGATE: + case OP_1: + case OP_2: + case OP_3: + case OP_4: + case OP_5: + case OP_6: + case OP_7: + case OP_8: + case OP_9: + case OP_10: + case OP_11: + case OP_12: + case OP_13: + case OP_14: + case OP_15: + case OP_16: + { + // ( -- value) + CBigNum bn((int)opcode - (int)(OP_1 - 1)); + stack.push_back(bn.getvch()); + } + break; + + + // + // Control + // + case OP_NOP: + break; + + case OP_VER: + { + CBigNum bn(VERSION); + stack.push_back(bn.getvch()); + } + break; + + case OP_IF: + case OP_NOTIF: + case OP_VERIF: + case OP_VERNOTIF: + { + // if [statements] [else [statements]] endif + bool fValue = false; + if (fExec) + { + if (stack.size() < 1) + return false; + valtype& vch = stacktop(-1); + if (opcode == OP_VERIF || opcode == OP_VERNOTIF) + fValue = (CBigNum(VERSION) >= CBigNum(vch)); + else + fValue = CastToBool(vch); + if (opcode == OP_NOTIF || opcode == OP_VERNOTIF) + fValue = !fValue; + stack.pop_back(); + } + vfExec.push_back(fValue); + } + break; + + case OP_ELSE: + { + if (vfExec.empty()) + return false; + vfExec.back() = !vfExec.back(); + } + break; + + case OP_ENDIF: + { + if (vfExec.empty()) + return false; + vfExec.pop_back(); + } + break; + + case OP_VERIFY: + { + // (true -- ) or + // (false -- false) and return + if (stack.size() < 1) + return false; + bool fValue = CastToBool(stacktop(-1)); + if (fValue) + stack.pop_back(); + else + pc = pend; + } + break; + + case OP_RETURN: + { + pc = pend; + } + break; + + + // + // Stack ops + // + case OP_TOALTSTACK: + { + if (stack.size() < 1) + return false; + altstack.push_back(stacktop(-1)); + stack.pop_back(); + } + break; + + case OP_FROMALTSTACK: + { + if (altstack.size() < 1) + return false; + stack.push_back(altstacktop(-1)); + altstack.pop_back(); + } + break; + + case OP_2DROP: + { + // (x1 x2 -- ) + stack.pop_back(); + stack.pop_back(); + } + break; + + case OP_2DUP: + { + // (x1 x2 -- x1 x2 x1 x2) + if (stack.size() < 2) + return false; + valtype vch1 = stacktop(-2); + valtype vch2 = stacktop(-1); + stack.push_back(vch1); + stack.push_back(vch2); + } + break; + + case OP_3DUP: + { + // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) + if (stack.size() < 3) + return false; + valtype vch1 = stacktop(-3); + valtype vch2 = stacktop(-2); + valtype vch3 = stacktop(-1); + stack.push_back(vch1); + stack.push_back(vch2); + stack.push_back(vch3); + } + break; + + case OP_2OVER: + { + // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) + if (stack.size() < 4) + return false; + valtype vch1 = stacktop(-4); + valtype vch2 = stacktop(-3); + stack.push_back(vch1); + stack.push_back(vch2); + } + break; + + case OP_2ROT: + { + // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) + if (stack.size() < 6) + return false; + valtype vch1 = stacktop(-6); + valtype vch2 = stacktop(-5); + stack.erase(stack.end()-6, stack.end()-4); + stack.push_back(vch1); + stack.push_back(vch2); + } + break; + + case OP_2SWAP: + { + // (x1 x2 x3 x4 -- x3 x4 x1 x2) + if (stack.size() < 4) + return false; + swap(stacktop(-4), stacktop(-2)); + swap(stacktop(-3), stacktop(-1)); + } + break; + + case OP_IFDUP: + { + // (x - 0 | x x) + if (stack.size() < 1) + return false; + valtype vch = stacktop(-1); + if (CastToBool(vch)) + stack.push_back(vch); + } + break; + + case OP_DEPTH: + { + // -- stacksize + CBigNum bn(stack.size()); + stack.push_back(bn.getvch()); + } + break; + + case OP_DROP: + { + // (x -- ) + if (stack.size() < 1) + return false; + stack.pop_back(); + } + break; + + case OP_DUP: + { + // (x -- x x) + if (stack.size() < 1) + return false; + valtype vch = stacktop(-1); + stack.push_back(vch); + } + break; + + case OP_NIP: + { + // (x1 x2 -- x2) + if (stack.size() < 2) + return false; + stack.erase(stack.end() - 2); + } + break; + + case OP_OVER: + { + // (x1 x2 -- x1 x2 x1) + if (stack.size() < 2) + return false; + valtype vch = stacktop(-2); + stack.push_back(vch); + } + break; + + case OP_PICK: + case OP_ROLL: + { + // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) + // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) + if (stack.size() < 2) + return false; + int n = CBigNum(stacktop(-1)).getint(); + stack.pop_back(); + if (n < 0 || n >= stack.size()) + return false; + valtype vch = stacktop(-n-1); + if (opcode == OP_ROLL) + stack.erase(stack.end()-n-1); + stack.push_back(vch); + } + break; + + case OP_ROT: + { + // (x1 x2 x3 -- x2 x3 x1) + // x2 x1 x3 after first swap + // x2 x3 x1 after second swap + if (stack.size() < 3) + return false; + swap(stacktop(-3), stacktop(-2)); + swap(stacktop(-2), stacktop(-1)); + } + break; + + case OP_SWAP: + { + // (x1 x2 -- x2 x1) + if (stack.size() < 2) + return false; + swap(stacktop(-2), stacktop(-1)); + } + break; + + case OP_TUCK: + { + // (x1 x2 -- x2 x1 x2) + if (stack.size() < 2) + return false; + valtype vch = stacktop(-1); + stack.insert(stack.end()-2, vch); + } + break; + + + // + // Splice ops + // + case OP_CAT: + { + // (x1 x2 -- out) + if (stack.size() < 2) + return false; + valtype& vch1 = stacktop(-2); + valtype& vch2 = stacktop(-1); + vch1.insert(vch1.end(), vch2.begin(), vch2.end()); + stack.pop_back(); + } + break; + + case OP_SUBSTR: + { + // (in begin size -- out) + if (stack.size() < 3) + return false; + valtype& vch = stacktop(-3); + int nBegin = CBigNum(stacktop(-2)).getint(); + int nEnd = nBegin + CBigNum(stacktop(-1)).getint(); + if (nBegin < 0 || nEnd < nBegin) + return false; + if (nBegin > vch.size()) + nBegin = vch.size(); + if (nEnd > vch.size()) + nEnd = vch.size(); + vch.erase(vch.begin() + nEnd, vch.end()); + vch.erase(vch.begin(), vch.begin() + nBegin); + stack.pop_back(); + stack.pop_back(); + } + break; + + case OP_LEFT: + case OP_RIGHT: + { + // (in size -- out) + if (stack.size() < 2) + return false; + valtype& vch = stacktop(-2); + int nSize = CBigNum(stacktop(-1)).getint(); + if (nSize < 0) + return false; + if (nSize > vch.size()) + nSize = vch.size(); + if (opcode == OP_LEFT) + vch.erase(vch.begin() + nSize, vch.end()); + else + vch.erase(vch.begin(), vch.end() - nSize); + stack.pop_back(); + } + break; + + case OP_SIZE: + { + // (in -- in size) + if (stack.size() < 1) + return false; + CBigNum bn(stacktop(-1).size()); + stack.push_back(bn.getvch()); + } + break; + + + // + // Bitwise logic + // + case OP_INVERT: + { + // (in - out) + if (stack.size() < 1) + return false; + valtype& vch = stacktop(-1); + for (int i = 0; i < vch.size(); i++) + vch[i] = ~vch[i]; + } + break; + + case OP_AND: + case OP_OR: + case OP_XOR: + { + // (x1 x2 - out) + if (stack.size() < 2) + return false; + valtype& vch1 = stacktop(-2); + valtype& vch2 = stacktop(-1); + MakeSameSize(vch1, vch2); + if (opcode == OP_AND) + { + for (int i = 0; i < vch1.size(); i++) + vch1[i] &= vch2[i]; + } + else if (opcode == OP_OR) + { + for (int i = 0; i < vch1.size(); i++) + vch1[i] |= vch2[i]; + } + else if (opcode == OP_XOR) + { + for (int i = 0; i < vch1.size(); i++) + vch1[i] ^= vch2[i]; + } + stack.pop_back(); + } + break; + + case OP_EQUAL: + case OP_EQUALVERIFY: + //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL + { + // (x1 x2 - bool) + if (stack.size() < 2) + return false; + valtype& vch1 = stacktop(-2); + valtype& vch2 = stacktop(-1); + bool fEqual = (vch1 == vch2); + // OP_NOTEQUAL is disabled because it would be too easy to say + // something like n != 1 and have some wiseguy pass in 1 with extra + // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001) + //if (opcode == OP_NOTEQUAL) + // fEqual = !fEqual; + stack.pop_back(); + stack.pop_back(); + stack.push_back(fEqual ? vchTrue : vchFalse); + if (opcode == OP_EQUALVERIFY) + { + if (fEqual) + stack.pop_back(); + else + pc = pend; + } + } + break; + + + // + // Numeric + // + case OP_1ADD: + case OP_1SUB: + case OP_2MUL: + case OP_2DIV: + case OP_NEGATE: + case OP_ABS: + case OP_NOT: + case OP_0NOTEQUAL: + { + // (in -- out) + if (stack.size() < 1) + return false; + CBigNum bn(stacktop(-1)); + switch (opcode) + { + case OP_1ADD: bn += bnOne; break; + case OP_1SUB: bn -= bnOne; break; + case OP_2MUL: bn <<= 1; break; + case OP_2DIV: bn >>= 1; break; + case OP_NEGATE: bn = -bn; break; + case OP_ABS: if (bn < bnZero) bn = -bn; break; + case OP_NOT: bn = (bn == bnZero); break; + case OP_0NOTEQUAL: bn = (bn != bnZero); break; + } + stack.pop_back(); + stack.push_back(bn.getvch()); + } + break; + + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_MOD: + case OP_LSHIFT: + case OP_RSHIFT: + case OP_BOOLAND: + case OP_BOOLOR: + case OP_NUMEQUAL: + case OP_NUMEQUALVERIFY: + case OP_NUMNOTEQUAL: + case OP_LESSTHAN: + case OP_GREATERTHAN: + case OP_LESSTHANOREQUAL: + case OP_GREATERTHANOREQUAL: + case OP_MIN: + case OP_MAX: + { + // (x1 x2 -- out) + if (stack.size() < 2) + return false; + CBigNum bn1(stacktop(-2)); + CBigNum bn2(stacktop(-1)); + CBigNum bn; + switch (opcode) + { + case OP_ADD: + bn = bn1 + bn2; + break; + + case OP_SUB: + bn = bn1 - bn2; + break; + + case OP_MUL: + if (!BN_mul(&bn, &bn1, &bn2, pctx)) + return false; + break; + + case OP_DIV: + if (!BN_div(&bn, NULL, &bn1, &bn2, pctx)) + return false; + break; + + case OP_MOD: + if (!BN_mod(&bn, &bn1, &bn2, pctx)) + return false; + break; + + case OP_LSHIFT: + if (bn2 < bnZero) + return false; + bn = bn1 << bn2.getulong(); + break; + + case OP_RSHIFT: + if (bn2 < bnZero) + return false; + bn = bn1 >> bn2.getulong(); + break; + + case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; + case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; + case OP_NUMEQUAL: bn = (bn1 == bn2); break; + case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; + case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; + case OP_LESSTHAN: bn = (bn1 < bn2); break; + case OP_GREATERTHAN: bn = (bn1 > bn2); break; + case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; + case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; + case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; + case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; + } + stack.pop_back(); + stack.pop_back(); + stack.push_back(bn.getvch()); + + if (opcode == OP_NUMEQUALVERIFY) + { + if (CastToBool(stacktop(-1))) + stack.pop_back(); + else + pc = pend; + } + } + break; + + case OP_WITHIN: + { + // (x min max -- out) + if (stack.size() < 3) + return false; + CBigNum bn1(stacktop(-3)); + CBigNum bn2(stacktop(-2)); + CBigNum bn3(stacktop(-1)); + bool fValue = (bn2 <= bn1 && bn1 < bn3); + stack.pop_back(); + stack.pop_back(); + stack.pop_back(); + stack.push_back(fValue ? vchTrue : vchFalse); + } + break; + + + // + // Crypto + // + case OP_RIPEMD160: + case OP_SHA1: + case OP_SHA256: + case OP_HASH160: + case OP_HASH256: + { + // (in -- hash) + if (stack.size() < 1) + return false; + valtype& vch = stacktop(-1); + valtype vchHash(opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160 ? 20 : 32); + if (opcode == OP_RIPEMD160) + RIPEMD160(&vch[0], vch.size(), &vchHash[0]); + else if (opcode == OP_SHA1) + SHA1(&vch[0], vch.size(), &vchHash[0]); + else if (opcode == OP_SHA256) + SHA256(&vch[0], vch.size(), &vchHash[0]); + else if (opcode == OP_HASH160) + { + uint160 hash160 = Hash160(vch); + memcpy(&vchHash[0], &hash160, sizeof(hash160)); + } + else if (opcode == OP_HASH256) + { + uint256 hash = Hash(vch.begin(), vch.end()); + memcpy(&vchHash[0], &hash, sizeof(hash)); + } + stack.pop_back(); + stack.push_back(vchHash); + } + break; + + case OP_CODESEPARATOR: + { + // Hash starts after the code separator + pbegincodehash = pc; + } + break; + + case OP_CHECKSIG: + case OP_CHECKSIGVERIFY: + { + // (sig pubkey -- bool) + if (stack.size() < 2) + return false; + + valtype& vchSig = stacktop(-2); + valtype& vchPubKey = stacktop(-1); + + ////// debug print + //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n"); + //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n"); + + // Subset of script starting at the most recent codeseparator + CScript scriptCode(pbegincodehash, pend); + + // Drop the signature, since there's no way for a signature to sign itself + scriptCode.FindAndDelete(CScript(vchSig)); + + bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); + + stack.pop_back(); + stack.pop_back(); + stack.push_back(fSuccess ? vchTrue : vchFalse); + if (opcode == OP_CHECKSIGVERIFY) + { + if (fSuccess) + stack.pop_back(); + else + pc = pend; + } + } + break; + + case OP_CHECKMULTISIG: + case OP_CHECKMULTISIGVERIFY: + { + // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) + + int i = 1; + if (stack.size() < i) + return false; + + int nKeysCount = CBigNum(stacktop(-i)).getint(); + if (nKeysCount < 0) + return false; + int ikey = ++i; + i += nKeysCount; + if (stack.size() < i) + return false; + + int nSigsCount = CBigNum(stacktop(-i)).getint(); + if (nSigsCount < 0 || nSigsCount > nKeysCount) + return false; + int isig = ++i; + i += nSigsCount; + if (stack.size() < i) + return false; + + // Subset of script starting at the most recent codeseparator + CScript scriptCode(pbegincodehash, pend); + + // Drop the signatures, since there's no way for a signature to sign itself + for (int i = 0; i < nSigsCount; i++) + { + valtype& vchSig = stacktop(-isig-i); + scriptCode.FindAndDelete(CScript(vchSig)); + } + + bool fSuccess = true; + while (fSuccess && nSigsCount > 0) + { + valtype& vchSig = stacktop(-isig); + valtype& vchPubKey = stacktop(-ikey); + + // Check signature + if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType)) + { + isig++; + nSigsCount--; + } + ikey++; + nKeysCount--; + + // If there are more signatures left than keys left, + // then too many signatures have failed + if (nSigsCount > nKeysCount) + fSuccess = false; + } + + while (i-- > 0) + stack.pop_back(); + stack.push_back(fSuccess ? vchTrue : vchFalse); + + if (opcode == OP_CHECKMULTISIGVERIFY) + { + if (fSuccess) + stack.pop_back(); + else + pc = pend; + } + } + break; + + default: + return false; + } + } + + + if (pvStackRet) + *pvStackRet = stack; + return (stack.empty() ? false : CastToBool(stack.back())); +} + +#undef top + + + + + + + + + +uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + if (nIn >= txTo.vin.size()) + { + printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); + return 1; + } + CTransaction txTmp(txTo); + + // In case concatenating two scripts ends up with two codeseparators, + // or an extra one at the end, this prevents all those possible incompatibilities. + scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); + + // Blank out other inputs' signatures + for (int i = 0; i < txTmp.vin.size(); i++) + txTmp.vin[i].scriptSig = CScript(); + txTmp.vin[nIn].scriptSig = scriptCode; + + // Blank out some of the outputs + if ((nHashType & 0x1f) == SIGHASH_NONE) + { + // Wildcard payee + txTmp.vout.clear(); + + // Let the others update at will + for (int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + else if ((nHashType & 0x1f) == SIGHASH_SINGLE) + { + // Only lockin the txout payee at same index as txin + unsigned int nOut = nIn; + if (nOut >= txTmp.vout.size()) + { + printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); + return 1; + } + txTmp.vout.resize(nOut+1); + for (int i = 0; i < nOut; i++) + txTmp.vout[i].SetNull(); + + // Let the others update at will + for (int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + + // Blank out other inputs completely, not recommended for open transactions + if (nHashType & SIGHASH_ANYONECANPAY) + { + txTmp.vin[0] = txTmp.vin[nIn]; + txTmp.vin.resize(1); + } + + // Serialize and hash + CDataStream ss(SER_GETHASH); + ss.reserve(10000); + ss << txTmp << nHashType; + return Hash(ss.begin(), ss.end()); +} + + +bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, + const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + + // Hash type is one byte tacked on to the end of the signature + if (vchSig.empty()) + return false; + if (nHashType == 0) + nHashType = vchSig.back(); + else if (nHashType != vchSig.back()) + return false; + vchSig.pop_back(); + + if (key.Verify(SignatureHash(scriptCode, txTo, nIn, nHashType), vchSig)) + return true; + + return false; +} + + + + + + + + + + + +bool Solver(const CScript& scriptPubKey, vector >& vSolutionRet) +{ + // Templates + static vector vTemplates; + if (vTemplates.empty()) + { + // Standard tx, sender provides pubkey, receiver adds signature + vTemplates.push_back(CScript() << OP_PUBKEY << OP_CHECKSIG); + + // Short account number tx, sender provides hash of pubkey, receiver provides signature and pubkey + vTemplates.push_back(CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG); + } + + // Scan templates + const CScript& script1 = scriptPubKey; + foreach(const CScript& script2, vTemplates) + { + vSolutionRet.clear(); + opcodetype opcode1, opcode2; + vector vch1, vch2; + + // Compare + CScript::const_iterator pc1 = script1.begin(); + CScript::const_iterator pc2 = script2.begin(); + loop + { + bool f1 = script1.GetOp(pc1, opcode1, vch1); + bool f2 = script2.GetOp(pc2, opcode2, vch2); + if (!f1 && !f2) + { + // Success + reverse(vSolutionRet.begin(), vSolutionRet.end()); + return true; + } + else if (f1 != f2) + { + break; + } + else if (opcode2 == OP_PUBKEY) + { + if (vch1.size() <= sizeof(uint256)) + break; + vSolutionRet.push_back(make_pair(opcode2, vch1)); + } + else if (opcode2 == OP_PUBKEYHASH) + { + if (vch1.size() != sizeof(uint160)) + break; + vSolutionRet.push_back(make_pair(opcode2, vch1)); + } + else if (opcode1 != opcode2) + { + break; + } + } + } + + vSolutionRet.clear(); + return false; +} + + +bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet) +{ + scriptSigRet.clear(); + + vector > vSolution; + if (!Solver(scriptPubKey, vSolution)) + return false; + + // Compile solution + CRITICAL_BLOCK(cs_mapKeys) + { + foreach(PAIRTYPE(opcodetype, valtype)& item, vSolution) + { + if (item.first == OP_PUBKEY) + { + // Sign + const valtype& vchPubKey = item.second; + if (!mapKeys.count(vchPubKey)) + return false; + if (hash != 0) + { + vector vchSig; + if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig)) + return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig; + } + } + else if (item.first == OP_PUBKEYHASH) + { + // Sign and give pubkey + map::iterator mi = mapPubKeys.find(uint160(item.second)); + if (mi == mapPubKeys.end()) + return false; + const vector& vchPubKey = (*mi).second; + if (!mapKeys.count(vchPubKey)) + return false; + if (hash != 0) + { + vector vchSig; + if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig)) + return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig << vchPubKey; + } + } + } + } + + return true; +} + + +bool IsMine(const CScript& scriptPubKey) +{ + CScript scriptSig; + return Solver(scriptPubKey, 0, 0, scriptSig); +} + + +bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector& vchPubKeyRet) +{ + vchPubKeyRet.clear(); + + vector > vSolution; + if (!Solver(scriptPubKey, vSolution)) + return false; + + CRITICAL_BLOCK(cs_mapKeys) + { + foreach(PAIRTYPE(opcodetype, valtype)& item, vSolution) + { + valtype vchPubKey; + if (item.first == OP_PUBKEY) + { + vchPubKey = item.second; + } + else if (item.first == OP_PUBKEYHASH) + { + map::iterator mi = mapPubKeys.find(uint160(item.second)); + if (mi == mapPubKeys.end()) + continue; + vchPubKey = (*mi).second; + } + if (!fMineOnly || mapKeys.count(vchPubKey)) + { + vchPubKeyRet = vchPubKey; + return true; + } + } + } + return false; +} + + +bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret) +{ + hash160Ret = 0; + + vector > vSolution; + if (!Solver(scriptPubKey, vSolution)) + return false; + + foreach(PAIRTYPE(opcodetype, valtype)& item, vSolution) + { + if (item.first == OP_PUBKEYHASH) + { + hash160Ret = uint160(item.second); + return true; + } + } + return false; +} + + +bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq) +{ + assert(nIn < txTo.vin.size()); + CTxIn& txin = txTo.vin[nIn]; + assert(txin.prevout.n < txFrom.vout.size()); + const CTxOut& txout = txFrom.vout[txin.prevout.n]; + + // Leave out the signature from the hash, since a signature can't sign itself. + // The checksig op will also drop the signatures from its hash. + uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType); + + if (!Solver(txout.scriptPubKey, hash, nHashType, txin.scriptSig)) + return false; + + txin.scriptSig = scriptPrereq + txin.scriptSig; + + // Test solution + if (scriptPrereq.empty()) + if (!EvalScript(txin.scriptSig + CScript(OP_CODESEPARATOR) + txout.scriptPubKey, txTo, nIn)) + return false; + + return true; +} + + +bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + assert(nIn < txTo.vin.size()); + const CTxIn& txin = txTo.vin[nIn]; + if (txin.prevout.n >= txFrom.vout.size()) + return false; + const CTxOut& txout = txFrom.vout[txin.prevout.n]; + + if (txin.prevout.hash != txFrom.GetHash()) + return false; + + return EvalScript(txin.scriptSig + CScript(OP_CODESEPARATOR) + txout.scriptPubKey, txTo, nIn, nHashType); +} diff --git a/script.h b/script.h new file mode 100644 index 000000000..0d977734b --- /dev/null +++ b/script.h @@ -0,0 +1,597 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +class CTransaction; + +enum +{ + SIGHASH_ALL = 1, + SIGHASH_NONE = 2, + SIGHASH_SINGLE = 3, + SIGHASH_ANYONECANPAY = 0x80, +}; + + + +enum opcodetype +{ + // push value + OP_0=0, + OP_FALSE=OP_0, + OP_PUSHDATA1=76, + OP_PUSHDATA2, + OP_PUSHDATA4, + OP_1NEGATE, + OP_RESERVED, + OP_1, + OP_TRUE=OP_1, + OP_2, + OP_3, + OP_4, + OP_5, + OP_6, + OP_7, + OP_8, + OP_9, + OP_10, + OP_11, + OP_12, + OP_13, + OP_14, + OP_15, + OP_16, + + // control + OP_NOP, + OP_VER, + OP_IF, + OP_NOTIF, + OP_VERIF, + OP_VERNOTIF, + OP_ELSE, + OP_ENDIF, + OP_VERIFY, + OP_RETURN, + + // stack ops + OP_TOALTSTACK, + OP_FROMALTSTACK, + OP_2DROP, + OP_2DUP, + OP_3DUP, + OP_2OVER, + OP_2ROT, + OP_2SWAP, + OP_IFDUP, + OP_DEPTH, + OP_DROP, + OP_DUP, + OP_NIP, + OP_OVER, + OP_PICK, + OP_ROLL, + OP_ROT, + OP_SWAP, + OP_TUCK, + + // splice ops + OP_CAT, + OP_SUBSTR, + OP_LEFT, + OP_RIGHT, + OP_SIZE, + + // bit logic + OP_INVERT, + OP_AND, + OP_OR, + OP_XOR, + OP_EQUAL, + OP_EQUALVERIFY, + OP_RESERVED1, + OP_RESERVED2, + + // numeric + OP_1ADD, + OP_1SUB, + OP_2MUL, + OP_2DIV, + OP_NEGATE, + OP_ABS, + OP_NOT, + OP_0NOTEQUAL, + + OP_ADD, + OP_SUB, + OP_MUL, + OP_DIV, + OP_MOD, + OP_LSHIFT, + OP_RSHIFT, + + OP_BOOLAND, + OP_BOOLOR, + OP_NUMEQUAL, + OP_NUMEQUALVERIFY, + OP_NUMNOTEQUAL, + OP_LESSTHAN, + OP_GREATERTHAN, + OP_LESSTHANOREQUAL, + OP_GREATERTHANOREQUAL, + OP_MIN, + OP_MAX, + + OP_WITHIN, + + // crypto + OP_RIPEMD160, + OP_SHA1, + OP_SHA256, + OP_HASH160, + OP_HASH256, + OP_CODESEPARATOR, + OP_CHECKSIG, + OP_CHECKSIGVERIFY, + OP_CHECKMULTISIG, + OP_CHECKMULTISIGVERIFY, + + + // multi-byte opcodes + OP_SINGLEBYTE_END = 0xF0, + OP_DOUBLEBYTE_BEGIN = 0xF000, + + // template matching params + OP_PUBKEY, + OP_PUBKEYHASH, + + + + OP_INVALIDOPCODE = 0xFFFF, +}; + + + + + + + + +inline const char* GetOpName(opcodetype opcode) +{ + switch (opcode) + { + // push value + case OP_0 : return "0"; + case OP_PUSHDATA1 : return "OP_PUSHDATA1"; + case OP_PUSHDATA2 : return "OP_PUSHDATA2"; + case OP_PUSHDATA4 : return "OP_PUSHDATA4"; + case OP_1NEGATE : return "-1"; + case OP_RESERVED : return "OP_RESERVED"; + case OP_1 : return "1"; + case OP_2 : return "2"; + case OP_3 : return "3"; + case OP_4 : return "4"; + case OP_5 : return "5"; + case OP_6 : return "6"; + case OP_7 : return "7"; + case OP_8 : return "8"; + case OP_9 : return "9"; + case OP_10 : return "10"; + case OP_11 : return "11"; + case OP_12 : return "12"; + case OP_13 : return "13"; + case OP_14 : return "14"; + case OP_15 : return "15"; + case OP_16 : return "16"; + + // control + case OP_NOP : return "OP_NOP"; + case OP_VER : return "OP_VER"; + case OP_IF : return "OP_IF"; + case OP_NOTIF : return "OP_NOTIF"; + case OP_VERIF : return "OP_VERIF"; + case OP_VERNOTIF : return "OP_VERNOTIF"; + case OP_ELSE : return "OP_ELSE"; + case OP_ENDIF : return "OP_ENDIF"; + case OP_VERIFY : return "OP_VERIFY"; + case OP_RETURN : return "OP_RETURN"; + + // stack ops + case OP_TOALTSTACK : return "OP_TOALTSTACK"; + case OP_FROMALTSTACK : return "OP_FROMALTSTACK"; + case OP_2DROP : return "OP_2DROP"; + case OP_2DUP : return "OP_2DUP"; + case OP_3DUP : return "OP_3DUP"; + case OP_2OVER : return "OP_2OVER"; + case OP_2ROT : return "OP_2ROT"; + case OP_2SWAP : return "OP_2SWAP"; + case OP_IFDUP : return "OP_IFDUP"; + case OP_DEPTH : return "OP_DEPTH"; + case OP_DROP : return "OP_DROP"; + case OP_DUP : return "OP_DUP"; + case OP_NIP : return "OP_NIP"; + case OP_OVER : return "OP_OVER"; + case OP_PICK : return "OP_PICK"; + case OP_ROLL : return "OP_ROLL"; + case OP_ROT : return "OP_ROT"; + case OP_SWAP : return "OP_SWAP"; + case OP_TUCK : return "OP_TUCK"; + + // splice ops + case OP_CAT : return "OP_CAT"; + case OP_SUBSTR : return "OP_SUBSTR"; + case OP_LEFT : return "OP_LEFT"; + case OP_RIGHT : return "OP_RIGHT"; + case OP_SIZE : return "OP_SIZE"; + + // bit logic + case OP_INVERT : return "OP_INVERT"; + case OP_AND : return "OP_AND"; + case OP_OR : return "OP_OR"; + case OP_XOR : return "OP_XOR"; + case OP_EQUAL : return "OP_EQUAL"; + case OP_EQUALVERIFY : return "OP_EQUALVERIFY"; + case OP_RESERVED1 : return "OP_RESERVED1"; + case OP_RESERVED2 : return "OP_RESERVED2"; + + // numeric + case OP_1ADD : return "OP_1ADD"; + case OP_1SUB : return "OP_1SUB"; + case OP_2MUL : return "OP_2MUL"; + case OP_2DIV : return "OP_2DIV"; + case OP_NEGATE : return "OP_NEGATE"; + case OP_ABS : return "OP_ABS"; + case OP_NOT : return "OP_NOT"; + case OP_0NOTEQUAL : return "OP_0NOTEQUAL"; + case OP_ADD : return "OP_ADD"; + case OP_SUB : return "OP_SUB"; + case OP_MUL : return "OP_MUL"; + case OP_DIV : return "OP_DIV"; + case OP_MOD : return "OP_MOD"; + case OP_LSHIFT : return "OP_LSHIFT"; + case OP_RSHIFT : return "OP_RSHIFT"; + case OP_BOOLAND : return "OP_BOOLAND"; + case OP_BOOLOR : return "OP_BOOLOR"; + case OP_NUMEQUAL : return "OP_NUMEQUAL"; + case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY"; + case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL"; + case OP_LESSTHAN : return "OP_LESSTHAN"; + case OP_GREATERTHAN : return "OP_GREATERTHAN"; + case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL"; + case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL"; + case OP_MIN : return "OP_MIN"; + case OP_MAX : return "OP_MAX"; + case OP_WITHIN : return "OP_WITHIN"; + + // crypto + case OP_RIPEMD160 : return "OP_RIPEMD160"; + case OP_SHA1 : return "OP_SHA1"; + case OP_SHA256 : return "OP_SHA256"; + case OP_HASH160 : return "OP_HASH160"; + case OP_HASH256 : return "OP_HASH256"; + case OP_CODESEPARATOR : return "OP_CODESEPARATOR"; + case OP_CHECKSIG : return "OP_CHECKSIG"; + case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY"; + case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG"; + case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; + + + + // multi-byte opcodes + case OP_SINGLEBYTE_END : return "OP_SINGLEBYTE_END"; + case OP_DOUBLEBYTE_BEGIN : return "OP_DOUBLEBYTE_BEGIN"; + case OP_PUBKEY : return "OP_PUBKEY"; + case OP_PUBKEYHASH : return "OP_PUBKEYHASH"; + + + + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; + default: + return "UNKNOWN_OPCODE"; + } +}; + + + + +inline string ValueString(const vector& vch) +{ + if (vch.size() <= 4) + return strprintf("%d", CBigNum(vch).getint()); + else + return HexNumStr(vch.begin(), vch.end()); + //return string("(") + HexStr(vch.begin(), vch.end()) + string(")"); +} + +inline string StackString(const vector >& vStack) +{ + string str; + foreach(const vector& vch, vStack) + { + if (!str.empty()) + str += " "; + str += ValueString(vch); + } + return str; +} + + + + + + + + + +class CScript : public vector +{ +protected: + CScript& push_int64(int64 n) + { + if (n == -1 || (n >= 1 && n <= 16)) + { + push_back(n + (OP_1 - 1)); + } + else + { + CBigNum bn(n); + *this << bn.getvch(); + } + return (*this); + } + + CScript& push_uint64(uint64 n) + { + if (n == -1 || (n >= 1 && n <= 16)) + { + push_back(n + (OP_1 - 1)); + } + else + { + CBigNum bn(n); + *this << bn.getvch(); + } + return (*this); + } + +public: + CScript() { } + CScript(const CScript& b) : vector(b.begin(), b.end()) { } + CScript(const_iterator pbegin, const_iterator pend) : vector(pbegin, pend) { } +#ifndef _MSC_VER + CScript(const unsigned char* pbegin, const unsigned char* pend) : vector(pbegin, pend) { } +#endif + + CScript& operator+=(const CScript& b) + { + insert(end(), b.begin(), b.end()); + return *this; + } + + friend CScript operator+(const CScript& a, const CScript& b) + { + CScript ret = a; + ret += b; + return (ret); + } + + + explicit CScript(char b) { operator<<(b); } + explicit CScript(short b) { operator<<(b); } + explicit CScript(int b) { operator<<(b); } + explicit CScript(long b) { operator<<(b); } + explicit CScript(int64 b) { operator<<(b); } + explicit CScript(unsigned char b) { operator<<(b); } + explicit CScript(unsigned int b) { operator<<(b); } + explicit CScript(unsigned short b) { operator<<(b); } + explicit CScript(unsigned long b) { operator<<(b); } + explicit CScript(uint64 b) { operator<<(b); } + + explicit CScript(opcodetype b) { operator<<(b); } + explicit CScript(const uint256& b) { operator<<(b); } + explicit CScript(const CBigNum& b) { operator<<(b); } + explicit CScript(const vector& b) { operator<<(b); } + + + CScript& operator<<(char b) { return (push_int64(b)); } + CScript& operator<<(short b) { return (push_int64(b)); } + CScript& operator<<(int b) { return (push_int64(b)); } + CScript& operator<<(long b) { return (push_int64(b)); } + CScript& operator<<(int64 b) { return (push_int64(b)); } + CScript& operator<<(unsigned char b) { return (push_uint64(b)); } + CScript& operator<<(unsigned int b) { return (push_uint64(b)); } + CScript& operator<<(unsigned short b) { return (push_uint64(b)); } + CScript& operator<<(unsigned long b) { return (push_uint64(b)); } + CScript& operator<<(uint64 b) { return (push_uint64(b)); } + + CScript& operator<<(opcodetype opcode) + { + if (opcode <= OP_SINGLEBYTE_END) + { + insert(end(), (unsigned char)opcode); + } + else + { + assert(opcode >= OP_DOUBLEBYTE_BEGIN); + insert(end(), (unsigned char)(opcode >> 8)); + insert(end(), (unsigned char)(opcode & 0xFF)); + } + return (*this); + } + + CScript& operator<<(const uint160& b) + { + insert(end(), sizeof(b)); + insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b)); + return (*this); + } + + CScript& operator<<(const uint256& b) + { + insert(end(), sizeof(b)); + insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b)); + return (*this); + } + + CScript& operator<<(const CBigNum& b) + { + *this << b.getvch(); + return (*this); + } + + CScript& operator<<(const vector& b) + { + if (b.size() < OP_PUSHDATA1) + { + insert(end(), (unsigned char)b.size()); + } + else if (b.size() <= 0xff) + { + insert(end(), OP_PUSHDATA1); + insert(end(), (unsigned char)b.size()); + } + else + { + insert(end(), OP_PUSHDATA2); + unsigned short nSize = b.size(); + insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize)); + } + insert(end(), b.begin(), b.end()); + return (*this); + } + + CScript& operator<<(const CScript& b) + { + // I'm not sure if this should push the script or concatenate scripts. + // If there's ever a use for pushing a script onto a script, delete this member fn + assert(("warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate", false)); + return (*this); + } + + + bool GetOp(iterator& pc, opcodetype& opcodeRet, vector& vchRet) + { + // This is why people hate C++ + const_iterator pc2 = pc; + bool fRet = GetOp(pc2, opcodeRet, vchRet); + pc = begin() + (pc2 - begin()); + return fRet; + } + + bool GetOp(const_iterator& pc, opcodetype& opcodeRet, vector& vchRet) const + { + opcodeRet = OP_INVALIDOPCODE; + vchRet.clear(); + if (pc >= end()) + return false; + + // Read instruction + unsigned int opcode = *pc++; + if (opcode >= OP_SINGLEBYTE_END) + { + if (pc + 1 > end()) + return false; + opcode <<= 8; + opcode |= *pc++; + } + + // Immediate operand + if (opcode <= OP_PUSHDATA4) + { + unsigned int nSize = opcode; + if (opcode == OP_PUSHDATA1) + { + if (pc + 1 > end()) + return false; + nSize = *pc++; + } + else if (opcode == OP_PUSHDATA2) + { + if (pc + 2 > end()) + return false; + nSize = 0; + memcpy(&nSize, &pc[0], 2); + pc += 2; + } + else if (opcode == OP_PUSHDATA4) + { + if (pc + 4 > end()) + return false; + memcpy(&nSize, &pc[0], 4); + pc += 4; + } + if (pc + nSize > end()) + return false; + vchRet.assign(pc, pc + nSize); + pc += nSize; + } + + opcodeRet = (opcodetype)opcode; + return true; + } + + + void FindAndDelete(const CScript& b) + { + iterator pc = begin(); + opcodetype opcode; + vector vchPushValue; + int count = 0; + do + { + while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0) + { + erase(pc, pc + b.size()); + count++; + } + } + while (GetOp(pc, opcode, vchPushValue)); + //printf("FindAndDeleted deleted %d items\n", count); /// debug + } + + + void PrintHex() const + { + printf("CScript(%s)\n", HexStr(begin(), end()).c_str()); + } + + string ToString() const + { + string str; + opcodetype opcode; + vector vch; + const_iterator it = begin(); + while (GetOp(it, opcode, vch)) + { + if (!str.empty()) + str += " "; + if (opcode <= OP_PUSHDATA4) + str += ValueString(vch); + else + str += GetOpName(opcode); + } + return str; + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + + + + + +bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType=0, + vector >* pvStackRet=NULL); +uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +bool IsMine(const CScript& scriptPubKey); +bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector& vchPubKeyRet); +bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret); +bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript()); +bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0); diff --git a/serialize.h b/serialize.h new file mode 100644 index 000000000..b7ab86d22 --- /dev/null +++ b/serialize.h @@ -0,0 +1,1158 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int64; +typedef unsigned long long uint64; +#endif +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define for if (false) ; else for +#endif +class CScript; +class CDataStream; +class CAutoFile; + +static const int VERSION = 105; + + + + + +///////////////////////////////////////////////////////////////// +// +// Templates for serializing to anything that looks like a stream, +// i.e. anything that supports .read(char*, int) and .write(char*, int) +// + +enum +{ + // primary actions + SER_NETWORK = (1 << 0), + SER_DISK = (1 << 1), + SER_GETHASH = (1 << 2), + + // modifiers + SER_SKIPSIG = (1 << 16), + SER_BLOCKHEADERONLY = (1 << 17), +}; + +#define IMPLEMENT_SERIALIZE(statements) \ + unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const \ + { \ + CSerActionGetSerializeSize ser_action; \ + const bool fGetSize = true; \ + const bool fWrite = false; \ + const bool fRead = false; \ + unsigned int nSerSize = 0; \ + ser_streamplaceholder s; \ + s.nType = nType; \ + s.nVersion = nVersion; \ + {statements} \ + return nSerSize; \ + } \ + template \ + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const \ + { \ + CSerActionSerialize ser_action; \ + const bool fGetSize = false; \ + const bool fWrite = true; \ + const bool fRead = false; \ + unsigned int nSerSize = 0; \ + {statements} \ + } \ + template \ + void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) \ + { \ + CSerActionUnserialize ser_action; \ + const bool fGetSize = false; \ + const bool fWrite = false; \ + const bool fRead = true; \ + unsigned int nSerSize = 0; \ + {statements} \ + } + +#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) + + + + + + +// +// Basic types +// +#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) +#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) + +inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } + +template inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } + +template inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); } + +inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } +template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } +template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } + + + + + + +// +// Compact size +// size < 253 -- 1 byte +// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) +// size <= UINT_MAX -- 5 bytes (254 + 4 bytes) +// size > UINT_MAX -- 9 bytes (255 + 8 bytes) +// +inline unsigned int GetSizeOfCompactSize(uint64 nSize) +{ + if (nSize < UCHAR_MAX-2) return sizeof(unsigned char); + else if (nSize <= USHRT_MAX) return sizeof(unsigned char) + sizeof(unsigned short); + else if (nSize <= UINT_MAX) return sizeof(unsigned char) + sizeof(unsigned int); + else return sizeof(unsigned char) + sizeof(uint64); +} + +template +void WriteCompactSize(Stream& os, uint64 nSize) +{ + if (nSize < UCHAR_MAX-2) + { + unsigned char chSize = nSize; + WRITEDATA(os, chSize); + } + else if (nSize <= USHRT_MAX) + { + unsigned char chSize = UCHAR_MAX-2; + unsigned short xSize = nSize; + WRITEDATA(os, chSize); + WRITEDATA(os, xSize); + } + else if (nSize <= UINT_MAX) + { + unsigned char chSize = UCHAR_MAX-1; + unsigned int xSize = nSize; + WRITEDATA(os, chSize); + WRITEDATA(os, xSize); + } + else + { + unsigned char chSize = UCHAR_MAX; + WRITEDATA(os, chSize); + WRITEDATA(os, nSize); + } + return; +} + +template +uint64 ReadCompactSize(Stream& is) +{ + unsigned char chSize; + READDATA(is, chSize); + if (chSize < UCHAR_MAX-2) + { + return chSize; + } + else if (chSize == UCHAR_MAX-2) + { + unsigned short nSize; + READDATA(is, nSize); + return nSize; + } + else if (chSize == UCHAR_MAX-1) + { + unsigned int nSize; + READDATA(is, nSize); + return nSize; + } + else + { + uint64 nSize; + READDATA(is, nSize); + return nSize; + } +} + + + +// +// Wrapper for serializing arrays and POD +// There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it +// +#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +class CFlatData +{ +protected: + char* pbegin; + char* pend; +public: + CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } + char* begin() { return pbegin; } + const char* begin() const { return pbegin; } + char* end() { return pend; } + const char* end() const { return pend; } + + unsigned int GetSerializeSize(int, int=0) const + { + return pend - pbegin; + } + + template + void Serialize(Stream& s, int, int=0) const + { + s.write(pbegin, pend - pbegin); + } + + template + void Unserialize(Stream& s, int, int=0) + { + s.read(pbegin, pend - pbegin); + } +}; + + + +// +// string stored as a fixed length field +// +template +class CFixedFieldString +{ +protected: + const string* pcstr; + string* pstr; +public: + explicit CFixedFieldString(const string& str) : pcstr(&str), pstr(NULL) { } + explicit CFixedFieldString(string& str) : pcstr(&str), pstr(&str) { } + + unsigned int GetSerializeSize(int, int=0) const + { + return LEN; + } + + template + void Serialize(Stream& s, int, int=0) const + { + char pszBuf[LEN]; + strncpy(pszBuf, pcstr->c_str(), LEN); + s.write(pszBuf, LEN); + } + + template + void Unserialize(Stream& s, int, int=0) + { + if (pstr == NULL) + throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string"); + char pszBuf[LEN+1]; + s.read(pszBuf, LEN); + pszBuf[LEN] = '\0'; + *pstr = pszBuf; + } +}; + + + + + +// +// Forward declarations +// + +// string +template unsigned int GetSerializeSize(const basic_string& str, int, int=0); +template void Serialize(Stream& os, const basic_string& str, int, int=0); +template void Unserialize(Stream& is, basic_string& str, int, int=0); + +// vector +template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&); +template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion=VERSION); +template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&); +template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion=VERSION); +template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&); +template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion=VERSION); + +// others derived from vector +extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const CScript& v, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, CScript& v, int nType, int nVersion=VERSION); + +// pair +template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion=VERSION); + +// map +template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const std::map& m, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, std::map& m, int nType, int nVersion=VERSION); + +// set +template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const std::set& m, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, std::set& m, int nType, int nVersion=VERSION); + + + + + +// +// If none of the specialized versions above matched, default to calling member function. +// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. +// The compiler will only cast int to long if none of the other templates matched. +// Thanks to Boost serialization for this idea. +// +template +inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=VERSION) +{ + return a.GetSerializeSize((int)nType, nVersion); +} + +template +inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION) +{ + a.Serialize(os, (int)nType, nVersion); +} + +template +inline void Unserialize(Stream& is, T& a, long nType, int nVersion=VERSION) +{ + a.Unserialize(is, (int)nType, nVersion); +} + + + + + +// +// string +// +template +unsigned int GetSerializeSize(const basic_string& str, int, int) +{ + return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); +} + +template +void Serialize(Stream& os, const basic_string& str, int, int) +{ + WriteCompactSize(os, str.size()); + if (!str.empty()) + os.write((char*)&str[0], str.size() * sizeof(str[0])); +} + +template +void Unserialize(Stream& is, basic_string& str, int, int) +{ + unsigned int nSize = ReadCompactSize(is); + str.resize(nSize); + if (nSize != 0) + is.read((char*)&str[0], nSize * sizeof(str[0])); +} + + + +// +// vector +// +template +unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); +} + +template +unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + unsigned int nSize = GetSizeOfCompactSize(v.size()); + for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + nSize += GetSerializeSize((*vi), nType, nVersion); + return nSize; +} + +template +inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) +{ + return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental()); +} + + +template +void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + WriteCompactSize(os, v.size()); + if (!v.empty()) + os.write((char*)&v[0], v.size() * sizeof(T)); +} + +template +void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + WriteCompactSize(os, v.size()); + for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + ::Serialize(os, (*vi), nType, nVersion); +} + +template +inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) +{ + Serialize_impl(os, v, nType, nVersion, boost::is_fundamental()); +} + + +template +void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + //unsigned int nSize = ReadCompactSize(is); + //v.resize(nSize); + //is.read((char*)&v[0], nSize * sizeof(T)); + + // Limit size per read so bogus size value won't cause out of memory + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + while (i < nSize) + { + unsigned int blk = min(nSize - i, 1 + 4999999 / sizeof(T)); + v.resize(i + blk); + is.read((char*)&v[i], blk * sizeof(T)); + i += blk; + } +} + +template +void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + //unsigned int nSize = ReadCompactSize(is); + //v.resize(nSize); + //for (std::vector::iterator vi = v.begin(); vi != v.end(); ++vi) + // Unserialize(is, (*vi), nType, nVersion); + + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + unsigned int nMid = 0; + while (nMid < nSize) + { + nMid += 5000000 / sizeof(T); + if (nMid > nSize) + nMid = nSize; + v.resize(nMid); + for (; i < nMid; i++) + Unserialize(is, v[i], nType, nVersion); + } +} + +template +inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) +{ + Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental()); +} + + + +// +// others derived from vector +// +inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) +{ + return GetSerializeSize((const vector&)v, nType, nVersion); +} + +template +void Serialize(Stream& os, const CScript& v, int nType, int nVersion) +{ + Serialize(os, (const vector&)v, nType, nVersion); +} + +template +void Unserialize(Stream& is, CScript& v, int nType, int nVersion) +{ + Unserialize(is, (vector&)v, nType, nVersion); +} + + + +// +// pair +// +template +unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) +{ + return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); +} + +template +void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) +{ + Serialize(os, item.first, nType, nVersion); + Serialize(os, item.second, nType, nVersion); +} + +template +void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) +{ + Unserialize(is, item.first, nType, nVersion); + Unserialize(is, item.second, nType, nVersion); +} + + + +// +// map +// +template +unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) +{ + unsigned int nSize = GetSizeOfCompactSize(m.size()); + for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) + nSize += GetSerializeSize((*mi), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const std::map& m, int nType, int nVersion) +{ + WriteCompactSize(os, m.size()); + for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) + Serialize(os, (*mi), nType, nVersion); +} + +template +void Unserialize(Stream& is, std::map& m, int nType, int nVersion) +{ + m.clear(); + unsigned int nSize = ReadCompactSize(is); + typename std::map::iterator mi = m.begin(); + for (unsigned int i = 0; i < nSize; i++) + { + pair item; + Unserialize(is, item, nType, nVersion); + mi = m.insert(mi, item); + } +} + + + +// +// set +// +template +unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) +{ + unsigned int nSize = GetSizeOfCompactSize(m.size()); + for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) + nSize += GetSerializeSize((*it), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const std::set& m, int nType, int nVersion) +{ + WriteCompactSize(os, m.size()); + for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) + Serialize(os, (*it), nType, nVersion); +} + +template +void Unserialize(Stream& is, std::set& m, int nType, int nVersion) +{ + m.clear(); + unsigned int nSize = ReadCompactSize(is); + typename std::set::iterator it = m.begin(); + for (unsigned int i = 0; i < nSize; i++) + { + K key; + Unserialize(is, key, nType, nVersion); + it = m.insert(it, key); + } +} + + + +// +// Support for IMPLEMENT_SERIALIZE and READWRITE macro +// +class CSerActionGetSerializeSize { }; +class CSerActionSerialize { }; +class CSerActionUnserialize { }; + +template +inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) +{ + return ::GetSerializeSize(obj, nType, nVersion); +} + +template +inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) +{ + ::Serialize(s, obj, nType, nVersion); + return 0; +} + +template +inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) +{ + ::Unserialize(s, obj, nType, nVersion); + return 0; +} + +struct ser_streamplaceholder +{ + int nType; + int nVersion; +}; + + + + + + + + + +// +// Allocator that clears its contents before deletion +// +template +struct secure_allocator : public std::allocator +{ + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + secure_allocator() throw() {} + secure_allocator(const secure_allocator& a) throw() : base(a) {} + ~secure_allocator() throw() {} + template struct rebind + { typedef secure_allocator<_Other> other; }; + + void deallocate(T* p, std::size_t n) + { + if (p != NULL) + memset(p, 0, sizeof(T) * n); + allocator::deallocate(p, n); + } +}; + + + +// +// Double ended buffer combining vector and stream-like interfaces. +// >> and << read and write unformatted data using the above serialization templates. +// Fills with data in linear time; some stringstream implementations take N^2 time. +// +class CDataStream +{ +protected: + typedef vector > vector_type; + vector_type vch; + unsigned int nReadPos; + short state; + short exceptmask; +public: + int nType; + int nVersion; + + typedef vector_type::allocator_type allocator_type; + typedef vector_type::size_type size_type; + typedef vector_type::difference_type difference_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + typedef vector_type::value_type value_type; + typedef vector_type::iterator iterator; + typedef vector_type::const_iterator const_iterator; + typedef vector_type::reverse_iterator reverse_iterator; + + explicit CDataStream(int nTypeIn=0, int nVersionIn=VERSION) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend) + { + Init(nTypeIn, nVersionIn); + } + +#if !defined(_MSC_VER) || _MSC_VER >= 1300 + CDataStream(const char* pbegin, const char* pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend) + { + Init(nTypeIn, nVersionIn); + } +#endif + + CDataStream(const vector_type& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end()) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const vector& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end()) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const vector& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) + { + Init(nTypeIn, nVersionIn); + } + + void Init(int nTypeIn=0, int nVersionIn=VERSION) + { + nReadPos = 0; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = ios::badbit | ios::failbit; + } + + CDataStream& operator+=(const CDataStream& b) + { + vch.insert(vch.end(), b.begin(), b.end()); + return *this; + } + + friend CDataStream operator+(const CDataStream& a, const CDataStream& b) + { + CDataStream ret = a; + ret += b; + return (ret); + } + + string str() const + { + return (string(begin(), end())); + } + + + // + // Vector subset + // + const_iterator begin() const { return vch.begin() + nReadPos; } + iterator begin() { return vch.begin() + nReadPos; } + const_iterator end() const { return vch.end(); } + iterator end() { return vch.end(); } + size_type size() const { return vch.size() - nReadPos; } + bool empty() const { return vch.size() == nReadPos; } + void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } + void reserve(size_type n) { vch.reserve(n + nReadPos); } + const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } + reference operator[](size_type pos) { return vch[pos + nReadPos]; } + void clear() { vch.clear(); nReadPos = 0; } + iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } + void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } + + void insert(iterator it, const_iterator first, const_iterator last) + { + if (it == vch.begin() + nReadPos && last - first <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } + +#if !defined(_MSC_VER) || _MSC_VER >= 1300 + void insert(iterator it, const char* first, const char* last) + { + if (it == vch.begin() + nReadPos && last - first <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } +#endif + + iterator erase(iterator it) + { + if (it == vch.begin() + nReadPos) + { + // special case for erasing from the front + if (++nReadPos >= vch.size()) + { + // whenever we reach the end, we take the opportunity to clear the buffer + nReadPos = 0; + return vch.erase(vch.begin(), vch.end()); + } + return vch.begin() + nReadPos; + } + else + return vch.erase(it); + } + + iterator erase(iterator first, iterator last) + { + if (first == vch.begin() + nReadPos) + { + // special case for erasing from the front + if (last == vch.end()) + { + nReadPos = 0; + return vch.erase(vch.begin(), vch.end()); + } + else + { + nReadPos = (last - vch.begin()); + return last; + } + } + else + return vch.erase(first, last); + } + + inline void Compact() + { + vch.erase(vch.begin(), vch.begin() + nReadPos); + nReadPos = 0; + } + + bool Rewind(size_type n) + { + // Rewind by n characters if the buffer hasn't been compacted yet + if (n > nReadPos) + return false; + nReadPos -= n; + return true; + } + + + // + // Stream subset + // + void setstate(short bits, const char* psz) + { + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); + } + + bool eof() const { return size() == 0; } + bool fail() const { return state & (ios::badbit | ios::failbit); } + bool good() const { return !eof() && (state == 0); } + void clear(short n) { state = n; } // name conflict with vector clear() + short exceptions() { return exceptmask; } + short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } + CDataStream* rdbuf() { return this; } + int in_avail() { return size(); } + + void SetType(int n) { nType = n; } + int GetType() { return nType; } + void SetVersion(int n) { nVersion = n; } + int GetVersion() { return nVersion; } + void ReadVersion() { *this >> nVersion; } + void WriteVersion() { *this << nVersion; } + + CDataStream& read(char* pch, int nSize) + { + // Read from the beginning of the buffer + assert(nSize >= 0); + unsigned int nReadPosNext = nReadPos + nSize; + if (nReadPosNext >= vch.size()) + { + if (nReadPosNext > vch.size()) + { + setstate(ios::failbit, "CDataStream::read() : end of data"); + memset(pch, 0, nSize); + nSize = vch.size() - nReadPos; + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = 0; + vch.clear(); + return (*this); + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = nReadPosNext; + return (*this); + } + + CDataStream& ignore(int nSize) + { + // Ignore from the beginning of the buffer + assert(nSize >= 0); + unsigned int nReadPosNext = nReadPos + nSize; + if (nReadPosNext >= vch.size()) + { + if (nReadPosNext > vch.size()) + { + setstate(ios::failbit, "CDataStream::ignore() : end of data"); + nSize = vch.size() - nReadPos; + } + nReadPos = 0; + vch.clear(); + return (*this); + } + nReadPos = nReadPosNext; + return (*this); + } + + CDataStream& write(const char* pch, int nSize) + { + // Write to the end of the buffer + assert(nSize >= 0); + vch.insert(vch.end(), pch, pch + nSize); + return (*this); + } + + template + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const + { + // Special case: stream << stream concatenates like stream += stream + if (!vch.empty()) + s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); + } + + template + unsigned int GetSerializeSize(const T& obj) + { + // Tells the size of the object if serialized to this stream + return ::GetSerializeSize(obj, nType, nVersion); + } + + template + CDataStream& operator<<(const T& obj) + { + // Serialize to this stream + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } + + template + CDataStream& operator>>(T& obj) + { + // Unserialize from this stream + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } +}; + +#ifdef TESTCDATASTREAM +// VC6sp6 +// CDataStream: +// n=1000 0 seconds +// n=2000 0 seconds +// n=4000 0 seconds +// n=8000 0 seconds +// n=16000 0 seconds +// n=32000 0 seconds +// n=64000 1 seconds +// n=128000 1 seconds +// n=256000 2 seconds +// n=512000 4 seconds +// n=1024000 8 seconds +// n=2048000 16 seconds +// n=4096000 32 seconds +// stringstream: +// n=1000 1 seconds +// n=2000 1 seconds +// n=4000 13 seconds +// n=8000 87 seconds +// n=16000 400 seconds +// n=32000 1660 seconds +// n=64000 6749 seconds +// n=128000 27241 seconds +// n=256000 109804 seconds +#include +int main(int argc, char *argv[]) +{ + vector vch(0xcc, 250); + printf("CDataStream:\n"); + for (int n = 1000; n <= 4500000; n *= 2) + { + CDataStream ss; + time_t nStart = time(NULL); + for (int i = 0; i < n; i++) + ss.write((char*)&vch[0], vch.size()); + printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); + } + printf("stringstream:\n"); + for (int n = 1000; n <= 4500000; n *= 2) + { + stringstream ss; + time_t nStart = time(NULL); + for (int i = 0; i < n; i++) + ss.write((char*)&vch[0], vch.size()); + printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); + } +} +#endif + + + + + + + + + + +// +// Automatic closing wrapper for FILE* +// - Will automatically close the file when it goes out of scope if not null. +// - If you're returning the file pointer, return file.release(). +// - If you need to close the file early, use file.fclose() instead of fclose(file). +// +class CAutoFile +{ +protected: + FILE* file; + short state; + short exceptmask; +public: + int nType; + int nVersion; + + typedef FILE element_type; + + CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=VERSION) + { + file = filenew; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = ios::badbit | ios::failbit; + } + + ~CAutoFile() + { + fclose(); + } + + void fclose() + { + if (file != NULL && file != stdin && file != stdout && file != stderr) + ::fclose(file); + file = NULL; + } + + FILE* release() { FILE* ret = file; file = NULL; return ret; } + operator FILE*() { return file; } + FILE* operator->() { return file; } + FILE& operator*() { return *file; } + FILE** operator&() { return &file; } + FILE* operator=(FILE* pnew) { return file = pnew; } + bool operator!() { return (file == NULL); } + + + // + // Stream subset + // + void setstate(short bits, const char* psz) + { + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); + } + + bool fail() const { return state & (ios::badbit | ios::failbit); } + bool good() const { return state == 0; } + void clear(short n = 0) { state = n; } + short exceptions() { return exceptmask; } + short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } + + void SetType(int n) { nType = n; } + int GetType() { return nType; } + void SetVersion(int n) { nVersion = n; } + int GetVersion() { return nVersion; } + void ReadVersion() { *this >> nVersion; } + void WriteVersion() { *this << nVersion; } + + CAutoFile& read(char* pch, int nSize) + { + if (!file) + throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); + if (fread(pch, 1, nSize, file) != nSize) + setstate(ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); + return (*this); + } + + CAutoFile& write(const char* pch, int nSize) + { + if (!file) + throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); + if (fwrite(pch, 1, nSize, file) != nSize) + setstate(ios::failbit, "CAutoFile::write : write failed"); + return (*this); + } + + template + unsigned int GetSerializeSize(const T& obj) + { + // Tells the size of the object if serialized to this stream + return ::GetSerializeSize(obj, nType, nVersion); + } + + template + CAutoFile& operator<<(const T& obj) + { + // Serialize to this stream + if (!file) + throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } + + template + CAutoFile& operator>>(T& obj) + { + // Unserialize from this stream + if (!file) + throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } +}; diff --git a/sha.cpp b/sha.cpp new file mode 100644 index 000000000..09b62fdc8 --- /dev/null +++ b/sha.cpp @@ -0,0 +1,554 @@ +// This file is public domain +// SHA routines extracted as a standalone file from: +// Crypto++: a C++ Class Library of Cryptographic Schemes +// Version 5.5.2 (9/24/2007) +// http://www.cryptopp.com + +// sha.cpp - modified by Wei Dai from Steve Reid's public domain sha1.c + +// Steve Reid implemented SHA-1. Wei Dai implemented SHA-2. +// Both are in the public domain. + +#include +#include +#include "sha.h" + +namespace CryptoPP +{ + +// start of Steve Reid's code + +#define blk0(i) (W[i] = data[i]) +#define blk1(i) (W[i&15] = rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1)) + +void SHA1::InitState(HashWordType *state) +{ + state[0] = 0x67452301L; + state[1] = 0xEFCDAB89L; + state[2] = 0x98BADCFEL; + state[3] = 0x10325476L; + state[4] = 0xC3D2E1F0L; +} + +#define f1(x,y,z) (z^(x&(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30); +#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30); +#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rotlFixed(v,5);w=rotlFixed(w,30); +#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rotlFixed(v,5);w=rotlFixed(w,30); +#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rotlFixed(v,5);w=rotlFixed(w,30); + +void SHA1::Transform(word32 *state, const word32 *data) +{ + word32 W[16]; + /* Copy context->state[] to working vars */ + word32 a = state[0]; + word32 b = state[1]; + word32 c = state[2]; + word32 d = state[3]; + word32 e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +// end of Steve Reid's code + +// ************************************************************* + +void SHA224::InitState(HashWordType *state) +{ + static const word32 s[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + memcpy(state, s, sizeof(s)); +} + +void SHA256::InitState(HashWordType *state) +{ + static const word32 s[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + memcpy(state, s, sizeof(s)); +} + +static const word32 SHA256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + +#define a(i) T[(0-i)&7] +#define b(i) T[(1-i)&7] +#define c(i) T[(2-i)&7] +#define d(i) T[(3-i)&7] +#define e(i) T[(4-i)&7] +#define f(i) T[(5-i)&7] +#define g(i) T[(6-i)&7] +#define h(i) T[(7-i)&7] + +#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+SHA256_K[i+j]+(j?blk2(i):blk0(i));\ + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + +// for SHA256 +#define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22)) +#define S1(x) (rotrFixed(x,6)^rotrFixed(x,11)^rotrFixed(x,25)) +#define s0(x) (rotrFixed(x,7)^rotrFixed(x,18)^(x>>3)) +#define s1(x) (rotrFixed(x,17)^rotrFixed(x,19)^(x>>10)) + +void SHA256::Transform(word32 *state, const word32 *data) +{ + word32 W[16]; + word32 T[8]; + /* Copy context->state[] to working vars */ + memcpy(T, state, sizeof(T)); + /* 64 operations, partially loop unrolled */ + for (unsigned int j=0; j<64; j+=16) + { + R( 0); R( 1); R( 2); R( 3); + R( 4); R( 5); R( 6); R( 7); + R( 8); R( 9); R(10); R(11); + R(12); R(13); R(14); R(15); + } + /* Add the working vars back into context.state[] */ + state[0] += a(0); + state[1] += b(0); + state[2] += c(0); + state[3] += d(0); + state[4] += e(0); + state[5] += f(0); + state[6] += g(0); + state[7] += h(0); +} + +/* +// smaller but slower +void SHA256_Transform(word32 *state, const word32 *data) +{ + word32 T[20]; + word32 W[32]; + unsigned int i = 0, j = 0; + word32 *t = T+8; + + memcpy(t, state, 8*4); + word32 e = t[4], a = t[0]; + + do + { + word32 w = data[j]; + W[j] = w; + w += K[j]; + w += t[7]; + w += S1(e); + w += Ch(e, t[5], t[6]); + e = t[3] + w; + t[3] = t[3+8] = e; + w += S0(t[0]); + a = w + Maj(a, t[1], t[2]); + t[-1] = t[7] = a; + --t; + ++j; + if (j%8 == 0) + t += 8; + } while (j<16); + + do + { + i = j&0xf; + word32 w = s1(W[i+16-2]) + s0(W[i+16-15]) + W[i] + W[i+16-7]; + W[i+16] = W[i] = w; + w += K[j]; + w += t[7]; + w += S1(e); + w += Ch(e, t[5], t[6]); + e = t[3] + w; + t[3] = t[3+8] = e; + w += S0(t[0]); + a = w + Maj(a, t[1], t[2]); + t[-1] = t[7] = a; + + w = s1(W[(i+1)+16-2]) + s0(W[(i+1)+16-15]) + W[(i+1)] + W[(i+1)+16-7]; + W[(i+1)+16] = W[(i+1)] = w; + w += K[j+1]; + w += (t-1)[7]; + w += S1(e); + w += Ch(e, (t-1)[5], (t-1)[6]); + e = (t-1)[3] + w; + (t-1)[3] = (t-1)[3+8] = e; + w += S0((t-1)[0]); + a = w + Maj(a, (t-1)[1], (t-1)[2]); + (t-1)[-1] = (t-1)[7] = a; + + t-=2; + j+=2; + if (j%8 == 0) + t += 8; + } while (j<64); + + state[0] += a; + state[1] += t[1]; + state[2] += t[2]; + state[3] += t[3]; + state[4] += e; + state[5] += t[5]; + state[6] += t[6]; + state[7] += t[7]; +} +*/ + +#undef S0 +#undef S1 +#undef s0 +#undef s1 +#undef R + +// ************************************************************* + +#ifdef WORD64_AVAILABLE + +void SHA384::InitState(HashWordType *state) +{ + static const word64 s[8] = { + W64LIT(0xcbbb9d5dc1059ed8), W64LIT(0x629a292a367cd507), + W64LIT(0x9159015a3070dd17), W64LIT(0x152fecd8f70e5939), + W64LIT(0x67332667ffc00b31), W64LIT(0x8eb44a8768581511), + W64LIT(0xdb0c2e0d64f98fa7), W64LIT(0x47b5481dbefa4fa4)}; + memcpy(state, s, sizeof(s)); +} + +void SHA512::InitState(HashWordType *state) +{ + static const word64 s[8] = { + W64LIT(0x6a09e667f3bcc908), W64LIT(0xbb67ae8584caa73b), + W64LIT(0x3c6ef372fe94f82b), W64LIT(0xa54ff53a5f1d36f1), + W64LIT(0x510e527fade682d1), W64LIT(0x9b05688c2b3e6c1f), + W64LIT(0x1f83d9abfb41bd6b), W64LIT(0x5be0cd19137e2179)}; + memcpy(state, s, sizeof(s)); +} + +CRYPTOPP_ALIGN_DATA(16) static const word64 SHA512_K[80] CRYPTOPP_SECTION_ALIGN16 = { + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), + W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), + W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), + W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), + W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), + W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), + W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), + W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), + W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), + W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), + W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), + W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), + W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), + W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), + W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), + W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), + W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), + W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), + W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), + W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), + W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) +}; + +#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86 +// put assembly version in separate function, otherwise MSVC 2005 SP1 doesn't generate correct code for the non-assembly version +CRYPTOPP_NAKED static void CRYPTOPP_FASTCALL SHA512_SSE2_Transform(word64 *state, const word64 *data) +{ +#ifdef __GNUC__ + __asm__ __volatile__ + ( + ".intel_syntax noprefix;" + AS1( push ebx) + AS2( mov ebx, eax) +#else + AS1( push ebx) + AS1( push esi) + AS1( push edi) + AS2( lea ebx, SHA512_K) +#endif + + AS2( mov eax, esp) + AS2( and esp, 0xfffffff0) + AS2( sub esp, 27*16) // 17*16 for expanded data, 20*8 for state + AS1( push eax) + AS2( xor eax, eax) + AS2( lea edi, [esp+4+8*8]) // start at middle of state buffer. will decrement pointer each round to avoid copying + AS2( lea esi, [esp+4+20*8+8]) // 16-byte alignment, then add 8 + + AS2( movq mm4, [ecx+0*8]) + AS2( movq [edi+0*8], mm4) + AS2( movq mm0, [ecx+1*8]) + AS2( movq [edi+1*8], mm0) + AS2( movq mm0, [ecx+2*8]) + AS2( movq [edi+2*8], mm0) + AS2( movq mm0, [ecx+3*8]) + AS2( movq [edi+3*8], mm0) + AS2( movq mm5, [ecx+4*8]) + AS2( movq [edi+4*8], mm5) + AS2( movq mm0, [ecx+5*8]) + AS2( movq [edi+5*8], mm0) + AS2( movq mm0, [ecx+6*8]) + AS2( movq [edi+6*8], mm0) + AS2( movq mm0, [ecx+7*8]) + AS2( movq [edi+7*8], mm0) + ASJ( jmp, 0, f) + +#define SSE2_S0_S1(r, a, b, c) \ + AS2( movq mm6, r)\ + AS2( psrlq r, a)\ + AS2( movq mm7, r)\ + AS2( psllq mm6, 64-c)\ + AS2( pxor mm7, mm6)\ + AS2( psrlq r, b-a)\ + AS2( pxor mm7, r)\ + AS2( psllq mm6, c-b)\ + AS2( pxor mm7, mm6)\ + AS2( psrlq r, c-b)\ + AS2( pxor r, mm7)\ + AS2( psllq mm6, b-a)\ + AS2( pxor r, mm6) + +#define SSE2_s0(r, a, b, c) \ + AS2( movdqa xmm6, r)\ + AS2( psrlq r, a)\ + AS2( movdqa xmm7, r)\ + AS2( psllq xmm6, 64-c)\ + AS2( pxor xmm7, xmm6)\ + AS2( psrlq r, b-a)\ + AS2( pxor xmm7, r)\ + AS2( psrlq r, c-b)\ + AS2( pxor r, xmm7)\ + AS2( psllq xmm6, c-a)\ + AS2( pxor r, xmm6) + +#define SSE2_s1(r, a, b, c) \ + AS2( movdqa xmm6, r)\ + AS2( psrlq r, a)\ + AS2( movdqa xmm7, r)\ + AS2( psllq xmm6, 64-c)\ + AS2( pxor xmm7, xmm6)\ + AS2( psrlq r, b-a)\ + AS2( pxor xmm7, r)\ + AS2( psllq xmm6, c-b)\ + AS2( pxor xmm7, xmm6)\ + AS2( psrlq r, c-b)\ + AS2( pxor r, xmm7) + + ASL(SHA512_Round) + // k + w is in mm0, a is in mm4, e is in mm5 + AS2( paddq mm0, [edi+7*8]) // h + AS2( movq mm2, [edi+5*8]) // f + AS2( movq mm3, [edi+6*8]) // g + AS2( pxor mm2, mm3) + AS2( pand mm2, mm5) + SSE2_S0_S1(mm5,14,18,41) + AS2( pxor mm2, mm3) + AS2( paddq mm0, mm2) // h += Ch(e,f,g) + AS2( paddq mm5, mm0) // h += S1(e) + AS2( movq mm2, [edi+1*8]) // b + AS2( movq mm1, mm2) + AS2( por mm2, mm4) + AS2( pand mm2, [edi+2*8]) // c + AS2( pand mm1, mm4) + AS2( por mm1, mm2) + AS2( paddq mm1, mm5) // temp = h + Maj(a,b,c) + AS2( paddq mm5, [edi+3*8]) // e = d + h + AS2( movq [edi+3*8], mm5) + AS2( movq [edi+11*8], mm5) + SSE2_S0_S1(mm4,28,34,39) // S0(a) + AS2( paddq mm4, mm1) // a = temp + S0(a) + AS2( movq [edi-8], mm4) + AS2( movq [edi+7*8], mm4) + AS1( ret) + + // first 16 rounds + ASL(0) + AS2( movq mm0, [edx+eax*8]) + AS2( movq [esi+eax*8], mm0) + AS2( movq [esi+eax*8+16*8], mm0) + AS2( paddq mm0, [ebx+eax*8]) + ASC( call, SHA512_Round) + AS1( inc eax) + AS2( sub edi, 8) + AS2( test eax, 7) + ASJ( jnz, 0, b) + AS2( add edi, 8*8) + AS2( cmp eax, 16) + ASJ( jne, 0, b) + + // rest of the rounds + AS2( movdqu xmm0, [esi+(16-2)*8]) + ASL(1) + // data expansion, W[i-2] already in xmm0 + AS2( movdqu xmm3, [esi]) + AS2( paddq xmm3, [esi+(16-7)*8]) + AS2( movdqa xmm2, [esi+(16-15)*8]) + SSE2_s1(xmm0, 6, 19, 61) + AS2( paddq xmm0, xmm3) + SSE2_s0(xmm2, 1, 7, 8) + AS2( paddq xmm0, xmm2) + AS2( movdq2q mm0, xmm0) + AS2( movhlps xmm1, xmm0) + AS2( paddq mm0, [ebx+eax*8]) + AS2( movlps [esi], xmm0) + AS2( movlps [esi+8], xmm1) + AS2( movlps [esi+8*16], xmm0) + AS2( movlps [esi+8*17], xmm1) + // 2 rounds + ASC( call, SHA512_Round) + AS2( sub edi, 8) + AS2( movdq2q mm0, xmm1) + AS2( paddq mm0, [ebx+eax*8+8]) + ASC( call, SHA512_Round) + // update indices and loop + AS2( add esi, 16) + AS2( add eax, 2) + AS2( sub edi, 8) + AS2( test eax, 7) + ASJ( jnz, 1, b) + // do housekeeping every 8 rounds + AS2( mov esi, 0xf) + AS2( and esi, eax) + AS2( lea esi, [esp+4+20*8+8+esi*8]) + AS2( add edi, 8*8) + AS2( cmp eax, 80) + ASJ( jne, 1, b) + +#define SSE2_CombineState(i) \ + AS2( movq mm0, [edi+i*8])\ + AS2( paddq mm0, [ecx+i*8])\ + AS2( movq [ecx+i*8], mm0) + + SSE2_CombineState(0) + SSE2_CombineState(1) + SSE2_CombineState(2) + SSE2_CombineState(3) + SSE2_CombineState(4) + SSE2_CombineState(5) + SSE2_CombineState(6) + SSE2_CombineState(7) + + AS1( pop esp) + AS1( emms) + +#if defined(__GNUC__) + AS1( pop ebx) + ".att_syntax prefix;" + : + : "a" (SHA512_K), "c" (state), "d" (data) + : "%esi", "%edi", "memory", "cc" + ); +#else + AS1( pop edi) + AS1( pop esi) + AS1( pop ebx) + AS1( ret) +#endif +} +#endif // #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE + +void SHA512::Transform(word64 *state, const word64 *data) +{ +#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86 + if (HasSSE2()) + { + SHA512_SSE2_Transform(state, data); + return; + } +#endif + +#define S0(x) (rotrFixed(x,28)^rotrFixed(x,34)^rotrFixed(x,39)) +#define S1(x) (rotrFixed(x,14)^rotrFixed(x,18)^rotrFixed(x,41)) +#define s0(x) (rotrFixed(x,1)^rotrFixed(x,8)^(x>>7)) +#define s1(x) (rotrFixed(x,19)^rotrFixed(x,61)^(x>>6)) + +#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+SHA512_K[i+j]+(j?blk2(i):blk0(i));\ + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + + word64 W[16]; + word64 T[8]; + /* Copy context->state[] to working vars */ + memcpy(T, state, sizeof(T)); + /* 80 operations, partially loop unrolled */ + for (unsigned int j=0; j<80; j+=16) + { + R( 0); R( 1); R( 2); R( 3); + R( 4); R( 5); R( 6); R( 7); + R( 8); R( 9); R(10); R(11); + R(12); R(13); R(14); R(15); + } + /* Add the working vars back into context.state[] */ + state[0] += a(0); + state[1] += b(0); + state[2] += c(0); + state[3] += d(0); + state[4] += e(0); + state[5] += f(0); + state[6] += g(0); + state[7] += h(0); +} + +#endif + +} diff --git a/sha.h b/sha.h new file mode 100644 index 000000000..4e56b56d9 --- /dev/null +++ b/sha.h @@ -0,0 +1,177 @@ +// This file is public domain +// SHA routines extracted as a standalone file from: +// Crypto++: a C++ Class Library of Cryptographic Schemes +// Version 5.5.2 (9/24/2007) +// http://www.cryptopp.com +#ifndef CRYPTOPP_SHA_H +#define CRYPTOPP_SHA_H +#include + +namespace CryptoPP +{ + +// +// Dependencies +// + +typedef unsigned char byte; +typedef unsigned short word16; +typedef unsigned int word32; +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 word64; +#else +typedef unsigned long long word64; +#endif + +template inline T rotlFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return T((x<>(sizeof(T)*8-y))); +} + +template inline T rotrFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return T((x>>y) | (x<<(sizeof(T)*8-y))); +} + +// ************** endian reversal *************** + +#ifdef _MSC_VER + #if _MSC_VER >= 1400 + #define CRYPTOPP_FAST_ROTATE(x) 1 + #elif _MSC_VER >= 1300 + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32 | (x) == 64) + #else + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) + #endif +#elif (defined(__MWERKS__) && TARGET_CPU_PPC) || \ + (defined(__GNUC__) && (defined(_ARCH_PWR2) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_ARCH_COM))) + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) +#elif defined(__GNUC__) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86) // depend on GCC's peephole optimization to generate rotate instructions + #define CRYPTOPP_FAST_ROTATE(x) 1 +#else + #define CRYPTOPP_FAST_ROTATE(x) 0 +#endif + +inline byte ByteReverse(byte value) +{ + return value; +} + +inline word16 ByteReverse(word16 value) +{ +#ifdef CRYPTOPP_BYTESWAP_AVAILABLE + return bswap_16(value); +#elif defined(_MSC_VER) && _MSC_VER >= 1300 + return _byteswap_ushort(value); +#else + return rotlFixed(value, 8U); +#endif +} + +inline word32 ByteReverse(word32 value) +{ +#if defined(__GNUC__) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_32(value); +#elif defined(__MWERKS__) && TARGET_CPU_PPC + return (word32)__lwbrx(&value,0); +#elif _MSC_VER >= 1400 || (_MSC_VER >= 1300 && !defined(_DLL)) + return _byteswap_ulong(value); +#elif CRYPTOPP_FAST_ROTATE(32) + // 5 instructions with rotate instruction, 9 without + return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); +#else + // 6 instructions with rotate instruction, 8 without + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return rotlFixed(value, 16U); +#endif +} + +#ifdef WORD64_AVAILABLE +inline word64 ByteReverse(word64 value) +{ +#if defined(__GNUC__) && defined(__x86_64__) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_64(value); +#elif defined(_MSC_VER) && _MSC_VER >= 1300 + return _byteswap_uint64(value); +#elif defined(CRYPTOPP_SLOW_WORD64) + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); +#else + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); + return rotlFixed(value, 32U); +#endif +} +#endif + + +// +// SHA +// + +// http://www.weidai.com/scan-mirror/md.html#SHA-1 +class SHA1 +{ +public: + typedef word32 HashWordType; + static void InitState(word32 *state); + static void Transform(word32 *digest, const word32 *data); + static const char * StaticAlgorithmName() {return "SHA-1";} +}; + +typedef SHA1 SHA; // for backwards compatibility + +// implements the SHA-256 standard +class SHA256 +{ +public: + typedef word32 HashWordType; + static void InitState(word32 *state); + static void Transform(word32 *digest, const word32 *data); + static const char * StaticAlgorithmName() {return "SHA-256";} +}; + +// implements the SHA-224 standard +class SHA224 +{ +public: + typedef word32 HashWordType; + static void InitState(word32 *state); + static void Transform(word32 *digest, const word32 *data) {SHA256::Transform(digest, data);} + static const char * StaticAlgorithmName() {return "SHA-224";} +}; + +#ifdef WORD64_AVAILABLE + +// implements the SHA-512 standard +class SHA512 +{ +public: + typedef word64 HashWordType; + static void InitState(word64 *state); + static void Transform(word64 *digest, const word64 *data); + static const char * StaticAlgorithmName() {return "SHA-512";} +}; + +// implements the SHA-384 standard +class SHA384 +{ +public: + typedef word64 HashWordType; + static void InitState(word64 *state); + static void Transform(word64 *digest, const word64 *data) {SHA512::Transform(digest, data);} + static const char * StaticAlgorithmName() {return "SHA-384";} +}; + +#endif + +} + +#endif diff --git a/ui.cpp b/ui.cpp new file mode 100644 index 000000000..96c5a83d5 --- /dev/null +++ b/ui.cpp @@ -0,0 +1,3290 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" +#ifdef _MSC_VER +#include +#endif + + + +DEFINE_EVENT_TYPE(wxEVT_CROSSTHREADCALL) +DEFINE_EVENT_TYPE(wxEVT_REPLY1) +DEFINE_EVENT_TYPE(wxEVT_REPLY2) +DEFINE_EVENT_TYPE(wxEVT_REPLY3) +DEFINE_EVENT_TYPE(wxEVT_TABLEADDED) +DEFINE_EVENT_TYPE(wxEVT_TABLEUPDATED) +DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED) + +CMainFrame* pframeMain = NULL; +map mapAddressBook; + + +void ThreadRequestProductDetails(void* parg); +void ThreadRandSendTest(void* parg); +bool fRandSendTest = false; +void RandSend(); +extern int g_isPainting; + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Util +// + +void HandleCtrlA(wxKeyEvent& event) +{ + // Ctrl-a select all + wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject(); + if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A') + textCtrl->SetSelection(-1, -1); + event.Skip(); +} + +bool Is24HourTime() +{ + //char pszHourFormat[256]; + //pszHourFormat[0] = '\0'; + //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256); + //return (pszHourFormat[0] != '0'); + return true; +} + +string DateStr(int64 nTime) +{ + return (string)wxDateTime((time_t)nTime).FormatDate(); +} + +string DateTimeStr(int64 nTime) +{ + wxDateTime datetime((time_t)nTime); + if (Is24HourTime()) + return (string)datetime.Format("%x %H:%M"); + else + return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p"); +} + +wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn) +{ + // Helper to simplify access to listctrl + wxListItem item; + item.m_itemId = nIndex; + item.m_col = nColumn; + item.m_mask = wxLIST_MASK_TEXT; + if (!listCtrl->GetItem(item)) + return ""; + return item.GetText(); +} + +int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1) +{ + int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0); + listCtrl->SetItem(nIndex, 1, str1); + return nIndex; +} + +int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4) +{ + int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0); + listCtrl->SetItem(nIndex, 1, str1); + listCtrl->SetItem(nIndex, 2, str2); + listCtrl->SetItem(nIndex, 3, str3); + listCtrl->SetItem(nIndex, 4, str4); + return nIndex; +} + +int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4) +{ + int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0); + listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata); + listCtrl->SetItem(nIndex, 1, str1); + listCtrl->SetItem(nIndex, 2, str2); + listCtrl->SetItem(nIndex, 3, str3); + listCtrl->SetItem(nIndex, 4, str4); + return nIndex; +} + +void SetSelection(wxListCtrl* listCtrl, int nIndex) +{ + int nSize = listCtrl->GetItemCount(); + long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); + for (int i = 0; i < nSize; i++) + listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState); +} + +int GetSelection(wxListCtrl* listCtrl) +{ + int nSize = listCtrl->GetItemCount(); + for (int i = 0; i < nSize; i++) + if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED)) + return i; + return -1; +} + + +string HtmlEscape(const char* psz, bool fMultiLine=false) +{ + int len = 0; + for (const char* p = psz; *p; p++) + { + if (*p == '<') len += 4; + else if (*p == '>') len += 4; + else if (*p == '&') len += 5; + else if (*p == '"') len += 6; + else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6; + else if (*p == '\n' && fMultiLine) len += 5; + else + len++; + } + string str; + str.reserve(len); + for (const char* p = psz; *p; p++) + { + if (*p == '<') str += "<"; + else if (*p == '>') str += ">"; + else if (*p == '&') str += "&"; + else if (*p == '"') str += """; + else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " "; + else if (*p == '\n' && fMultiLine) str += "
\n"; + else + str += *p; + } + return str; +} + +string HtmlEscape(const string& str, bool fMultiLine=false) +{ + return HtmlEscape(str.c_str(), fMultiLine); +} + +void AddToMyProducts(CProduct product) +{ + CProduct& productInsert = mapMyProducts[product.GetHash()]; + productInsert = product; + InsertLine(pframeMain->m_listCtrlProductsSent, &productInsert, + product.mapValue["category"], + product.mapValue["title"].substr(0, 100), + product.mapValue["description"].substr(0, 100), + product.mapValue["price"], + ""); +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Custom events +// + +set setCallbackAvailable; +CCriticalSection cs_setCallbackAvailable; + +void AddCallbackAvailable(void* p) +{ + CRITICAL_BLOCK(cs_setCallbackAvailable) + setCallbackAvailable.insert(p); +} + +void RemoveCallbackAvailable(void* p) +{ + CRITICAL_BLOCK(cs_setCallbackAvailable) + setCallbackAvailable.erase(p); +} + +bool IsCallbackAvailable(void* p) +{ + CRITICAL_BLOCK(cs_setCallbackAvailable) + return setCallbackAvailable.count(p); + return false; +} + +template +void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T pbeginIn, const T pendIn) +{ + if (!pevthandler) + return; + + const char* pbegin = (pendIn != pbeginIn) ? &pbeginIn[0] : NULL; + const char* pend = pbegin + (pendIn - pbeginIn) * sizeof(pbeginIn[0]); + wxCommandEvent event(nEventID); + wxString strData(wxChar(0), (pend - pbegin) / sizeof(wxChar) + 1); + memcpy(&strData[0], pbegin, pend - pbegin); + event.SetString(strData); + event.SetInt(pend - pbegin); + + pevthandler->AddPendingEvent(event); +} + +template +void AddPendingCustomEvent(wxEvtHandler* pevthandler, int nEventID, const T& obj) +{ + CDataStream ss; + ss << obj; + AddPendingCustomEvent(pevthandler, nEventID, ss.begin(), ss.end()); +} + +void AddPendingReplyEvent1(void* pevthandler, CDataStream& vRecv) +{ + if (IsCallbackAvailable(pevthandler)) + AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY1, vRecv.begin(), vRecv.end()); +} + +void AddPendingReplyEvent2(void* pevthandler, CDataStream& vRecv) +{ + if (IsCallbackAvailable(pevthandler)) + AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY2, vRecv.begin(), vRecv.end()); +} + +void AddPendingReplyEvent3(void* pevthandler, CDataStream& vRecv) +{ + if (IsCallbackAvailable(pevthandler)) + AddPendingCustomEvent((wxEvtHandler*)pevthandler, wxEVT_REPLY3, vRecv.begin(), vRecv.end()); +} + +CDataStream GetStreamFromEvent(const wxCommandEvent& event) +{ + wxString strData = event.GetString(); + return CDataStream(strData.begin(), strData.begin() + event.GetInt(), SER_NETWORK); +} + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CMainFrame +// + +CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent) +{ + Connect(wxEVT_CROSSTHREADCALL, wxCommandEventHandler(CMainFrame::OnCrossThreadCall), NULL, this); + + // Init + fRefreshListCtrl = false; + fRefreshListCtrlRunning = false; + fOnSetFocusAddress = false; + pindexBestLast = NULL; + m_choiceFilter->SetSelection(0); + m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); + m_listCtrl->SetFocus(); + SetIcon(wxICON(bitcoin)); + m_menuOptions->Check(wxID_OPTIONSGENERATEBITCOINS, fGenerateBitcoins); + + // Init toolbar with transparency masked bitmaps + m_toolBar->ClearTools(); + + //// shouldn't have to do mask separately anymore, bitmap alpha support added in wx 2.8.9, + wxBitmap bmpSend(wxT("send20"), wxBITMAP_TYPE_RESOURCE); + bmpSend.SetMask(new wxMask(wxBitmap(wxT("send20mask"), wxBITMAP_TYPE_RESOURCE))); + m_toolBar->AddTool(wxID_BUTTONSEND, wxT("&Send Coins"), bmpSend, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString); + + wxBitmap bmpAddressBook(wxT("addressbook20"), wxBITMAP_TYPE_RESOURCE); + bmpAddressBook.SetMask(new wxMask(wxBitmap(wxT("addressbook20mask"), wxBITMAP_TYPE_RESOURCE))); + m_toolBar->AddTool(wxID_BUTTONRECEIVE, wxT("&Address Book"), bmpAddressBook, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString); + + m_toolBar->Realize(); + + // Init column headers + int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8; + m_listCtrl->InsertColumn(0, "", wxLIST_FORMAT_LEFT, 0); + m_listCtrl->InsertColumn(1, "", wxLIST_FORMAT_LEFT, 0); + m_listCtrl->InsertColumn(2, "Status", wxLIST_FORMAT_LEFT, 90); + m_listCtrl->InsertColumn(3, "Date", wxLIST_FORMAT_LEFT, nDateWidth); + m_listCtrl->InsertColumn(4, "Description", wxLIST_FORMAT_LEFT, 409 - nDateWidth); + m_listCtrl->InsertColumn(5, "Debit", wxLIST_FORMAT_RIGHT, 79); + m_listCtrl->InsertColumn(6, "Credit", wxLIST_FORMAT_RIGHT, 79); + + //m_listCtrlProductsSent->InsertColumn(0, "Category", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlProductsSent->InsertColumn(1, "Title", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlProductsSent->InsertColumn(2, "Description", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlProductsSent->InsertColumn(3, "Price", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlProductsSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100); + + //m_listCtrlOrdersSent->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersSent->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersSent->InsertColumn(2, "", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersSent->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersSent->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100); + + //m_listCtrlOrdersReceived->InsertColumn(0, "Time", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersReceived->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersReceived->InsertColumn(2, "Payment Status", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersReceived->InsertColumn(3, "", wxLIST_FORMAT_LEFT, 100); + //m_listCtrlOrdersReceived->InsertColumn(4, "", wxLIST_FORMAT_LEFT, 100); + + // Init status bar + int pnWidths[3] = { -100, 81, 286 }; + m_statusBar->SetFieldsCount(3, pnWidths); + + // Fill your address text box + vector vchPubKey; + if (CWalletDB("r").ReadDefaultKey(vchPubKey)) + m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey)); + + // Fill listctrl with wallet transactions + RefreshListCtrl(); +} + +CMainFrame::~CMainFrame() +{ + pframeMain = NULL; +} + +void Shutdown(void* parg) +{ + static CCriticalSection cs_Shutdown; + CRITICAL_BLOCK(cs_Shutdown) + { + fShutdown = true; + nTransactionsUpdated++; + DBFlush(false); + StopNode(); + DBFlush(true); + + printf("Bitcoin exiting\n"); + exit(0); + } +} + +void CMainFrame::OnClose(wxCloseEvent& event) +{ + Destroy(); + _beginthread(Shutdown, 0, NULL); +} + +void CMainFrame::OnMouseEvents(wxMouseEvent& event) +{ + RandAddSeed(); + RAND_add(&event.m_x, sizeof(event.m_x), 0.25); + RAND_add(&event.m_y, sizeof(event.m_y), 0.25); +} + +void CMainFrame::OnListColBeginDrag(wxListEvent& event) +{ + // Hidden columns not resizeable + if (event.GetColumn() <= 1 && !fDebug) + event.Veto(); +} + +void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5, const wxString& str6) +{ + string str0 = strSort; + long nData = *(long*)&hashKey; + + if (fNew) + { + nIndex = m_listCtrl->InsertItem(0, str0); + } + else + { + if (nIndex == -1) + { + // Find item + while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1) + if (GetItemText(m_listCtrl, nIndex, 1) == hashKey.ToString()) + break; + if (nIndex == -1) + { + printf("CMainFrame::InsertLine : Couldn't find item to be updated\n"); + return; + } + } + + // If sort key changed, must delete and reinsert to make it relocate + if (GetItemText(m_listCtrl, nIndex, 0) != str0) + { + m_listCtrl->DeleteItem(nIndex); + nIndex = m_listCtrl->InsertItem(0, str0); + } + } + + m_listCtrl->SetItem(nIndex, 1, hashKey.ToString()); + m_listCtrl->SetItem(nIndex, 2, str2); + m_listCtrl->SetItem(nIndex, 3, str3); + m_listCtrl->SetItem(nIndex, 4, str4); + m_listCtrl->SetItem(nIndex, 5, str5); + m_listCtrl->SetItem(nIndex, 6, str6); + m_listCtrl->SetItemData(nIndex, nData); +} + +string FormatTxStatus(const CWalletTx& wtx) +{ + // Status + int nDepth = wtx.GetDepthInMainChain(); + if (!wtx.IsFinal()) + return strprintf("Open for %d blocks", nBestHeight - wtx.nLockTime); + else if (nDepth < 6) + return strprintf("%d/unconfirmed", nDepth); + else + return strprintf("%d blocks", nDepth); +} + +string SingleLine(const string& strIn) +{ + string strOut; + bool fOneSpace = false; + foreach(int c, strIn) + { + if (isspace(c)) + { + fOneSpace = true; + } + else if (c > ' ') + { + if (fOneSpace && !strOut.empty()) + strOut += ' '; + strOut += c; + fOneSpace = false; + } + } + return strOut; +} + +void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) +{ + int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime(); + int64 nCredit = wtx.GetCredit(); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + uint256 hash = wtx.GetHash(); + string strStatus = FormatTxStatus(wtx); + map mapValue = wtx.mapValue; + + // Find the block the tx is in + CBlockIndex* pindex = NULL; + map::iterator mi = mapBlockIndex.find(wtx.hashBlock); + if (mi != mapBlockIndex.end()) + pindex = (*mi).second; + + // Sort order, unrecorded transactions sort to the top + string strSort = strprintf("%010d-%01d-%010u", + (pindex ? pindex->nHeight : INT_MAX), + (wtx.IsCoinBase() ? 1 : 0), + wtx.nTimeReceived); + + // Insert line + if (nNet > 0 || wtx.IsCoinBase()) + { + // + // Credit + // + string strDescription; + + if (wtx.IsCoinBase()) + { + // Coinbase + strDescription = "Generated"; + if (nCredit == 0) + { + int64 nUnmatured = 0; + foreach(const CTxOut& txout, wtx.vout) + nUnmatured += txout.GetCredit(); + if (wtx.IsInMainChain()) + strDescription += strprintf(" (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); + else + strDescription += " (not accepted)"; + } + } + else if (!mapValue["from"].empty() || !mapValue["message"].empty()) + { + // Online transaction + if (!mapValue["from"].empty()) + strDescription += "From: " + mapValue["from"]; + if (!mapValue["message"].empty()) + { + if (!strDescription.empty()) + strDescription += " - "; + strDescription += mapValue["message"]; + } + } + else + { + // Offline transaction + foreach(const CTxOut& txout, wtx.vout) + { + if (txout.IsMine()) + { + vector vchPubKey; + if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) + { + string strAddress = PubKeyToAddress(vchPubKey); + if (mapAddressBook.count(strAddress)) + { + //strDescription += "Received payment to "; + //strDescription += "Received with address "; + strDescription += "From: unknown, To: "; + strDescription += strAddress; + /// The labeling feature is just too confusing, so I hid it + /// by putting it at the end where it runs off the screen. + /// It can still be seen by widening the column, or in the + /// details dialog. + if (!mapAddressBook[strAddress].empty()) + strDescription += " (" + mapAddressBook[strAddress] + ")"; + } + } + break; + } + } + } + + InsertLine(fNew, nIndex, hash, strSort, + strStatus, + nTime ? DateTimeStr(nTime) : "", + SingleLine(strDescription), + "", + FormatMoney(nNet, true)); + } + else + { + bool fAllFromMe = true; + foreach(const CTxIn& txin, wtx.vin) + fAllFromMe = fAllFromMe && txin.IsMine(); + + bool fAllToMe = true; + foreach(const CTxOut& txout, wtx.vout) + fAllToMe = fAllToMe && txout.IsMine(); + + if (fAllFromMe && fAllToMe) + { + // Payment to self + int64 nValue = wtx.vout[0].nValue; + InsertLine(fNew, nIndex, hash, strSort, + strStatus, + nTime ? DateTimeStr(nTime) : "", + "Payment to yourself", + FormatMoney(nNet - nValue, true), + FormatMoney(nValue, true)); + } + else if (fAllFromMe) + { + // + // Debit + // + int64 nTxFee = nDebit - wtx.GetValueOut(); + for (int nOut = 0; nOut < wtx.vout.size(); nOut++) + { + const CTxOut& txout = wtx.vout[nOut]; + if (txout.IsMine()) + continue; + + string strAddress; + if (!mapValue["to"].empty()) + { + // Online transaction + strAddress = mapValue["to"]; + } + else + { + // Offline transaction + uint160 hash160; + if (ExtractHash160(txout.scriptPubKey, hash160)) + strAddress = Hash160ToAddress(hash160); + } + + string strDescription = "To: "; + if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) + strDescription += mapAddressBook[strAddress] + " "; + strDescription += strAddress; + if (!mapValue["message"].empty()) + { + if (!strDescription.empty()) + strDescription += " - "; + strDescription += mapValue["message"]; + } + + int64 nValue = txout.nValue; + if (nOut == 0 && nTxFee > 0) + nValue += nTxFee; + + InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), + strStatus, + nTime ? DateTimeStr(nTime) : "", + SingleLine(strDescription), + FormatMoney(-nValue, true), + ""); + } + } + else + { + // + // Mixed debit transaction, can't break down payees + // + bool fAllMine = true; + foreach(const CTxOut& txout, wtx.vout) + fAllMine = fAllMine && txout.IsMine(); + foreach(const CTxIn& txin, wtx.vin) + fAllMine = fAllMine && txin.IsMine(); + + InsertLine(fNew, nIndex, hash, strSort, + strStatus, + nTime ? DateTimeStr(nTime) : "", + "", + FormatMoney(nNet, true), + ""); + } + } +} + +void CMainFrame::RefreshStatus() +{ + static int nLastTop; + int nTop = m_listCtrl->GetTopItem(); + if (nTop == nLastTop && pindexBestLast == pindexBest) + return; + + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + int nStart = nTop; + int nEnd = min(nStart + 100, m_listCtrl->GetItemCount()); + if (pindexBestLast == pindexBest) + { + if (nStart >= nLastTop && nStart < nLastTop + 100) + nStart = nLastTop + 100; + if (nEnd >= nLastTop && nEnd < nLastTop + 100) + nEnd = nLastTop; + } + nLastTop = nTop; + pindexBestLast = pindexBest; + + for (int nIndex = nStart; nIndex < nEnd; nIndex++) + { + uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); + map::iterator mi = mapWallet.find(hash); + if (mi == mapWallet.end()) + { + printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n"); + continue; + } + const CWalletTx& wtx = (*mi).second; + if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed) + InsertTransaction(wtx, false, nIndex); + else + m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx)); + } + } +} + +void CMainFrame::RefreshListCtrl() +{ + fRefreshListCtrl = true; + ::wxWakeUpIdle(); +} + +void CMainFrame::OnIdle(wxIdleEvent& event) +{ + if (fRefreshListCtrl) + { + // Collect list of wallet transactions and sort newest first + bool fEntered = false; + vector > vSorted; + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + printf("RefreshListCtrl starting\n"); + fEntered = true; + fRefreshListCtrl = false; + vWalletUpdated.clear(); + + // Do the newest transactions first + vSorted.reserve(mapWallet.size()); + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + unsigned int nTime = UINT_MAX - wtx.GetTxTime(); + vSorted.push_back(make_pair(nTime, (*it).first)); + } + m_listCtrl->DeleteAllItems(); + } + if (!fEntered) + return; + + sort(vSorted.begin(), vSorted.end()); + + // Fill list control + for (int i = 0; i < vSorted.size();) + { + if (fShutdown) + return; + bool fEntered = false; + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + fEntered = true; + uint256& hash = vSorted[i++].second; + map::iterator mi = mapWallet.find(hash); + if (mi != mapWallet.end()) + InsertTransaction((*mi).second, true); + } + if (!fEntered || i == 100 || i % 500 == 0) + wxYield(); + } + + printf("RefreshListCtrl done\n"); + } + else + { + // Check for time updates + static int64 nLastTime; + if (GetTime() > nLastTime + 30) + { + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + nLastTime = GetTime(); + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx& wtx = (*it).second; + if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime()) + InsertTransaction(wtx, false); + } + } + } + } +} + +void CMainFrame::OnPaint(wxPaintEvent& event) +{ + event.Skip(); +} + +void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) +{ + // Update listctrl contents + if (!vWalletUpdated.empty()) + { + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + pair item; + foreach(item, vWalletUpdated) + { + bool fNew = item.second; + map::iterator mi = mapWallet.find(item.first); + if (mi != mapWallet.end()) + { + printf("vWalletUpdated: %s %s\n", (*mi).second.GetHash().ToString().substr(0,6).c_str(), fNew ? "new" : ""); + InsertTransaction((*mi).second, fNew); + } + } + m_listCtrl->ScrollList(0, INT_MAX); + vWalletUpdated.clear(); + } + } + + // Update status column of visible items only + RefreshStatus(); + + // Update status bar + string strGen = ""; + if (fGenerateBitcoins) + strGen = " Generating"; + if (fGenerateBitcoins && vNodes.empty()) + strGen = "(not connected)"; + m_statusBar->SetStatusText(strGen, 1); + + string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, m_listCtrl->GetItemCount()); + m_statusBar->SetStatusText(strStatus, 2); + + // Balance total + TRY_CRITICAL_BLOCK(cs_mapWallet) + m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); + + m_listCtrl->OnPaint(event); +} + +void CrossThreadCall(wxCommandEvent& event) +{ + if (pframeMain) + pframeMain->GetEventHandler()->AddPendingEvent(event); +} + +void CrossThreadCall(int nID, void* pdata) +{ + wxCommandEvent event; + event.SetInt(nID); + event.SetClientData(pdata); + if (pframeMain) + pframeMain->GetEventHandler()->AddPendingEvent(event); +} + +void CMainFrame::OnCrossThreadCall(wxCommandEvent& event) +{ + void* pdata = event.GetClientData(); + switch (event.GetInt()) + { + case UICALL_ADDORDER: + { + break; + } + + case UICALL_UPDATEORDER: + { + break; + } + } +} + +void CMainFrame::OnMenuFileExit(wxCommandEvent& event) +{ + Close(true); +} + +void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event) +{ + fGenerateBitcoins = event.IsChecked(); + nTransactionsUpdated++; + CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins); + + if (fGenerateBitcoins) + if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1) + printf("Error: _beginthread(ThreadBitcoinMiner) failed\n"); + + Refresh(); + wxPaintEvent eventPaint; + AddPendingEvent(eventPaint); +} + +void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event) +{ + OnButtonChange(event); +} + +void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event) +{ + COptionsDialog dialog(this); + dialog.ShowModal(); +} + +void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event) +{ + CAboutDialog dialog(this); + dialog.ShowModal(); +} + +void CMainFrame::OnButtonSend(wxCommandEvent& event) +{ + /// debug test + if (fRandSendTest) + { + RandSend(); + return; + } + + // Toolbar: Send + CSendDialog dialog(this); + dialog.ShowModal(); +} + +void CMainFrame::OnButtonAddressBook(wxCommandEvent& event) +{ + // Toolbar: Address Book + CAddressBookDialog dialogAddr(this, "", false); + if (dialogAddr.ShowModal() == 2) + { + // Send + CSendDialog dialogSend(this, dialogAddr.GetAddress()); + dialogSend.ShowModal(); + } +} + +void CMainFrame::OnSetFocusAddress(wxFocusEvent& event) +{ + // Automatically select-all when entering window + m_textCtrlAddress->SetSelection(-1, -1); + fOnSetFocusAddress = true; + event.Skip(); +} + +void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event) +{ + if (fOnSetFocusAddress) + m_textCtrlAddress->SetSelection(-1, -1); + fOnSetFocusAddress = false; + event.Skip(); +} + +void CMainFrame::OnButtonCopy(wxCommandEvent& event) +{ + // Copy address box to clipboard + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue())); + wxTheClipboard->Close(); + } +} + +void CMainFrame::OnButtonChange(wxCommandEvent& event) +{ + CYourAddressDialog dialog(this, string(m_textCtrlAddress->GetValue())); + if (!dialog.ShowModal()) + return; + string strAddress = (string)dialog.GetAddress(); + if (strAddress != m_textCtrlAddress->GetValue()) + { + uint160 hash160; + if (!AddressToHash160(strAddress, hash160)) + return; + if (!mapPubKeys.count(hash160)) + return; + CWalletDB().WriteDefaultKey(mapPubKeys[hash160]); + m_textCtrlAddress->SetValue(strAddress); + } +} + +void CMainFrame::OnListItemActivatedAllTransactions(wxListEvent& event) +{ + uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1)); + CWalletTx wtx; + CRITICAL_BLOCK(cs_mapWallet) + { + map::iterator mi = mapWallet.find(hash); + if (mi == mapWallet.end()) + { + printf("CMainFrame::OnListItemActivatedAllTransactions() : tx not found in mapWallet\n"); + return; + } + wtx = (*mi).second; + } + CTxDetailsDialog dialog(this, wtx); + dialog.ShowModal(); + //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx); + //pdialog->Show(); +} + +void CMainFrame::OnListItemActivatedProductsSent(wxListEvent& event) +{ + CProduct& product = *(CProduct*)event.GetItem().GetData(); + CEditProductDialog* pdialog = new CEditProductDialog(this); + pdialog->SetProduct(product); + pdialog->Show(); +} + +void CMainFrame::OnListItemActivatedOrdersSent(wxListEvent& event) +{ + CWalletTx& order = *(CWalletTx*)event.GetItem().GetData(); + CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, false); + pdialog->Show(); +} + +void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event) +{ + CWalletTx& order = *(CWalletTx*)event.GetItem().GetData(); + CViewOrderDialog* pdialog = new CViewOrderDialog(this, order, true); + pdialog->Show(); +} + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CTxDetailsDialog +// + +CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent) +{ + string strHTML; + strHTML.reserve(4000); + strHTML += ""; + + int64 nTime = wtx.GetTxTime(); + int64 nCredit = wtx.GetCredit(); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + + + + strHTML += "Status: " + FormatTxStatus(wtx) + "
"; + strHTML += "Date: " + (nTime ? DateTimeStr(nTime) : "") + "
"; + + + // + // From + // + if (wtx.IsCoinBase()) + { + strHTML += "Source: Generated
"; + } + else if (!wtx.mapValue["from"].empty()) + { + // Online transaction + if (!wtx.mapValue["from"].empty()) + strHTML += "From: " + HtmlEscape(wtx.mapValue["from"]) + "
"; + } + else + { + // Offline transaction + if (nNet > 0) + { + // Credit + foreach(const CTxOut& txout, wtx.vout) + { + if (txout.IsMine()) + { + vector vchPubKey; + if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) + { + string strAddress = PubKeyToAddress(vchPubKey); + if (mapAddressBook.count(strAddress)) + { + strHTML += "From: unknown
"; + strHTML += "To: "; + strHTML += HtmlEscape(strAddress); + if (!mapAddressBook[strAddress].empty()) + strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")"; + else + strHTML += " (yours)"; + strHTML += "
"; + } + } + break; + } + } + } + } + + + // + // To + // + string strAddress; + if (!wtx.mapValue["to"].empty()) + { + // Online transaction + strAddress = wtx.mapValue["to"]; + strHTML += "To: "; + if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) + strHTML += mapAddressBook[strAddress] + " "; + strHTML += HtmlEscape(strAddress) + "
"; + } + + + // + // Amount + // + if (wtx.IsCoinBase() && nCredit == 0) + { + // + // Coinbase + // + int64 nUnmatured = 0; + foreach(const CTxOut& txout, wtx.vout) + nUnmatured += txout.GetCredit(); + if (wtx.IsInMainChain()) + strHTML += strprintf("Credit: (%s matures in %d more blocks)
", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); + else + strHTML += "Credit: (not accepted)
"; + } + else if (nNet > 0) + { + // + // Credit + // + strHTML += "Credit: " + FormatMoney(nNet) + "
"; + } + else + { + bool fAllFromMe = true; + foreach(const CTxIn& txin, wtx.vin) + fAllFromMe = fAllFromMe && txin.IsMine(); + + bool fAllToMe = true; + foreach(const CTxOut& txout, wtx.vout) + fAllToMe = fAllToMe && txout.IsMine(); + + if (fAllFromMe) + { + // + // Debit + // + foreach(const CTxOut& txout, wtx.vout) + { + if (txout.IsMine()) + continue; + + if (wtx.mapValue["to"].empty()) + { + // Offline transaction + uint160 hash160; + if (ExtractHash160(txout.scriptPubKey, hash160)) + { + string strAddress = Hash160ToAddress(hash160); + strHTML += "To: "; + if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) + strHTML += mapAddressBook[strAddress] + " "; + strHTML += strAddress; + strHTML += "
"; + } + } + + strHTML += "Debit: " + FormatMoney(-txout.nValue) + "
"; + } + + if (fAllToMe) + { + // Payment to self + int64 nValue = wtx.vout[0].nValue; + strHTML += "Debit: " + FormatMoney(-nValue) + "
"; + strHTML += "Credit: " + FormatMoney(nValue) + "
"; + } + + int64 nTxFee = nDebit - wtx.GetValueOut(); + if (nTxFee > 0) + strHTML += "Transaction fee: " + FormatMoney(-nTxFee) + "
"; + } + else + { + // + // Mixed debit transaction + // + foreach(const CTxIn& txin, wtx.vin) + if (txin.IsMine()) + strHTML += "Debit: " + FormatMoney(-txin.GetDebit()) + "
"; + foreach(const CTxOut& txout, wtx.vout) + if (txout.IsMine()) + strHTML += "Credit: " + FormatMoney(txout.GetCredit()) + "
"; + } + } + + strHTML += "Net amount: " + FormatMoney(nNet, true) + "
"; + + + // + // Message + // + if (!wtx.mapValue["message"].empty()) + strHTML += "
Message:
" + HtmlEscape(wtx.mapValue["message"], true) + "
"; + + if (wtx.IsCoinBase()) + strHTML += "
Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.
"; + + + // + // Debug view + // + if (fDebug) + { + strHTML += "

debug print

"; + foreach(const CTxIn& txin, wtx.vin) + if (txin.IsMine()) + strHTML += "Debit: " + FormatMoney(-txin.GetDebit()) + "
"; + foreach(const CTxOut& txout, wtx.vout) + if (txout.IsMine()) + strHTML += "Credit: " + FormatMoney(txout.GetCredit()) + "
"; + + strHTML += "Inputs:
"; + CRITICAL_BLOCK(cs_mapWallet) + { + foreach(const CTxIn& txin, wtx.vin) + { + COutPoint prevout = txin.prevout; + map::iterator mi = mapWallet.find(prevout.hash); + if (mi != mapWallet.end()) + { + const CWalletTx& prev = (*mi).second; + if (prevout.n < prev.vout.size()) + { + strHTML += HtmlEscape(prev.ToString(), true); + strHTML += "    " + FormatTxStatus(prev) + ", "; + strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "
"; + } + } + } + } + + strHTML += "


Transaction:
"; + strHTML += HtmlEscape(wtx.ToString(), true); + } + + + + strHTML += "
"; + string(strHTML.begin(), strHTML.end()).swap(strHTML); + m_htmlWin->SetPage(strHTML); + m_buttonOK->SetFocus(); +} + +void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event) +{ + Close(); + //Destroy(); +} + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// COptionsDialog +// + +COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent) +{ + m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee)); + m_buttonOK->SetFocus(); +} + +void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event) +{ + int64 nTmp = nTransactionFee; + ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp); + m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp)); +} + +void COptionsDialog::OnButtonOK(wxCommandEvent& event) +{ + // nTransactionFee + int64 nPrevTransactionFee = nTransactionFee; + if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee) + CWalletDB().WriteSetting("nTransactionFee", nTransactionFee); + + Close(); +} + +void COptionsDialog::OnButtonCancel(wxCommandEvent& event) +{ + Close(); +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CAboutDialog +// + +CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent) +{ + m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d Alpha", VERSION/100, VERSION%100)); + + // Workaround until upgrade to wxWidgets supporting UTF-8 + wxString str = m_staticTextMain->GetLabel(); + if (str.Find('Â') != wxNOT_FOUND) + str.Remove(str.Find('Â'), 1); + m_staticTextMain->SetLabel(str); +} + +void CAboutDialog::OnButtonOK(wxCommandEvent& event) +{ + Close(); +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CSendDialog +// + +CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent) +{ + // Init + m_textCtrlAddress->SetValue(strAddress); + m_choiceTransferType->SetSelection(0); + m_bitmapCheckMark->Show(false); + //// todo: should add a display of your balance for convenience + + // Set Icon + wxBitmap bmpSend(wxT("send16"), wxBITMAP_TYPE_RESOURCE); + bmpSend.SetMask(new wxMask(wxBitmap(wxT("send16masknoshadow"), wxBITMAP_TYPE_RESOURCE))); + wxIcon iconSend; + iconSend.CopyFromBitmap(bmpSend); + SetIcon(iconSend); + + wxCommandEvent event; + OnTextAddress(event); + + // Fixup the tab order + m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel); + m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste); + this->Layout(); +} + +void CSendDialog::OnTextAddress(wxCommandEvent& event) +{ + // Check mark + bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue()); + m_bitmapCheckMark->Show(fBitcoinAddress); + + // Grey out message if bitcoin address + bool fEnable = !fBitcoinAddress; + m_staticTextFrom->Enable(fEnable); + m_textCtrlFrom->Enable(fEnable); + m_staticTextMessage->Enable(fEnable); + m_textCtrlMessage->Enable(fEnable); + m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE)); +} + +void CSendDialog::OnKillFocusAmount(wxFocusEvent& event) +{ + // Reformat the amount + if (m_textCtrlAmount->GetValue().Trim().empty()) + return; + int64 nTmp; + if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp)) + m_textCtrlAmount->SetValue(FormatMoney(nTmp)); +} + +void CSendDialog::OnButtonAddressBook(wxCommandEvent& event) +{ + // Open address book + CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), true); + if (dialog.ShowModal()) + m_textCtrlAddress->SetValue(dialog.GetAddress()); +} + +void CSendDialog::OnButtonPaste(wxCommandEvent& event) +{ + // Copy clipboard to address box + if (wxTheClipboard->Open()) + { + if (wxTheClipboard->IsSupported(wxDF_TEXT)) + { + wxTextDataObject data; + wxTheClipboard->GetData(data); + m_textCtrlAddress->SetValue(data.GetText()); + } + wxTheClipboard->Close(); + } +} + +void CSendDialog::OnButtonSend(wxCommandEvent& event) +{ + CWalletTx wtx; + string strAddress = (string)m_textCtrlAddress->GetValue(); + + // Parse amount + int64 nValue = 0; + if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0) + { + wxMessageBox("Error in amount ", "Send Coins"); + return; + } + if (nValue > GetBalance()) + { + wxMessageBox("Amount exceeds your balance ", "Send Coins"); + return; + } + if (nValue + nTransactionFee > GetBalance()) + { + wxMessageBox(string("Total exceeds your balance when the ") + FormatMoney(nTransactionFee) + " transaction fee is included ", "Send Coins"); + return; + } + + // Parse bitcoin address + uint160 hash160; + bool fBitcoinAddress = AddressToHash160(strAddress, hash160); + + if (fBitcoinAddress) + { + // Send to bitcoin address + CScript scriptPubKey; + scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; + + if (!SendMoney(scriptPubKey, nValue, wtx)) + return; + + wxMessageBox("Payment sent ", "Sending..."); + } + else + { + // Parse IP address + CAddress addr(strAddress.c_str()); + if (addr.ip == 0) + { + wxMessageBox("Invalid address ", "Send Coins"); + return; + } + + // Message + wtx.mapValue["to"] = strAddress; + wtx.mapValue["from"] = m_textCtrlFrom->GetValue(); + wtx.mapValue["message"] = m_textCtrlMessage->GetValue(); + + // Send to IP address + CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx); + if (!pdialog->ShowModal()) + return; + } + + if (!mapAddressBook.count(strAddress)) + SetAddressBookName(strAddress, ""); + + EndModal(true); +} + +void CSendDialog::OnButtonCancel(wxCommandEvent& event) +{ + // Cancel + EndModal(false); +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CSendingDialog +// + +CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 nPriceIn, const CWalletTx& wtxIn) : CSendingDialogBase(NULL) // we have to give null so parent can't destroy us +{ + addr = addrIn; + nPrice = nPriceIn; + wtx = wtxIn; + start = wxDateTime::UNow(); + strStatus = ""; + fCanCancel = true; + fAbort = false; + fSuccess = false; + fUIDone = false; + fWorkDone = false; + + SetTitle(strprintf("Sending %s to %s...", FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str())); + m_textCtrlStatus->SetValue(""); + + _beginthread(SendingDialogStartTransfer, 0, this); +} + +CSendingDialog::~CSendingDialog() +{ + printf("~CSendingDialog()\n"); +} + +void CSendingDialog::Close() +{ + // Last one out turn out the lights. + // fWorkDone signals that work side is done and UI thread should call destroy. + // fUIDone signals that UI window has closed and work thread should call destroy. + // This allows the window to disappear and end modality when cancelled + // without making the user wait for ConnectNode to return. The dialog object + // hangs around in the background until the work thread exits. + if (IsModal()) + EndModal(fSuccess); + else + Show(false); + if (fWorkDone) + Destroy(); + else + fUIDone = true; +} + +void CSendingDialog::OnClose(wxCloseEvent& event) +{ + if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel) + { + Close(); + } + else + { + event.Veto(); + wxCommandEvent cmdevent; + OnButtonCancel(cmdevent); + } +} + +void CSendingDialog::OnButtonOK(wxCommandEvent& event) +{ + if (fWorkDone) + Close(); +} + +void CSendingDialog::OnButtonCancel(wxCommandEvent& event) +{ + if (fCanCancel) + fAbort = true; +} + +void CSendingDialog::OnPaint(wxPaintEvent& event) +{ + if (strStatus.size() > 130) + m_textCtrlStatus->SetValue(string("\n") + strStatus); + else + m_textCtrlStatus->SetValue(string("\n\n") + strStatus); + m_staticTextSending->SetFocus(); + if (!fCanCancel) + m_buttonCancel->Enable(false); + if (fWorkDone) + { + m_buttonOK->Enable(true); + m_buttonOK->SetFocus(); + m_buttonCancel->Enable(false); + } + if (fAbort && fCanCancel && IsShown()) + { + strStatus = "CANCELLED"; + m_buttonOK->Enable(true); + m_buttonOK->SetFocus(); + m_buttonCancel->Enable(false); + m_buttonCancel->SetLabel("Cancelled"); + Close(); + wxMessageBox("Transfer cancelled ", "Sending...", wxOK, this); + } + event.Skip(); + + /// debug test + if (fRandSendTest && fWorkDone && fSuccess) + { + Close(); + Sleep(1000); + RandSend(); + } +} + + +// +// Everything from here on is not in the UI thread and must only communicate +// with the rest of the dialog through variables and calling repaint. +// + +void CSendingDialog::Repaint() +{ + Refresh(); + wxPaintEvent event; + AddPendingEvent(event); +} + +bool CSendingDialog::Status() +{ + if (fUIDone) + { + Destroy(); + return false; + } + if (fAbort && fCanCancel) + { + strStatus = "CANCELLED"; + Repaint(); + fWorkDone = true; + return false; + } + return true; +} + +bool CSendingDialog::Status(const string& str) +{ + if (!Status()) + return false; + strStatus = str; + Repaint(); + return true; +} + +bool CSendingDialog::Error(const string& str) +{ + fCanCancel = false; + fWorkDone = true; + Status(string("Error: ") + str); + return false; +} + +void SendingDialogStartTransfer(void* parg) +{ + ((CSendingDialog*)parg)->StartTransfer(); +} + +void CSendingDialog::StartTransfer() +{ + // Make sure we have enough money + if (nPrice + nTransactionFee > GetBalance()) + { + Error("You don't have enough money"); + return; + } + + // We may have connected already for product details + if (!Status("Connecting...")) + return; + CNode* pnode = ConnectNode(addr, 5 * 60); + if (!pnode) + { + Error("Unable to connect"); + return; + } + + // Send order to seller, with response going to OnReply2 via event handler + if (!Status("Requesting public key...")) + return; + pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this); +} + +void SendingDialogOnReply2(void* parg, CDataStream& vRecv) +{ + ((CSendingDialog*)parg)->OnReply2(vRecv); +} + +void CSendingDialog::OnReply2(CDataStream& vRecv) +{ + if (!Status("Received public key...")) + return; + + CScript scriptPubKey; + int nRet; + try + { + vRecv >> nRet; + if (nRet > 0) + { + string strMessage; + vRecv >> strMessage; + Error("Transfer was not accepted"); + //// todo: enlarge the window and enable a hidden white box to put seller's message + return; + } + vRecv >> scriptPubKey; + } + catch (...) + { + //// what do we want to do about this? + Error("Invalid response received"); + return; + } + + // Should already be connected + CNode* pnode = ConnectNode(addr, 5 * 60); + if (!pnode) + { + Error("Lost connection"); + return; + } + + // Pause to give the user a chance to cancel + while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000)) + { + Sleep(200); + if (!Status()) + return; + } + + CRITICAL_BLOCK(cs_main) + { + // Pay + if (!Status("Creating transaction...")) + return; + if (nPrice + nTransactionFee > GetBalance()) + { + Error("You don't have enough money"); + return; + } + int64 nFeeRequired; + if (!CreateTransaction(scriptPubKey, nPrice, wtx, nFeeRequired)) + { + if (nPrice + nFeeRequired > GetBalance()) + Error(strprintf("This is an oversized transaction that requires a transaction fee of %s", FormatMoney(nFeeRequired).c_str())); + else + Error("Transaction creation failed"); + return; + } + + // Last chance to cancel + Sleep(50); + if (!Status()) + return; + fCanCancel = false; + if (fAbort) + { + fCanCancel = true; + if (!Status()) + return; + fCanCancel = false; + } + if (!Status("Sending payment...")) + return; + + // Commit + if (!CommitTransactionSpent(wtx)) + { + Error("Error finalizing payment"); + return; + } + + // Send payment tx to seller, with response going to OnReply3 via event handler + pnode->PushRequest("submitorder", wtx, SendingDialogOnReply3, this); + + // Accept and broadcast transaction + if (!wtx.AcceptTransaction()) + printf("ERROR: CSendingDialog : wtxNew.AcceptTransaction() %s failed\n", wtx.GetHash().ToString().c_str()); + wtx.RelayWalletTransaction(); + + Status("Waiting for confirmation..."); + MainFrameRepaint(); + } +} + +void SendingDialogOnReply3(void* parg, CDataStream& vRecv) +{ + ((CSendingDialog*)parg)->OnReply3(vRecv); +} + +void CSendingDialog::OnReply3(CDataStream& vRecv) +{ + int nRet; + try + { + vRecv >> nRet; + if (nRet > 0) + { + Error("The payment was sent, but the recipient was unable to verify it.\n" + "The transaction is recorded and will credit to the recipient if it is valid,\n" + "but without comment information."); + return; + } + } + catch (...) + { + //// what do we want to do about this? + Error("Payment was sent, but an invalid response was received"); + return; + } + + fSuccess = true; + fWorkDone = true; + Status("Payment completed"); +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CYourAddressDialog +// + +CYourAddressDialog::CYourAddressDialog(wxWindow* parent, const string& strInitSelected) : CYourAddressDialogBase(parent) +{ + // Init column headers + m_listCtrl->InsertColumn(0, "Label", wxLIST_FORMAT_LEFT, 200); + m_listCtrl->InsertColumn(1, "Bitcoin Address", wxLIST_FORMAT_LEFT, 350); + m_listCtrl->SetFocus(); + + // Fill listctrl with address book data + CRITICAL_BLOCK(cs_mapKeys) + { + foreach(const PAIRTYPE(string, string)& item, mapAddressBook) + { + string strAddress = item.first; + string strName = item.second; + uint160 hash160; + bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160)); + if (fMine) + { + int nIndex = InsertLine(m_listCtrl, strName, strAddress); + if (strAddress == strInitSelected) + m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); + } + } + } +} + +wxString CYourAddressDialog::GetAddress() +{ + int nIndex = GetSelection(m_listCtrl); + if (nIndex == -1) + return ""; + return GetItemText(m_listCtrl, nIndex, 1); +} + +void CYourAddressDialog::OnListEndLabelEdit(wxListEvent& event) +{ + // Update address book with edited name + if (event.IsEditCancelled()) + return; + string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1); + SetAddressBookName(strAddress, string(event.GetText())); + pframeMain->RefreshListCtrl(); +} + +void CYourAddressDialog::OnListItemSelected(wxListEvent& event) +{ +} + +void CYourAddressDialog::OnListItemActivated(wxListEvent& event) +{ + // Doubleclick edits item + wxCommandEvent event2; + OnButtonRename(event2); +} + +void CYourAddressDialog::OnButtonRename(wxCommandEvent& event) +{ + // Ask new name + int nIndex = GetSelection(m_listCtrl); + if (nIndex == -1) + return; + string strName = (string)m_listCtrl->GetItemText(nIndex); + string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); + CGetTextFromUserDialog dialog(this, "Edit Address Label", "New Label", strName); + if (!dialog.ShowModal()) + return; + strName = dialog.GetValue(); + + // Change name + SetAddressBookName(strAddress, strName); + m_listCtrl->SetItemText(nIndex, strName); + pframeMain->RefreshListCtrl(); +} + +void CYourAddressDialog::OnButtonNew(wxCommandEvent& event) +{ + // Ask name + CGetTextFromUserDialog dialog(this, "New Bitcoin Address", "Label", ""); + if (!dialog.ShowModal()) + return; + string strName = dialog.GetValue(); + + // Generate new key + string strAddress = PubKeyToAddress(GenerateNewKey()); + SetAddressBookName(strAddress, strName); + + // Add to list and select it + int nIndex = InsertLine(m_listCtrl, strName, strAddress); + SetSelection(m_listCtrl, nIndex); + m_listCtrl->SetFocus(); +} + +void CYourAddressDialog::OnButtonCopy(wxCommandEvent& event) +{ + // Copy address box to clipboard + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxTextDataObject(GetAddress())); + wxTheClipboard->Close(); + } +} + +void CYourAddressDialog::OnButtonOK(wxCommandEvent& event) +{ + // OK + EndModal(true); +} + +void CYourAddressDialog::OnButtonCancel(wxCommandEvent& event) +{ + // Cancel + EndModal(false); +} + +void CYourAddressDialog::OnClose(wxCloseEvent& event) +{ + // Close + EndModal(false); +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CAddressBookDialog +// + +CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, bool fSendingIn) : CAddressBookDialogBase(parent) +{ + fSending = fSendingIn; + if (!fSending) + m_buttonCancel->Show(false); + + // Init column headers + m_listCtrl->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 200); + m_listCtrl->InsertColumn(1, "Address", wxLIST_FORMAT_LEFT, 350); + m_listCtrl->SetFocus(); + + // Set Icon + wxBitmap bmpAddressBook(wxT("addressbook16"), wxBITMAP_TYPE_RESOURCE); + bmpAddressBook.SetMask(new wxMask(wxBitmap(wxT("addressbook16mask"), wxBITMAP_TYPE_RESOURCE))); + wxIcon iconAddressBook; + iconAddressBook.CopyFromBitmap(bmpAddressBook); + SetIcon(iconAddressBook); + + // Fill listctrl with address book data + CRITICAL_BLOCK(cs_mapKeys) + { + foreach(const PAIRTYPE(string, string)& item, mapAddressBook) + { + string strAddress = item.first; + string strName = item.second; + uint160 hash160; + bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160)); + if (!fMine) + { + int nIndex = InsertLine(m_listCtrl, strName, strAddress); + if (strAddress == strInitSelected) + m_listCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); + } + } + } +} + +wxString CAddressBookDialog::GetAddress() +{ + int nIndex = GetSelection(m_listCtrl); + if (nIndex == -1) + return ""; + return GetItemText(m_listCtrl, nIndex, 1); +} + +void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event) +{ + // Update address book with edited name + if (event.IsEditCancelled()) + return; + string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1); + SetAddressBookName(strAddress, string(event.GetText())); + pframeMain->RefreshListCtrl(); +} + +void CAddressBookDialog::OnListItemSelected(wxListEvent& event) +{ +} + +void CAddressBookDialog::OnListItemActivated(wxListEvent& event) +{ + if (fSending) + { + // Doubleclick returns selection + EndModal(GetAddress() != "" ? 2 : 0); + } + else + { + // Doubleclick edits item + wxCommandEvent event2; + OnButtonEdit(event2); + } +} + +bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle) +{ + uint160 hash160; + bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160)); + if (fMine) + wxMessageBox("This is one of your own addresses for receiving payments and cannot be entered in the address book. ", strTitle); + return fMine; +} + +void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event) +{ + // Ask new name + int nIndex = GetSelection(m_listCtrl); + if (nIndex == -1) + return; + string strName = (string)m_listCtrl->GetItemText(nIndex); + string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); + string strAddressOrg = strAddress; + do + { + CGetTextFromUserDialog dialog(this, "Edit Address", "Name", strName, "Address", strAddress); + if (!dialog.ShowModal()) + return; + strName = dialog.GetValue1(); + strAddress = dialog.GetValue2(); + } + while (CheckIfMine(strAddress, "Edit Address")); + + // Change name + if (strAddress != strAddressOrg) + CWalletDB().EraseName(strAddressOrg); + SetAddressBookName(strAddress, strName); + m_listCtrl->SetItem(nIndex, 1, strAddress); + m_listCtrl->SetItemText(nIndex, strName); + pframeMain->RefreshListCtrl(); +} + +void CAddressBookDialog::OnButtonNew(wxCommandEvent& event) +{ + // Ask name + string strName; + string strAddress; + do + { + CGetTextFromUserDialog dialog(this, "New Address", "Name", strName, "Address", strAddress); + if (!dialog.ShowModal()) + return; + strName = dialog.GetValue1(); + strAddress = dialog.GetValue2(); + } + while (CheckIfMine(strAddress, "New Address")); + + // Add to list and select it + SetAddressBookName(strAddress, strName); + int nIndex = InsertLine(m_listCtrl, strName, strAddress); + SetSelection(m_listCtrl, nIndex); + m_listCtrl->SetFocus(); + pframeMain->RefreshListCtrl(); +} + +void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event) +{ + for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--) + { + if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED)) + { + string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); + CWalletDB().EraseName(strAddress); + m_listCtrl->DeleteItem(nIndex); + } + } + pframeMain->RefreshListCtrl(); +} + +void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event) +{ + // Copy address box to clipboard + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxTextDataObject(GetAddress())); + wxTheClipboard->Close(); + } +} + +void CAddressBookDialog::OnButtonOK(wxCommandEvent& event) +{ + // OK + EndModal(GetAddress() != "" ? 1 : 0); +} + +void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event) +{ + // Cancel + EndModal(0); +} + +void CAddressBookDialog::OnClose(wxCloseEvent& event) +{ + // Close + EndModal(0); +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CProductsDialog +// + +bool CompareIntStringPairBestFirst(const pair& item1, const pair& item2) +{ + return (item1.first > item2.first); +} + +CProductsDialog::CProductsDialog(wxWindow* parent) : CProductsDialogBase(parent) +{ + // Init column headers + m_listCtrl->InsertColumn(0, "Title", wxLIST_FORMAT_LEFT, 200); + m_listCtrl->InsertColumn(1, "Price", wxLIST_FORMAT_LEFT, 80); + m_listCtrl->InsertColumn(2, "Seller", wxLIST_FORMAT_LEFT, 80); + m_listCtrl->InsertColumn(3, "Stars", wxLIST_FORMAT_LEFT, 50); + m_listCtrl->InsertColumn(4, "Power", wxLIST_FORMAT_LEFT, 50); + + // Tally top categories + map mapTopCategories; + CRITICAL_BLOCK(cs_mapProducts) + for (map::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi) + mapTopCategories[(*mi).second.mapValue["category"]]++; + + // Sort top categories + vector > vTopCategories; + for (map::iterator mi = mapTopCategories.begin(); mi != mapTopCategories.end(); ++mi) + vTopCategories.push_back(make_pair((*mi).second, (*mi).first)); + sort(vTopCategories.begin(), vTopCategories.end(), CompareIntStringPairBestFirst); + + // Fill categories combo box + int nLimit = 250; + for (vector >::iterator it = vTopCategories.begin(); it != vTopCategories.end() && nLimit-- > 0; ++it) + m_comboBoxCategory->Append((*it).second); + + // Fill window with initial search + //wxCommandEvent event; + //OnButtonSearch(event); +} + +void CProductsDialog::OnCombobox(wxCommandEvent& event) +{ + OnButtonSearch(event); +} + +bool CompareProductsBestFirst(const CProduct* p1, const CProduct* p2) +{ + return (p1->nAtoms > p2->nAtoms); +} + +void CProductsDialog::OnButtonSearch(wxCommandEvent& event) +{ + string strCategory = (string)m_comboBoxCategory->GetValue(); + string strSearch = (string)m_textCtrlSearch->GetValue(); + + // Search products + vector vProductsFound; + CRITICAL_BLOCK(cs_mapProducts) + { + for (map::iterator mi = mapProducts.begin(); mi != mapProducts.end(); ++mi) + { + CProduct& product = (*mi).second; + if (product.mapValue["category"].find(strCategory) != -1) + { + if (product.mapValue["title"].find(strSearch) != -1 || + product.mapValue["description"].find(strSearch) != -1 || + product.mapValue["seller"].find(strSearch) != -1) + { + vProductsFound.push_back(&product); + } + } + } + } + + // Sort + sort(vProductsFound.begin(), vProductsFound.end(), CompareProductsBestFirst); + + // Display + foreach(CProduct* pproduct, vProductsFound) + { + InsertLine(m_listCtrl, + pproduct->mapValue["title"], + pproduct->mapValue["price"], + pproduct->mapValue["seller"], + pproduct->mapValue["stars"], + itostr(pproduct->nAtoms)); + } +} + +void CProductsDialog::OnListItemActivated(wxListEvent& event) +{ + // Doubleclick opens product + CViewProductDialog* pdialog = new CViewProductDialog(this, m_vProduct[event.GetIndex()]); + pdialog->Show(); +} + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CEditProductDialog +// + +CEditProductDialog::CEditProductDialog(wxWindow* parent) : CEditProductDialogBase(parent) +{ + m_textCtrlLabel[0 ] = m_textCtrlLabel0; + m_textCtrlLabel[1 ] = m_textCtrlLabel1; + m_textCtrlLabel[2 ] = m_textCtrlLabel2; + m_textCtrlLabel[3 ] = m_textCtrlLabel3; + m_textCtrlLabel[4 ] = m_textCtrlLabel4; + m_textCtrlLabel[5 ] = m_textCtrlLabel5; + m_textCtrlLabel[6 ] = m_textCtrlLabel6; + m_textCtrlLabel[7 ] = m_textCtrlLabel7; + m_textCtrlLabel[8 ] = m_textCtrlLabel8; + m_textCtrlLabel[9 ] = m_textCtrlLabel9; + m_textCtrlLabel[10] = m_textCtrlLabel10; + m_textCtrlLabel[11] = m_textCtrlLabel11; + m_textCtrlLabel[12] = m_textCtrlLabel12; + m_textCtrlLabel[13] = m_textCtrlLabel13; + m_textCtrlLabel[14] = m_textCtrlLabel14; + m_textCtrlLabel[15] = m_textCtrlLabel15; + m_textCtrlLabel[16] = m_textCtrlLabel16; + m_textCtrlLabel[17] = m_textCtrlLabel17; + m_textCtrlLabel[18] = m_textCtrlLabel18; + m_textCtrlLabel[19] = m_textCtrlLabel19; + + m_textCtrlField[0 ] = m_textCtrlField0; + m_textCtrlField[1 ] = m_textCtrlField1; + m_textCtrlField[2 ] = m_textCtrlField2; + m_textCtrlField[3 ] = m_textCtrlField3; + m_textCtrlField[4 ] = m_textCtrlField4; + m_textCtrlField[5 ] = m_textCtrlField5; + m_textCtrlField[6 ] = m_textCtrlField6; + m_textCtrlField[7 ] = m_textCtrlField7; + m_textCtrlField[8 ] = m_textCtrlField8; + m_textCtrlField[9 ] = m_textCtrlField9; + m_textCtrlField[10] = m_textCtrlField10; + m_textCtrlField[11] = m_textCtrlField11; + m_textCtrlField[12] = m_textCtrlField12; + m_textCtrlField[13] = m_textCtrlField13; + m_textCtrlField[14] = m_textCtrlField14; + m_textCtrlField[15] = m_textCtrlField15; + m_textCtrlField[16] = m_textCtrlField16; + m_textCtrlField[17] = m_textCtrlField17; + m_textCtrlField[18] = m_textCtrlField18; + m_textCtrlField[19] = m_textCtrlField19; + + m_buttonDel[0 ] = m_buttonDel0; + m_buttonDel[1 ] = m_buttonDel1; + m_buttonDel[2 ] = m_buttonDel2; + m_buttonDel[3 ] = m_buttonDel3; + m_buttonDel[4 ] = m_buttonDel4; + m_buttonDel[5 ] = m_buttonDel5; + m_buttonDel[6 ] = m_buttonDel6; + m_buttonDel[7 ] = m_buttonDel7; + m_buttonDel[8 ] = m_buttonDel8; + m_buttonDel[9 ] = m_buttonDel9; + m_buttonDel[10] = m_buttonDel10; + m_buttonDel[11] = m_buttonDel11; + m_buttonDel[12] = m_buttonDel12; + m_buttonDel[13] = m_buttonDel13; + m_buttonDel[14] = m_buttonDel14; + m_buttonDel[15] = m_buttonDel15; + m_buttonDel[16] = m_buttonDel16; + m_buttonDel[17] = m_buttonDel17; + m_buttonDel[18] = m_buttonDel18; + m_buttonDel[19] = m_buttonDel19; + + for (int i = 1; i < FIELDS_MAX; i++) + ShowLine(i, false); + + LayoutAll(); +} + +void CEditProductDialog::LayoutAll() +{ + m_scrolledWindow->Layout(); + m_scrolledWindow->GetSizer()->Fit(m_scrolledWindow); + this->Layout(); +} + +void CEditProductDialog::ShowLine(int i, bool fShow) +{ + m_textCtrlLabel[i]->Show(fShow); + m_textCtrlField[i]->Show(fShow); + m_buttonDel[i]->Show(fShow); +} + +void CEditProductDialog::OnButtonDel0(wxCommandEvent& event) { OnButtonDel(event, 0); } +void CEditProductDialog::OnButtonDel1(wxCommandEvent& event) { OnButtonDel(event, 1); } +void CEditProductDialog::OnButtonDel2(wxCommandEvent& event) { OnButtonDel(event, 2); } +void CEditProductDialog::OnButtonDel3(wxCommandEvent& event) { OnButtonDel(event, 3); } +void CEditProductDialog::OnButtonDel4(wxCommandEvent& event) { OnButtonDel(event, 4); } +void CEditProductDialog::OnButtonDel5(wxCommandEvent& event) { OnButtonDel(event, 5); } +void CEditProductDialog::OnButtonDel6(wxCommandEvent& event) { OnButtonDel(event, 6); } +void CEditProductDialog::OnButtonDel7(wxCommandEvent& event) { OnButtonDel(event, 7); } +void CEditProductDialog::OnButtonDel8(wxCommandEvent& event) { OnButtonDel(event, 8); } +void CEditProductDialog::OnButtonDel9(wxCommandEvent& event) { OnButtonDel(event, 9); } +void CEditProductDialog::OnButtonDel10(wxCommandEvent& event) { OnButtonDel(event, 10); } +void CEditProductDialog::OnButtonDel11(wxCommandEvent& event) { OnButtonDel(event, 11); } +void CEditProductDialog::OnButtonDel12(wxCommandEvent& event) { OnButtonDel(event, 12); } +void CEditProductDialog::OnButtonDel13(wxCommandEvent& event) { OnButtonDel(event, 13); } +void CEditProductDialog::OnButtonDel14(wxCommandEvent& event) { OnButtonDel(event, 14); } +void CEditProductDialog::OnButtonDel15(wxCommandEvent& event) { OnButtonDel(event, 15); } +void CEditProductDialog::OnButtonDel16(wxCommandEvent& event) { OnButtonDel(event, 16); } +void CEditProductDialog::OnButtonDel17(wxCommandEvent& event) { OnButtonDel(event, 17); } +void CEditProductDialog::OnButtonDel18(wxCommandEvent& event) { OnButtonDel(event, 18); } +void CEditProductDialog::OnButtonDel19(wxCommandEvent& event) { OnButtonDel(event, 19); } + +void CEditProductDialog::OnButtonDel(wxCommandEvent& event, int n) +{ + Freeze(); + int x, y; + m_scrolledWindow->GetViewStart(&x, &y); + int i; + for (i = n; i < FIELDS_MAX-1; i++) + { + m_textCtrlLabel[i]->SetValue(m_textCtrlLabel[i+1]->GetValue()); + m_textCtrlField[i]->SetValue(m_textCtrlField[i+1]->GetValue()); + if (!m_buttonDel[i+1]->IsShown()) + break; + } + m_textCtrlLabel[i]->SetValue(""); + m_textCtrlField[i]->SetValue(""); + ShowLine(i, false); + m_buttonAddField->Enable(true); + LayoutAll(); + m_scrolledWindow->Scroll(0, y); + Thaw(); +} + +void CEditProductDialog::OnButtonAddField(wxCommandEvent& event) +{ + for (int i = 0; i < FIELDS_MAX; i++) + { + if (!m_buttonDel[i]->IsShown()) + { + Freeze(); + ShowLine(i, true); + if (i == FIELDS_MAX-1) + m_buttonAddField->Enable(false); + LayoutAll(); + m_scrolledWindow->Scroll(0, 99999); + Thaw(); + break; + } + } +} + +void CEditProductDialog::OnButtonSend(wxCommandEvent& event) +{ + CProduct product; + GetProduct(product); + + // Sign the detailed product + product.vchPubKeyFrom = keyUser.GetPubKey(); + if (!keyUser.Sign(product.GetSigHash(), product.vchSig)) + { + wxMessageBox("Error digitally signing the product "); + return; + } + + // Save detailed product + AddToMyProducts(product); + + // Strip down to summary product + product.mapDetails.clear(); + product.vOrderForm.clear(); + + // Sign the summary product + if (!keyUser.Sign(product.GetSigHash(), product.vchSig)) + { + wxMessageBox("Error digitally signing the product "); + return; + } + + // Verify + if (!product.CheckProduct()) + { + wxMessageBox("Errors found in product "); + return; + } + + // Broadcast + AdvertStartPublish(pnodeLocalHost, MSG_PRODUCT, 0, product); + + Destroy(); +} + +void CEditProductDialog::OnButtonPreview(wxCommandEvent& event) +{ + CProduct product; + GetProduct(product); + CViewProductDialog* pdialog = new CViewProductDialog(this, product); + pdialog->Show(); +} + +void CEditProductDialog::OnButtonCancel(wxCommandEvent& event) +{ + Destroy(); +} + +void CEditProductDialog::SetProduct(const CProduct& productIn) +{ + CProduct product = productIn; + + m_comboBoxCategory->SetValue(product.mapValue["category"]); + m_textCtrlTitle->SetValue(product.mapValue["title"]); + m_textCtrlPrice->SetValue(product.mapValue["price"]); + m_textCtrlDescription->SetValue(product.mapValue["description"]); + m_textCtrlInstructions->SetValue(product.mapValue["instructions"]); + + for (int i = 0; i < FIELDS_MAX; i++) + { + bool fUsed = i < product.vOrderForm.size(); + m_buttonDel[i]->Show(fUsed); + m_textCtrlLabel[i]->Show(fUsed); + m_textCtrlField[i]->Show(fUsed); + if (!fUsed) + continue; + + m_textCtrlLabel[i]->SetValue(product.vOrderForm[i].first); + string strControl = product.vOrderForm[i].second; + if (strControl.substr(0, 5) == "text=") + m_textCtrlField[i]->SetValue(""); + else if (strControl.substr(0, 7) == "choice=") + m_textCtrlField[i]->SetValue(strControl.substr(7)); + else + m_textCtrlField[i]->SetValue(strControl); + } +} + +void CEditProductDialog::GetProduct(CProduct& product) +{ + // map mapValue; + // vector > vOrderForm; + + product.mapValue["category"] = m_comboBoxCategory->GetValue().Trim(); + product.mapValue["title"] = m_textCtrlTitle->GetValue().Trim(); + product.mapValue["price"] = m_textCtrlPrice->GetValue().Trim(); + product.mapValue["description"] = m_textCtrlDescription->GetValue().Trim(); + product.mapValue["instructions"] = m_textCtrlInstructions->GetValue().Trim(); + + for (int i = 0; i < FIELDS_MAX; i++) + { + if (m_buttonDel[i]->IsShown()) + { + string strLabel = (string)m_textCtrlLabel[i]->GetValue().Trim(); + string strControl = (string)m_textCtrlField[i]->GetValue(); + if (strControl.empty()) + strControl = "text="; + else + strControl = "choice=" + strControl; + product.vOrderForm.push_back(make_pair(strLabel, strControl)); + } + } +} + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CViewProductDialog +// + +CViewProductDialog::CViewProductDialog(wxWindow* parent, const CProduct& productIn) : CViewProductDialogBase(parent) +{ + Connect(wxEVT_REPLY1, wxCommandEventHandler(CViewProductDialog::OnReply1), NULL, this); + AddCallbackAvailable(GetEventHandler()); + + // Fill display with product summary while waiting for details + product = productIn; + UpdateProductDisplay(false); + + m_buttonBack->Enable(false); + m_buttonNext->Enable(!product.vOrderForm.empty()); + m_htmlWinReviews->Show(true); + m_scrolledWindow->Show(false); + this->Layout(); + + // Request details from seller + _beginthread(ThreadRequestProductDetails, 0, new pair(product, GetEventHandler())); +} + +CViewProductDialog::~CViewProductDialog() +{ + RemoveCallbackAvailable(GetEventHandler()); +} + +void ThreadRequestProductDetails(void* parg) +{ + // Extract parameters + pair* pitem = (pair*)parg; + CProduct product = pitem->first; + wxEvtHandler* pevthandler = pitem->second; + delete pitem; + + // Connect to seller + CNode* pnode = ConnectNode(product.addr, 5 * 60); + if (!pnode) + { + CDataStream ssEmpty; + AddPendingReplyEvent1(pevthandler, ssEmpty); + return; + } + + // Request detailed product, with response going to OnReply1 via dialog's event handler + pnode->PushRequest("getdetails", product.GetHash(), AddPendingReplyEvent1, (void*)pevthandler); +} + +void CViewProductDialog::OnReply1(wxCommandEvent& event) +{ + CDataStream ss = GetStreamFromEvent(event); + if (ss.empty()) + { + product.mapValue["description"] = "-- CAN'T CONNECT TO SELLER --\n"; + UpdateProductDisplay(true); + return; + } + + int nRet; + CProduct product2; + try + { + ss >> nRet; + if (nRet > 0) + throw false; + ss >> product2; + if (product2.GetHash() != product.GetHash()) + throw false; + if (!product2.CheckSignature()) + throw false; + } + catch (...) + { + product.mapValue["description"] = "-- INVALID RESPONSE --\n"; + UpdateProductDisplay(true); + return; + } + + product = product2; + UpdateProductDisplay(true); +} + +bool CompareReviewsBestFirst(const CReview* p1, const CReview* p2) +{ + return (p1->nAtoms > p2->nAtoms); +} + +void CViewProductDialog::UpdateProductDisplay(bool fDetails) +{ + // Product and reviews + string strHTML; + strHTML.reserve(4000); + strHTML += "\n" + "\n" + "\n" + "\n" + "\n"; + strHTML += "Category: " + HtmlEscape(product.mapValue["category"]) + "
\n"; + strHTML += "Title: " + HtmlEscape(product.mapValue["title"]) + "
\n"; + strHTML += "Price: " + HtmlEscape(product.mapValue["price"]) + "
\n"; + + if (!fDetails) + strHTML += "Loading details...
\n
\n"; + else + strHTML += HtmlEscape(product.mapValue["description"], true) + "
\n
\n"; + + strHTML += "Reviews:
\n
\n"; + + if (!product.vchPubKeyFrom.empty()) + { + CReviewDB reviewdb("r"); + + // Get reviews + vector vReviews; + reviewdb.ReadReviews(product.GetUserHash(), vReviews); + + // Get reviewer's number of atoms + vector vSortedReviews; + vSortedReviews.reserve(vReviews.size()); + for (vector::reverse_iterator it = vReviews.rbegin(); it != vReviews.rend(); ++it) + { + CReview& review = *it; + CUser user; + reviewdb.ReadUser(review.GetUserHash(), user); + review.nAtoms = user.GetAtomCount(); + vSortedReviews.push_back(&review); + } + + reviewdb.Close(); + + // Sort + stable_sort(vSortedReviews.begin(), vSortedReviews.end(), CompareReviewsBestFirst); + + // Format reviews + foreach(CReview* preview, vSortedReviews) + { + CReview& review = *preview; + int nStars = atoi(review.mapValue["stars"].c_str()); + if (nStars < 1 || nStars > 5) + continue; + + strHTML += "" + itostr(nStars) + (nStars == 1 ? " star" : " stars") + ""; + strHTML += "     "; + strHTML += DateStr(atoi64(review.mapValue["date"])) + "
\n"; + strHTML += HtmlEscape(review.mapValue["review"], true); + strHTML += "
\n
\n"; + } + } + + strHTML += "\n\n"; + + // Shrink capacity to fit + string(strHTML.begin(), strHTML.end()).swap(strHTML); + + m_htmlWinReviews->SetPage(strHTML); + + ///// need to find some other indicator to use so can allow empty order form + if (product.vOrderForm.empty()) + return; + + // Order form + m_staticTextInstructions->SetLabel(product.mapValue["instructions"]); + for (int i = 0; i < FIELDS_MAX; i++) + { + m_staticTextLabel[i] = NULL; + m_textCtrlField[i] = NULL; + m_choiceField[i] = NULL; + } + + // Construct flexgridsizer + wxBoxSizer* bSizer21 = (wxBoxSizer*)m_scrolledWindow->GetSizer(); + wxFlexGridSizer* fgSizer; + fgSizer = new wxFlexGridSizer(0, 2, 0, 0); + fgSizer->AddGrowableCol(1); + fgSizer->SetFlexibleDirection(wxBOTH); + fgSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + + // Construct order form fields + wxWindow* windowLast = NULL; + for (int i = 0; i < product.vOrderForm.size(); i++) + { + string strLabel = product.vOrderForm[i].first; + string strControl = product.vOrderForm[i].second; + + if (strLabel.size() < 20) + strLabel.insert(strLabel.begin(), 20 - strLabel.size(), ' '); + + m_staticTextLabel[i] = new wxStaticText(m_scrolledWindow, wxID_ANY, strLabel, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + m_staticTextLabel[i]->Wrap(-1); + fgSizer->Add(m_staticTextLabel[i], 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5); + + if (strControl.substr(0, 5) == "text=") + { + m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5); + windowLast = m_textCtrlField[i]; + } + else if (strControl.substr(0, 7) == "choice=") + { + vector vChoices; + ParseString(strControl.substr(7), ',', vChoices); + + wxArrayString arraystring; + foreach(const string& str, vChoices) + arraystring.Add(str); + + m_choiceField[i] = new wxChoice(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, arraystring, 0); + fgSizer->Add(m_choiceField[i], 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + windowLast = m_choiceField[i]; + } + else + { + m_textCtrlField[i] = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + fgSizer->Add(m_textCtrlField[i], 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5); + m_staticTextLabel[i]->Show(false); + m_textCtrlField[i]->Show(false); + } + } + + // Insert after instructions and before submit/cancel buttons + bSizer21->Insert(2, fgSizer, 0, wxEXPAND|wxRIGHT|wxLEFT, 5); + m_scrolledWindow->Layout(); + bSizer21->Fit(m_scrolledWindow); + this->Layout(); + + // Fixup the tab order + m_buttonSubmitForm->MoveAfterInTabOrder(windowLast); + m_buttonCancelForm->MoveAfterInTabOrder(m_buttonSubmitForm); + //m_buttonBack->MoveAfterInTabOrder(m_buttonCancelForm); + //m_buttonNext->MoveAfterInTabOrder(m_buttonBack); + //m_buttonCancel->MoveAfterInTabOrder(m_buttonNext); + this->Layout(); +} + +void CViewProductDialog::GetOrder(CWalletTx& wtx) +{ + wtx.SetNull(); + for (int i = 0; i < product.vOrderForm.size(); i++) + { + string strValue; + if (m_textCtrlField[i]) + strValue = m_textCtrlField[i]->GetValue().Trim(); + else + strValue = m_choiceField[i]->GetStringSelection(); + wtx.vOrderForm.push_back(make_pair(m_staticTextLabel[i]->GetLabel(), strValue)); + } +} + +void CViewProductDialog::OnButtonSubmitForm(wxCommandEvent& event) +{ + m_buttonSubmitForm->Enable(false); + m_buttonCancelForm->Enable(false); + + CWalletTx wtx; + GetOrder(wtx); + + CSendingDialog* pdialog = new CSendingDialog(this, product.addr, atoi64(product.mapValue["price"]), wtx); + if (!pdialog->ShowModal()) + { + m_buttonSubmitForm->Enable(true); + m_buttonCancelForm->Enable(true); + return; + } +} + +void CViewProductDialog::OnButtonCancelForm(wxCommandEvent& event) +{ + Destroy(); +} + +void CViewProductDialog::OnButtonBack(wxCommandEvent& event) +{ + Freeze(); + m_htmlWinReviews->Show(true); + m_scrolledWindow->Show(false); + m_buttonBack->Enable(false); + m_buttonNext->Enable(!product.vOrderForm.empty()); + this->Layout(); + Thaw(); +} + +void CViewProductDialog::OnButtonNext(wxCommandEvent& event) +{ + if (!product.vOrderForm.empty()) + { + Freeze(); + m_htmlWinReviews->Show(false); + m_scrolledWindow->Show(true); + m_buttonBack->Enable(true); + m_buttonNext->Enable(false); + this->Layout(); + Thaw(); + } +} + +void CViewProductDialog::OnButtonCancel(wxCommandEvent& event) +{ + Destroy(); +} + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CViewOrderDialog +// + +CViewOrderDialog::CViewOrderDialog(wxWindow* parent, CWalletTx order, bool fReceived) : CViewOrderDialogBase(parent) +{ + int64 nPrice = (fReceived ? order.GetCredit() : order.GetDebit()); + + string strHTML; + strHTML.reserve(4000); + strHTML += "\n" + "\n" + "\n" + "\n" + "\n"; + strHTML += "Time: " + HtmlEscape(DateTimeStr(order.nTimeReceived)) + "
\n"; + strHTML += "Price: " + HtmlEscape(FormatMoney(nPrice)) + "
\n"; + strHTML += "Status: " + HtmlEscape(FormatTxStatus(order)) + "
\n"; + + strHTML += "\n"; + for (int i = 0; i < order.vOrderForm.size(); i++) + { + strHTML += " "; + strHTML += "\n"; + } + strHTML += "
" + HtmlEscape(order.vOrderForm[i].first) + ":" + HtmlEscape(order.vOrderForm[i].second) + "
\n"; + + strHTML += "\n\n"; + + // Shrink capacity to fit + // (strings are ref counted, so it may live on in SetPage) + string(strHTML.begin(), strHTML.end()).swap(strHTML); + + m_htmlWin->SetPage(strHTML); +} + +void CViewOrderDialog::OnButtonOK(wxCommandEvent& event) +{ + Destroy(); +} + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CEditReviewDialog +// + +CEditReviewDialog::CEditReviewDialog(wxWindow* parent) : CEditReviewDialogBase(parent) +{ +} + +void CEditReviewDialog::OnButtonSubmit(wxCommandEvent& event) +{ + if (m_choiceStars->GetSelection() == -1) + { + wxMessageBox("Please select a rating "); + return; + } + + CReview review; + GetReview(review); + + // Sign the review + review.vchPubKeyFrom = keyUser.GetPubKey(); + if (!keyUser.Sign(review.GetSigHash(), review.vchSig)) + { + wxMessageBox("Unable to digitally sign the review "); + return; + } + + // Broadcast + if (!review.AcceptReview()) + { + wxMessageBox("Save failed "); + return; + } + RelayMessage(CInv(MSG_REVIEW, review.GetHash()), review); + + Destroy(); +} + +void CEditReviewDialog::OnButtonCancel(wxCommandEvent& event) +{ + Destroy(); +} + +void CEditReviewDialog::GetReview(CReview& review) +{ + review.mapValue["time"] = i64tostr(GetAdjustedTime()); + review.mapValue["stars"] = itostr(m_choiceStars->GetSelection()+1); + review.mapValue["review"] = m_textCtrlReview->GetValue(); +} + + + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CMyApp +// + +// Define a new application +class CMyApp: public wxApp +{ + public: + CMyApp(){}; + ~CMyApp(){}; + bool OnInit(); + bool OnInit2(); + int OnExit(); + + // 2nd-level exception handling: we get all the exceptions occurring in any + // event handler here + virtual bool OnExceptionInMainLoop(); + + // 3rd, and final, level exception handling: whenever an unhandled + // exception is caught, this function is called + virtual void OnUnhandledException(); + + // and now for something different: this function is called in case of a + // crash (e.g. dereferencing null pointer, division by 0, ...) + virtual void OnFatalException(); +}; + +IMPLEMENT_APP(CMyApp) + +bool CMyApp::OnInit() +{ + try + { + return OnInit2(); + } + catch (std::exception& e) { + PrintException(&e, "OnInit()"); + } catch (...) { + PrintException(NULL, "OnInit()"); + } + return false; +} + +map ParseParameters(int argc, char* argv[]) +{ + map mapArgs; + for (int i = 0; i < argc; i++) + { + char psz[10000]; + strcpy(psz, argv[i]); + char* pszValue = ""; + if (strchr(psz, '=')) + { + pszValue = strchr(psz, '='); + *pszValue++ = '\0'; + } + strlwr(psz); + if (psz[0] == '-') + psz[0] = '/'; + mapArgs[psz] = pszValue; + } + return mapArgs; +} + +bool CMyApp::OnInit2() +{ +#ifdef _MSC_VER + // Turn off microsoft heap dump noise for now + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); +#endif +#ifdef __WXDEBUG__ + // Disable malfunctioning wxWidgets debug assertion + g_isPainting = 10000; +#endif + + //// debug print + printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + printf("Bitcoin version %d, Windows version %08x\n", VERSION, GetVersion()); + + // + // Limit to single instance per user + // Required to protect the database files if we're going to keep deleting log.* + // + wxString strMutexName = wxString("Bitcoin.") + getenv("HOMEPATH"); + for (int i = 0; i < strMutexName.size(); i++) + if (!isalnum(strMutexName[i])) + strMutexName[i] = '.'; + wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); + if (psingleinstancechecker->IsAnotherRunning()) + { + printf("Existing instance found\n"); + unsigned int nStart = GetTime(); + loop + { + // Show the previous instance and exit + HWND hwndPrev = FindWindow("wxWindowClassNR", "Bitcoin"); + if (hwndPrev) + { + if (IsIconic(hwndPrev)) + ShowWindow(hwndPrev, SW_RESTORE); + SetForegroundWindow(hwndPrev); + return false; + } + + if (GetTime() > nStart + 60) + return false; + + // Resume this instance if the other exits + delete psingleinstancechecker; + Sleep(1000); + psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); + if (!psingleinstancechecker->IsAnotherRunning()) + break; + } + } + + // + // Parameters + // + wxImage::AddHandler(new wxPNGHandler); + map mapArgs = ParseParameters(argc, argv); + + if (mapArgs.count("/datadir")) + strSetDataDir = mapArgs["/datadir"]; + + if (mapArgs.count("/proxy")) + addrProxy = CAddress(mapArgs["/proxy"].c_str()); + + if (mapArgs.count("/debug")) + fDebug = true; + + if (mapArgs.count("/dropmessages")) + { + nDropMessagesTest = atoi(mapArgs["/dropmessages"]); + if (nDropMessagesTest == 0) + nDropMessagesTest = 20; + } + + if (mapArgs.count("/loadblockindextest")) + { + CTxDB txdb("r"); + txdb.LoadBlockIndex(); + PrintBlockTree(); + ExitProcess(0); + } + + // + // Load data files + // + string strErrors; + int64 nStart, nEnd; + + printf("Loading addresses...\n"); + QueryPerformanceCounter((LARGE_INTEGER*)&nStart); + if (!LoadAddresses()) + strErrors += "Error loading addr.dat \n"; + QueryPerformanceCounter((LARGE_INTEGER*)&nEnd); + printf(" addresses %20I64d\n", nEnd - nStart); + + printf("Loading block index...\n"); + QueryPerformanceCounter((LARGE_INTEGER*)&nStart); + if (!LoadBlockIndex()) + strErrors += "Error loading blkindex.dat \n"; + QueryPerformanceCounter((LARGE_INTEGER*)&nEnd); + printf(" block index %20I64d\n", nEnd - nStart); + + printf("Loading wallet...\n"); + QueryPerformanceCounter((LARGE_INTEGER*)&nStart); + if (!LoadWallet()) + strErrors += "Error loading wallet.dat \n"; + QueryPerformanceCounter((LARGE_INTEGER*)&nEnd); + printf(" wallet %20I64d\n", nEnd - nStart); + + printf("Done loading\n"); + + //// debug print + printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); + printf("nBestHeight = %d\n", nBestHeight); + printf("mapKeys.size() = %d\n", mapKeys.size()); + printf("mapPubKeys.size() = %d\n", mapPubKeys.size()); + printf("mapWallet.size() = %d\n", mapWallet.size()); + printf("mapAddressBook.size() = %d\n", mapAddressBook.size()); + + if (!strErrors.empty()) + { + wxMessageBox(strErrors, "Bitcoin"); + OnExit(); + return false; + } + + // Add wallet transactions that aren't already in a block to mapTransactions + ReacceptWalletTransactions(); + + // + // Parameters + // + if (mapArgs.count("/printblockindex") || mapArgs.count("/printblocktree")) + { + PrintBlockTree(); + OnExit(); + return false; + } + + if (mapArgs.count("/gen")) + { + if (mapArgs["/gen"].empty()) + fGenerateBitcoins = true; + else + fGenerateBitcoins = atoi(mapArgs["/gen"].c_str()); + } + + // + // Create the main frame window + // + { + pframeMain = new CMainFrame(NULL); + pframeMain->Show(); + + if (!CheckDiskSpace()) + { + OnExit(); + return false; + } + + if (!StartNode(strErrors)) + wxMessageBox(strErrors, "Bitcoin"); + + if (fGenerateBitcoins) + if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1) + printf("Error: _beginthread(ThreadBitcoinMiner) failed\n"); + + // + // Tests + // + if (argc >= 2 && stricmp(argv[1], "/send") == 0) + { + int64 nValue = 1; + if (argc >= 3) + ParseMoney(argv[2], nValue); + + string strAddress; + if (argc >= 4) + strAddress = argv[3]; + CAddress addr(strAddress.c_str()); + + CWalletTx wtx; + wtx.mapValue["to"] = strAddress; + wtx.mapValue["from"] = addrLocalHost.ToString(); + wtx.mapValue["message"] = "command line send"; + + // Send to IP address + CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx); + if (!pdialog->ShowModal()) + return false; + } + + if (mapArgs.count("/randsendtest")) + { + if (!mapArgs["/randsendtest"].empty()) + _beginthread(ThreadRandSendTest, 0, new string(mapArgs["/randsendtest"])); + else + fRandSendTest = true; + fDebug = true; + } + } + + return true; +} + +int CMyApp::OnExit() +{ + Shutdown(NULL); + return wxApp::OnExit(); +} + +bool CMyApp::OnExceptionInMainLoop() +{ + try + { + throw; + } + catch (std::exception& e) + { + PrintException(&e, "CMyApp::OnExceptionInMainLoop()"); + wxLogWarning(_T("Exception %s %s"), typeid(e).name(), e.what()); + Sleep(1000); + throw; + } + catch (...) + { + PrintException(NULL, "CMyApp::OnExceptionInMainLoop()"); + wxLogWarning(_T("Unknown exception")); + Sleep(1000); + throw; + } + + return true; +} + +void CMyApp::OnUnhandledException() +{ + // this shows how we may let some exception propagate uncaught + try + { + throw; + } + catch (std::exception& e) + { + PrintException(&e, "CMyApp::OnUnhandledException()"); + wxLogWarning(_T("Exception %s %s"), typeid(e).name(), e.what()); + Sleep(1000); + throw; + } + catch (...) + { + PrintException(NULL, "CMyApp::OnUnhandledException()"); + wxLogWarning(_T("Unknown exception")); + Sleep(1000); + throw; + } +} + +void CMyApp::OnFatalException() +{ + wxMessageBox("Program has crashed and will terminate. ", "Bitcoin", wxOK | wxICON_ERROR); +} + + + +void MainFrameRepaint() +{ + if (pframeMain) + { + printf("MainFrameRepaint()\n"); + wxPaintEvent event; + pframeMain->Refresh(); + pframeMain->AddPendingEvent(event); + } +} + + + + + + + +// randsendtest to bitcoin address +void ThreadRandSendTest(void* parg) +{ + string strAddress = *(string*)parg; + uint160 hash160; + if (!AddressToHash160(strAddress, hash160)) + { + wxMessageBox(strprintf("ThreadRandSendTest: Bitcoin address '%s' not valid ", strAddress.c_str())); + return; + } + + loop + { + Sleep(GetRand(30) * 1000 + 100); + + // Message + CWalletTx wtx; + wtx.mapValue["to"] = strAddress; + wtx.mapValue["from"] = addrLocalHost.ToString(); + static int nRep; + wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep); + + // Value + int64 nValue = (GetRand(9) + 1) * 100 * CENT; + if (GetBalance() < nValue) + { + wxMessageBox("Out of money "); + return; + } + nValue += (nRep % 100) * CENT; + + // Send to bitcoin address + CScript scriptPubKey; + scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; + + if (!SendMoney(scriptPubKey, nValue, wtx)) + return; + } +} + + +// randsendtest to any connected node +void RandSend() +{ + CWalletTx wtx; + + while (vNodes.empty()) + Sleep(1000); + CAddress addr; + CRITICAL_BLOCK(cs_vNodes) + addr = vNodes[GetRand(vNodes.size())]->addr; + + // Message + wtx.mapValue["to"] = addr.ToString(); + wtx.mapValue["from"] = addrLocalHost.ToString(); + static int nRep; + wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep); + + // Value + int64 nValue = (GetRand(999) + 1) * CENT; + if (GetBalance() < nValue) + { + wxMessageBox("Out of money "); + return; + } + + // Send to IP address + CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx); + if (!pdialog->Show()) + wxMessageBox("ShowModal Failed "); +} diff --git a/ui.h b/ui.h new file mode 100644 index 000000000..163554a59 --- /dev/null +++ b/ui.h @@ -0,0 +1,420 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + + + + +DECLARE_EVENT_TYPE(wxEVT_CROSSTHREADCALL, -1) +DECLARE_EVENT_TYPE(wxEVT_REPLY1, -1) +DECLARE_EVENT_TYPE(wxEVT_REPLY2, -1) +DECLARE_EVENT_TYPE(wxEVT_REPLY3, -1) +DECLARE_EVENT_TYPE(wxEVT_TABLEADDED, -1) +DECLARE_EVENT_TYPE(wxEVT_TABLEUPDATED, -1) +DECLARE_EVENT_TYPE(wxEVT_TABLEDELETED, -1) + +enum +{ + UICALL_ADDORDER = 1, + UICALL_UPDATEORDER, +}; + + + +extern void HandleCtrlA(wxKeyEvent& event); +extern string DateTimeStr(int64 nTime); +extern string FormatTxStatus(const CWalletTx& wtx); +extern void CrossThreadCall(int nID, void* pdata); +extern void MainFrameRepaint(); +extern void Shutdown(void* parg); + + + + + + +class CMainFrame : public CMainFrameBase +{ +protected: + // Event handlers + void OnClose(wxCloseEvent& event); + void OnMouseEvents(wxMouseEvent& event); + void OnKeyDown(wxKeyEvent& event) { HandleCtrlA(event); } + void OnIdle(wxIdleEvent& event); + void OnPaint(wxPaintEvent& event); + void OnPaintListCtrl(wxPaintEvent& event); + void OnMenuFileExit(wxCommandEvent& event); + void OnMenuOptionsGenerate(wxCommandEvent& event); + void OnMenuOptionsChangeYourAddress(wxCommandEvent& event); + void OnMenuOptionsOptions(wxCommandEvent& event); + void OnMenuHelpAbout(wxCommandEvent& event); + void OnButtonSend(wxCommandEvent& event); + void OnButtonAddressBook(wxCommandEvent& event); + void OnSetFocusAddress(wxFocusEvent& event); + void OnMouseEventsAddress(wxMouseEvent& event); + void OnButtonCopy(wxCommandEvent& event); + void OnButtonChange(wxCommandEvent& event); + void OnListColBeginDrag(wxListEvent& event); + void OnListItemActivatedAllTransactions(wxListEvent& event); + void OnListItemActivatedProductsSent(wxListEvent& event); + void OnListItemActivatedOrdersSent(wxListEvent& event); + void OnListItemActivatedOrdersReceived(wxListEvent& event); + +public: + /** Constructor */ + CMainFrame(wxWindow* parent); + ~CMainFrame(); + + // Custom + bool fRefreshListCtrl; + bool fRefreshListCtrlRunning; + bool fOnSetFocusAddress; + CBlockIndex* pindexBestLast; + set setUnmaturedDisplayed; + + void OnCrossThreadCall(wxCommandEvent& event); + void InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5); + void InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1); + void RefreshListCtrl(); + void RefreshStatus(); +}; + + + + +class CTxDetailsDialog : public CTxDetailsDialogBase +{ +protected: + // Event handlers + void OnButtonOK(wxCommandEvent& event); + +public: + /** Constructor */ + CTxDetailsDialog(wxWindow* parent, CWalletTx wtx); + + // State + CWalletTx wtx; +}; + + + +class COptionsDialog : public COptionsDialogBase +{ +protected: + // Event handlers + void OnKillFocusTransactionFee(wxFocusEvent& event); + void OnButtonOK(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + +public: + /** Constructor */ + COptionsDialog(wxWindow* parent); +}; + + + +class CAboutDialog : public CAboutDialogBase +{ +protected: + // Event handlers + void OnButtonOK(wxCommandEvent& event); + +public: + /** Constructor */ + CAboutDialog(wxWindow* parent); +}; + + + +class CSendDialog : public CSendDialogBase +{ +protected: + // Event handlers + void OnKeyDown(wxKeyEvent& event) { HandleCtrlA(event); } + void OnTextAddress(wxCommandEvent& event); + void OnKillFocusAmount(wxFocusEvent& event); + void OnButtonAddressBook(wxCommandEvent& event); + void OnButtonPaste(wxCommandEvent& event); + void OnButtonSend(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + +public: + /** Constructor */ + CSendDialog(wxWindow* parent, const wxString& strAddress=""); +}; + + + +class CSendingDialog : public CSendingDialogBase +{ +public: + // Event handlers + void OnClose(wxCloseEvent& event); + void OnButtonOK(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + void OnPaint(wxPaintEvent& event); + +public: + /** Constructor */ + CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 nPriceIn, const CWalletTx& wtxIn); + ~CSendingDialog(); + + // State + CAddress addr; + int64 nPrice; + CWalletTx wtx; + wxDateTime start; + string strStatus; + bool fCanCancel; + bool fAbort; + bool fSuccess; + bool fUIDone; + bool fWorkDone; + + void Close(); + void Repaint(); + bool Status(); + bool Status(const string& str); + bool Error(const string& str); + void StartTransfer(); + void OnReply2(CDataStream& vRecv); + void OnReply3(CDataStream& vRecv); +}; + +void SendingDialogStartTransfer(void* parg); +void SendingDialogOnReply2(void* parg, CDataStream& vRecv); +void SendingDialogOnReply3(void* parg, CDataStream& vRecv); + + + +class CYourAddressDialog : public CYourAddressDialogBase +{ +protected: + // Event handlers + void OnListEndLabelEdit(wxListEvent& event); + void OnListItemSelected(wxListEvent& event); + void OnListItemActivated(wxListEvent& event); + void OnButtonRename(wxCommandEvent& event); + void OnButtonNew(wxCommandEvent& event); + void OnButtonCopy(wxCommandEvent& event); + void OnButtonOK(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + void OnClose(wxCloseEvent& event); + +public: + /** Constructor */ + CYourAddressDialog(wxWindow* parent); + CYourAddressDialog(wxWindow* parent, const string& strInitSelected); + + // Custom + wxString GetAddress(); +}; + + + +class CAddressBookDialog : public CAddressBookDialogBase +{ +protected: + // Event handlers + void OnListEndLabelEdit(wxListEvent& event); + void OnListItemSelected(wxListEvent& event); + void OnListItemActivated(wxListEvent& event); + void OnButtonEdit(wxCommandEvent& event); + void OnButtonDelete(wxCommandEvent& event); + void OnButtonNew(wxCommandEvent& event); + void OnButtonCopy(wxCommandEvent& event); + void OnButtonOK(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + void OnClose(wxCloseEvent& event); + +public: + /** Constructor */ + CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, bool fSendingIn); + + // Custom + bool fSending; + wxString GetAddress(); + bool CheckIfMine(const string& strAddress, const string& strTitle); +}; + + + +class CProductsDialog : public CProductsDialogBase +{ +protected: + // Event handlers + void OnKeyDown(wxKeyEvent& event) { HandleCtrlA(event); } + void OnCombobox(wxCommandEvent& event); + void OnButtonSearch(wxCommandEvent& event); + void OnListItemActivated(wxListEvent& event); + +public: + /** Constructor */ + CProductsDialog(wxWindow* parent); + + // Custom + vector m_vProduct; +}; + + + +class CEditProductDialog : public CEditProductDialogBase +{ +protected: + // Event handlers + void OnKeyDown(wxKeyEvent& event) { HandleCtrlA(event); } + void OnButtonDel0(wxCommandEvent& event); + void OnButtonDel1(wxCommandEvent& event); + void OnButtonDel2(wxCommandEvent& event); + void OnButtonDel3(wxCommandEvent& event); + void OnButtonDel4(wxCommandEvent& event); + void OnButtonDel5(wxCommandEvent& event); + void OnButtonDel6(wxCommandEvent& event); + void OnButtonDel7(wxCommandEvent& event); + void OnButtonDel8(wxCommandEvent& event); + void OnButtonDel9(wxCommandEvent& event); + void OnButtonDel10(wxCommandEvent& event); + void OnButtonDel11(wxCommandEvent& event); + void OnButtonDel12(wxCommandEvent& event); + void OnButtonDel13(wxCommandEvent& event); + void OnButtonDel14(wxCommandEvent& event); + void OnButtonDel15(wxCommandEvent& event); + void OnButtonDel16(wxCommandEvent& event); + void OnButtonDel17(wxCommandEvent& event); + void OnButtonDel18(wxCommandEvent& event); + void OnButtonDel19(wxCommandEvent& event); + void OnButtonAddField(wxCommandEvent& event); + void OnButtonSend(wxCommandEvent& event); + void OnButtonPreview(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + +public: + /** Constructor */ + CEditProductDialog(wxWindow* parent); + + // Custom + enum { FIELDS_MAX = 20 }; + wxTextCtrl* m_textCtrlLabel[FIELDS_MAX]; + wxTextCtrl* m_textCtrlField[FIELDS_MAX]; + wxButton* m_buttonDel[FIELDS_MAX]; + + void LayoutAll(); + void ShowLine(int i, bool fShow=true); + void OnButtonDel(wxCommandEvent& event, int n); + void SetProduct(const CProduct& productIn); + void GetProduct(CProduct& product); + +}; + + + +class CViewProductDialog : public CViewProductDialogBase +{ +protected: + // Event handlers + void OnButtonSubmitForm(wxCommandEvent& event); + void OnButtonCancelForm(wxCommandEvent& event); + void OnButtonBack(wxCommandEvent& event); + void OnButtonNext(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + +public: + /** Constructor */ + CViewProductDialog(wxWindow* parent, const CProduct& productIn); + ~CViewProductDialog(); + + // Custom + CProduct product; + enum { FIELDS_MAX = 20 }; + wxStaticText* m_staticTextLabel[FIELDS_MAX]; + wxTextCtrl* m_textCtrlField[FIELDS_MAX]; + wxChoice* m_choiceField[FIELDS_MAX]; + + void GetOrder(CWalletTx& order); + void UpdateProductDisplay(bool fDetails); + void OnReply1(wxCommandEvent& event); +}; + + + +class CViewOrderDialog : public CViewOrderDialogBase +{ +protected: + // Event handlers + void OnButtonOK(wxCommandEvent& event); + +public: + /** Constructor */ + CViewOrderDialog(wxWindow* parent, CWalletTx order, bool fReceived); + + // Custom + bool fReceived; +}; + + + +class CEditReviewDialog : public CEditReviewDialogBase +{ +protected: + // Event handlers + void OnKeyDown(wxKeyEvent& event) { HandleCtrlA(event); } + void OnButtonSubmit(wxCommandEvent& event); + void OnButtonCancel(wxCommandEvent& event); + +public: + /** Constructor */ + CEditReviewDialog(wxWindow* parent); + + // Custom + void GetReview(CReview& review); +}; + + + +class CGetTextFromUserDialog : public CGetTextFromUserDialogBase +{ +protected: + // Event handlers + void OnButtonOK(wxCommandEvent& event) { EndModal(true); } + void OnButtonCancel(wxCommandEvent& event) { EndModal(false); } + void OnClose(wxCloseEvent& event) { EndModal(false); } + + void OnKeyDown(wxKeyEvent& event) + { + if (event.GetKeyCode() == '\r' || event.GetKeyCode() == WXK_NUMPAD_ENTER) + EndModal(true); + else + HandleCtrlA(event); + } + +public: + /** Constructor */ + CGetTextFromUserDialog(wxWindow* parent, + const string& strCaption, + const string& strMessage1, + const string& strValue1="", + const string& strMessage2="", + const string& strValue2="") : CGetTextFromUserDialogBase(parent, wxID_ANY, strCaption) + { + m_staticTextMessage1->SetLabel(strMessage1); + m_textCtrl1->SetValue(strValue1); + if (!strMessage2.empty()) + { + m_staticTextMessage2->Show(true); + m_staticTextMessage2->SetLabel(strMessage2); + m_textCtrl2->Show(true); + m_textCtrl2->SetValue(strValue2); + SetSize(wxDefaultCoord, 180); + } + } + + // Custom + string GetValue() { return (string)m_textCtrl1->GetValue(); } + string GetValue1() { return (string)m_textCtrl1->GetValue(); } + string GetValue2() { return (string)m_textCtrl2->GetValue(); } +}; + + + + + diff --git a/ui.rc b/ui.rc new file mode 100644 index 000000000..95258c7d5 --- /dev/null +++ b/ui.rc @@ -0,0 +1,14 @@ +bitcoin ICON "rc/bitcoin.ico" + +#include "wx/msw/wx.rc" + +check ICON "rc/check.ico" +send16 BITMAP "rc/send16.bmp" +send16mask BITMAP "rc/send16mask.bmp" +send16masknoshadow BITMAP "rc/send16masknoshadow.bmp" +send20 BITMAP "rc/send20.bmp" +send20mask BITMAP "rc/send20mask.bmp" +addressbook16 BITMAP "rc/addressbook16.bmp" +addressbook16mask BITMAP "rc/addressbook16mask.bmp" +addressbook20 BITMAP "rc/addressbook20.bmp" +addressbook20mask BITMAP "rc/addressbook20mask.bmp" diff --git a/uibase.cpp b/uibase.cpp new file mode 100644 index 000000000..2972e9af3 --- /dev/null +++ b/uibase.cpp @@ -0,0 +1,1825 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 16 2008) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "uibase.h" + +/////////////////////////////////////////////////////////////////////////// + +CMainFrameBase::CMainFrameBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + + m_menubar = new wxMenuBar(0); + m_menubar->SetBackgroundColour(wxColour(240, 240, 240)); + + m_menuFile = new wxMenu(); + wxMenuItem* m_menuFileExit; + m_menuFileExit = new wxMenuItem(m_menuFile, wxID_ANY, wxString(wxT("E&xit")) , wxEmptyString, wxITEM_NORMAL); + m_menuFile->Append(m_menuFileExit); + + m_menubar->Append(m_menuFile, wxT("&File")); + + m_menuOptions = new wxMenu(); + wxMenuItem* m_menuOptionsGenerateBitcoins; + m_menuOptionsGenerateBitcoins = new wxMenuItem(m_menuOptions, wxID_OPTIONSGENERATEBITCOINS, wxString(wxT("&Generate Coins")) , wxEmptyString, wxITEM_CHECK); + m_menuOptions->Append(m_menuOptionsGenerateBitcoins); + + wxMenuItem* m_menuChangeYourAddress; + m_menuChangeYourAddress = new wxMenuItem(m_menuOptions, wxID_ANY, wxString(wxT("&Change Your Address...")) , wxEmptyString, wxITEM_NORMAL); + m_menuOptions->Append(m_menuChangeYourAddress); + + wxMenuItem* m_menuOptionsOptions; + m_menuOptionsOptions = new wxMenuItem(m_menuOptions, wxID_ANY, wxString(wxT("&Options...")) , wxEmptyString, wxITEM_NORMAL); + m_menuOptions->Append(m_menuOptionsOptions); + + m_menubar->Append(m_menuOptions, wxT("&Options")); + + m_menuHelp = new wxMenu(); + wxMenuItem* m_menuHelpAbout; + m_menuHelpAbout = new wxMenuItem(m_menuHelp, wxID_ANY, wxString(wxT("&About...")) , wxEmptyString, wxITEM_NORMAL); + m_menuHelp->Append(m_menuHelpAbout); + + m_menubar->Append(m_menuHelp, wxT("&Help")); + + this->SetMenuBar(m_menubar); + + m_toolBar = this->CreateToolBar(wxTB_FLAT|wxTB_HORZ_TEXT, wxID_ANY); + m_toolBar->SetToolBitmapSize(wxSize(20,20)); + m_toolBar->SetToolSeparation(1); + m_toolBar->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString)); + + m_toolBar->AddTool(wxID_BUTTONSEND, wxT("&Send Coins"), wxBitmap(wxT("send20"), wxBITMAP_TYPE_RESOURCE), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString); + m_toolBar->AddTool(wxID_BUTTONRECEIVE, wxT("&Address Book"), wxBitmap(wxT("addressbook20"), wxBITMAP_TYPE_RESOURCE), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString); + m_toolBar->Realize(); + + m_statusBar = this->CreateStatusBar(1, wxST_SIZEGRIP, wxID_ANY); + m_statusBar->SetBackgroundColour(wxColour(240, 240, 240)); + + wxBoxSizer* bSizer2; + bSizer2 = new wxBoxSizer(wxVERTICAL); + + + bSizer2->Add(0, 2, 0, wxEXPAND, 5); + + wxBoxSizer* bSizer85; + bSizer85 = new wxBoxSizer(wxHORIZONTAL); + + m_staticText32 = new wxStaticText(this, wxID_ANY, wxT("Your Bitcoin Address:"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText32->Wrap(-1); + bSizer85->Add(m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5); + + m_textCtrlAddress = new wxTextCtrl(this, wxID_TEXTCTRLADDRESS, wxEmptyString, wxDefaultPosition, wxSize(250,-1), wxTE_READONLY); + m_textCtrlAddress->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENU)); + + bSizer85->Add(m_textCtrlAddress, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_buttonCopy = new wxButton(this, wxID_BUTTONCOPY, wxT("&Copy to Clipboard"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + bSizer85->Add(m_buttonCopy, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5); + + m_button91 = new wxButton(this, wxID_BUTTONCHANGE, wxT("C&hange..."), wxDefaultPosition, wxDefaultSize, 0); + m_button91->Hide(); + + bSizer85->Add(m_button91, 0, wxRIGHT, 5); + + + bSizer85->Add(0, 0, 0, wxEXPAND, 5); + + bSizer2->Add(bSizer85, 0, wxEXPAND|wxRIGHT|wxLEFT, 5); + + wxBoxSizer* bSizer3; + bSizer3 = new wxBoxSizer(wxHORIZONTAL); + + m_panel14 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + wxBoxSizer* bSizer66; + bSizer66 = new wxBoxSizer(wxHORIZONTAL); + + m_staticText41 = new wxStaticText(m_panel14, wxID_ANY, wxT("Balance:"), wxDefaultPosition, wxSize(-1,15), 0); + m_staticText41->Wrap(-1); + bSizer66->Add(m_staticText41, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5); + + m_staticTextBalance = new wxStaticText(m_panel14, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(120,15), wxALIGN_RIGHT|wxST_NO_AUTORESIZE); + m_staticTextBalance->Wrap(-1); + m_staticTextBalance->SetFont(wxFont(8, 70, 90, 90, false, wxEmptyString)); + m_staticTextBalance->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + bSizer66->Add(m_staticTextBalance, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + m_panel14->SetSizer(bSizer66); + m_panel14->Layout(); + bSizer66->Fit(m_panel14); + bSizer3->Add(m_panel14, 1, wxEXPAND|wxALIGN_BOTTOM|wxALL, 5); + + + bSizer3->Add(0, 0, 0, wxEXPAND, 5); + + wxString m_choiceFilterChoices[] = { wxT(" All"), wxT(" Sent"), wxT(" Received"), wxT(" In Progress") }; + int m_choiceFilterNChoices = sizeof(m_choiceFilterChoices) / sizeof(wxString); + m_choiceFilter = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(110,-1), m_choiceFilterNChoices, m_choiceFilterChoices, 0); + m_choiceFilter->SetSelection(0); + m_choiceFilter->Hide(); + + bSizer3->Add(m_choiceFilter, 0, wxALIGN_BOTTOM|wxTOP|wxRIGHT|wxLEFT, 5); + + bSizer2->Add(bSizer3, 0, wxEXPAND, 5); + + m_notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); + m_panel7 = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + wxBoxSizer* bSizer157; + bSizer157 = new wxBoxSizer(wxVERTICAL); + + m_listCtrl = new wxListCtrl(m_panel7, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_DESCENDING|wxALWAYS_SHOW_SB); + bSizer157->Add(m_listCtrl, 1, wxEXPAND|wxALL, 5); + + m_panel7->SetSizer(bSizer157); + m_panel7->Layout(); + bSizer157->Fit(m_panel7); + m_notebook->AddPage(m_panel7, wxT("All Transactions"), false); + + bSizer2->Add(m_notebook, 1, wxEXPAND, 5); + + wxBoxSizer* bSizer_TabsForFutureUse; + bSizer_TabsForFutureUse = new wxBoxSizer(wxVERTICAL); + + m_panel9 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_panel9->Hide(); + + wxBoxSizer* bSizer159; + bSizer159 = new wxBoxSizer(wxVERTICAL); + + m_listCtrlEscrows = new wxListCtrl(m_panel9, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT); + bSizer159->Add(m_listCtrlEscrows, 1, wxALL|wxEXPAND, 5); + + m_panel9->SetSizer(bSizer159); + m_panel9->Layout(); + bSizer159->Fit(m_panel9); + bSizer_TabsForFutureUse->Add(m_panel9, 1, wxEXPAND | wxALL, 5); + + m_panel8 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_panel8->Hide(); + + wxBoxSizer* bSizer158; + bSizer158 = new wxBoxSizer(wxVERTICAL); + + m_listCtrlOrdersSent = new wxListCtrl(m_panel8, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT); + bSizer158->Add(m_listCtrlOrdersSent, 1, wxALL|wxEXPAND, 5); + + m_panel8->SetSizer(bSizer158); + m_panel8->Layout(); + bSizer158->Fit(m_panel8); + bSizer_TabsForFutureUse->Add(m_panel8, 1, wxEXPAND | wxALL, 5); + + m_panel10 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_panel10->Hide(); + + wxBoxSizer* bSizer160; + bSizer160 = new wxBoxSizer(wxVERTICAL); + + m_listCtrlProductsSent = new wxListCtrl(m_panel10, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT); + bSizer160->Add(m_listCtrlProductsSent, 1, wxALL|wxEXPAND, 5); + + m_panel10->SetSizer(bSizer160); + m_panel10->Layout(); + bSizer160->Fit(m_panel10); + bSizer_TabsForFutureUse->Add(m_panel10, 1, wxEXPAND | wxALL, 5); + + m_panel11 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_panel11->Hide(); + + wxBoxSizer* bSizer161; + bSizer161 = new wxBoxSizer(wxVERTICAL); + + m_listCtrlOrdersReceived = new wxListCtrl(m_panel11, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT); + bSizer161->Add(m_listCtrlOrdersReceived, 1, wxALL|wxEXPAND, 5); + + m_panel11->SetSizer(bSizer161); + m_panel11->Layout(); + bSizer161->Fit(m_panel11); + bSizer_TabsForFutureUse->Add(m_panel11, 1, wxEXPAND | wxALL, 5); + + bSizer2->Add(bSizer_TabsForFutureUse, 1, wxEXPAND, 5); + + this->SetSizer(bSizer2); + this->Layout(); + + // Connect Events + this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CMainFrameBase::OnClose)); + this->Connect(wxEVT_IDLE, wxIdleEventHandler(CMainFrameBase::OnIdle)); + this->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_MOTION, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Connect(wxEVT_PAINT, wxPaintEventHandler(CMainFrameBase::OnPaint)); + this->Connect(m_menuFileExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuFileExit)); + this->Connect(m_menuOptionsGenerateBitcoins->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuOptionsGenerate)); + this->Connect(m_menuChangeYourAddress->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuOptionsChangeYourAddress)); + this->Connect(m_menuOptionsOptions->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuOptionsOptions)); + this->Connect(m_menuHelpAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuHelpAbout)); + this->Connect(wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonSend)); + this->Connect(wxID_BUTTONRECEIVE, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonAddressBook)); + m_textCtrlAddress->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CMainFrameBase::OnKeyDown), NULL, this); + m_textCtrlAddress->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_MOTION, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(CMainFrameBase::OnSetFocusAddress), NULL, this); + m_buttonCopy->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonCopy), NULL, this); + m_button91->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonChange), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler(CMainFrameBase::OnListColBeginDrag), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedAllTransactions), NULL, this); + m_listCtrl->Connect(wxEVT_PAINT, wxPaintEventHandler(CMainFrameBase::OnPaintListCtrl), NULL, this); + m_listCtrlOrdersSent->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedOrdersSent), NULL, this); + m_listCtrlProductsSent->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedProductsSent), NULL, this); + m_listCtrlOrdersReceived->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedOrdersReceived), NULL, this); +} + +CMainFrameBase::~CMainFrameBase() +{ + // Disconnect Events + this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CMainFrameBase::OnClose)); + this->Disconnect(wxEVT_IDLE, wxIdleEventHandler(CMainFrameBase::OnIdle)); + this->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_MIDDLE_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_RIGHT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_MOTION, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(CMainFrameBase::OnMouseEvents)); + this->Disconnect(wxEVT_PAINT, wxPaintEventHandler(CMainFrameBase::OnPaint)); + this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuFileExit)); + this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuOptionsGenerate)); + this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuOptionsChangeYourAddress)); + this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuOptionsOptions)); + this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(CMainFrameBase::OnMenuHelpAbout)); + this->Disconnect(wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonSend)); + this->Disconnect(wxID_BUTTONRECEIVE, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonAddressBook)); + m_textCtrlAddress->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CMainFrameBase::OnKeyDown), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_MIDDLE_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_RIGHT_UP, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_MOTION, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(CMainFrameBase::OnMouseEventsAddress), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(CMainFrameBase::OnSetFocusAddress), NULL, this); + m_buttonCopy->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonCopy), NULL, this); + m_button91->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CMainFrameBase::OnButtonChange), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler(CMainFrameBase::OnListColBeginDrag), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedAllTransactions), NULL, this); + m_listCtrl->Disconnect(wxEVT_PAINT, wxPaintEventHandler(CMainFrameBase::OnPaintListCtrl), NULL, this); + m_listCtrlOrdersSent->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedOrdersSent), NULL, this); + m_listCtrlProductsSent->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedProductsSent), NULL, this); + m_listCtrlOrdersReceived->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CMainFrameBase::OnListItemActivatedOrdersReceived), NULL, this); +} + +CTxDetailsDialogBase::CTxDetailsDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer64; + bSizer64 = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* bSizer66; + bSizer66 = new wxBoxSizer(wxVERTICAL); + + m_htmlWin = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); + bSizer66->Add(m_htmlWin, 1, wxALL|wxEXPAND, 5); + + bSizer64->Add(bSizer66, 1, wxEXPAND, 5); + + wxBoxSizer* bSizer65; + bSizer65 = new wxBoxSizer(wxVERTICAL); + + m_buttonOK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxSize(85,25), 0); + bSizer65->Add(m_buttonOK, 0, wxALL, 5); + + bSizer64->Add(bSizer65, 0, wxALIGN_RIGHT, 5); + + this->SetSizer(bSizer64); + this->Layout(); + + // Connect Events + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CTxDetailsDialogBase::OnButtonOK), NULL, this); +} + +CTxDetailsDialogBase::~CTxDetailsDialogBase() +{ + // Disconnect Events + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CTxDetailsDialogBase::OnButtonOK), NULL, this); +} + +COptionsDialogBase::COptionsDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer55; + bSizer55 = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* bSizer57; + bSizer57 = new wxBoxSizer(wxVERTICAL); + + + bSizer57->Add(0, 20, 0, wxEXPAND, 5); + + m_staticText32 = new wxStaticText(this, wxID_ANY, wxT("Optional transaction fee you give to the nodes that process your transactions."), wxDefaultPosition, wxDefaultSize, 0); + m_staticText32->Wrap(-1); + bSizer57->Add(m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + wxBoxSizer* bSizer56; + bSizer56 = new wxBoxSizer(wxHORIZONTAL); + + m_staticText31 = new wxStaticText(this, wxID_ANY, wxT("Transaction fee:"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText31->Wrap(-1); + bSizer56->Add(m_staticText31, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5); + + m_textCtrlTransactionFee = new wxTextCtrl(this, wxID_TRANSACTIONFEE, wxEmptyString, wxDefaultPosition, wxSize(70,-1), 0); + bSizer56->Add(m_textCtrlTransactionFee, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + bSizer57->Add(bSizer56, 0, wxEXPAND, 5); + + bSizer55->Add(bSizer57, 1, wxEXPAND|wxLEFT, 5); + + wxBoxSizer* bSizer58; + bSizer58 = new wxBoxSizer(wxHORIZONTAL); + + m_buttonOK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxSize(85,25), 0); + bSizer58->Add(m_buttonOK, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer58->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer55->Add(bSizer58, 0, wxALIGN_RIGHT, 5); + + this->SetSizer(bSizer55); + this->Layout(); + + // Connect Events + m_textCtrlTransactionFee->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(COptionsDialogBase::OnKillFocusTransactionFee), NULL, this); + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(COptionsDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(COptionsDialogBase::OnButtonCancel), NULL, this); +} + +COptionsDialogBase::~COptionsDialogBase() +{ + // Disconnect Events + m_textCtrlTransactionFee->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(COptionsDialogBase::OnKillFocusTransactionFee), NULL, this); + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(COptionsDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(COptionsDialogBase::OnButtonCancel), NULL, this); +} + +CAboutDialogBase::CAboutDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer60; + bSizer60 = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* bSizer62; + bSizer62 = new wxBoxSizer(wxHORIZONTAL); + + + bSizer62->Add(60, 0, 0, wxEXPAND, 5); + + wxBoxSizer* bSizer63; + bSizer63 = new wxBoxSizer(wxVERTICAL); + + + bSizer63->Add(0, 50, 0, wxEXPAND, 5); + + wxBoxSizer* bSizer64; + bSizer64 = new wxBoxSizer(wxHORIZONTAL); + + m_staticText40 = new wxStaticText(this, wxID_ANY, wxT("Bitcoin "), wxDefaultPosition, wxDefaultSize, 0); + m_staticText40->Wrap(-1); + m_staticText40->SetFont(wxFont(10, 74, 90, 92, false, wxT("Tahoma"))); + + bSizer64->Add(m_staticText40, 0, wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxLEFT, 5); + + m_staticTextVersion = new wxStaticText(this, wxID_ANY, wxT("version"), wxDefaultPosition, wxDefaultSize, 0); + m_staticTextVersion->Wrap(-1); + m_staticTextVersion->SetFont(wxFont(10, 74, 90, 90, false, wxT("Tahoma"))); + + bSizer64->Add(m_staticTextVersion, 0, wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxRIGHT, 5); + + bSizer63->Add(bSizer64, 0, wxEXPAND, 5); + + + bSizer63->Add(0, 4, 0, wxEXPAND, 5); + + m_staticTextMain = new wxStaticText(this, wxID_ANY, wxT("Copyright © 2009 Satoshi Nakamoto.\n\nThis is experimental software. Do not rely on it for actual financial transactions.\n\nDistributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php.\n\nThis product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com)."), wxDefaultPosition, wxDefaultSize, 0); + m_staticTextMain->Wrap(400); + bSizer63->Add(m_staticTextMain, 0, wxALL, 5); + + + bSizer63->Add(0, 0, 1, wxEXPAND, 5); + + bSizer62->Add(bSizer63, 1, wxEXPAND, 5); + + bSizer60->Add(bSizer62, 1, wxEXPAND, 5); + + wxBoxSizer* bSizer61; + bSizer61 = new wxBoxSizer(wxHORIZONTAL); + + + bSizer61->Add(0, 0, 1, wxEXPAND, 5); + + m_buttonOK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxSize(85,25), 0); + bSizer61->Add(m_buttonOK, 0, wxALL, 5); + + bSizer60->Add(bSizer61, 0, wxALIGN_RIGHT|wxEXPAND, 5); + + this->SetSizer(bSizer60); + this->Layout(); + + // Connect Events + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAboutDialogBase::OnButtonOK), NULL, this); +} + +CAboutDialogBase::~CAboutDialogBase() +{ + // Disconnect Events + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAboutDialogBase::OnButtonOK), NULL, this); +} + +CSendDialogBase::CSendDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer21; + bSizer21 = new wxBoxSizer(wxVERTICAL); + + + bSizer21->Add(0, 5, 0, wxEXPAND, 5); + + wxFlexGridSizer* fgSizer1; + fgSizer1 = new wxFlexGridSizer(3, 2, 0, 0); + fgSizer1->AddGrowableCol(1); + fgSizer1->SetFlexibleDirection(wxBOTH); + fgSizer1->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + + + fgSizer1->Add(0, 0, 0, wxEXPAND, 5); + + m_staticText14 = new wxStaticText(this, wxID_ANY, wxT("Enter the recipient's IP address (e.g. 123.45.6.7) for online transfer with comments and confirmation, \nor Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) if recipient is not online."), wxDefaultPosition, wxDefaultSize, 0); + m_staticText14->Wrap(-1); + fgSizer1->Add(m_staticText14, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + wxBoxSizer* bSizer47; + bSizer47 = new wxBoxSizer(wxHORIZONTAL); + + bSizer47->SetMinSize(wxSize(70,-1)); + + bSizer47->Add(0, 0, 1, wxEXPAND, 5); + + m_bitmapCheckMark = new wxStaticBitmap(this, wxID_ANY, wxICON(check), wxDefaultPosition, wxSize(16,16), 0); + bSizer47->Add(m_bitmapCheckMark, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_staticText36 = new wxStaticText(this, wxID_ANY, wxT("Pay &To:"), wxDefaultPosition, wxSize(-1,-1), wxALIGN_RIGHT); + m_staticText36->Wrap(-1); + bSizer47->Add(m_staticText36, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5); + + fgSizer1->Add(bSizer47, 1, wxEXPAND|wxLEFT, 5); + + wxBoxSizer* bSizer19; + bSizer19 = new wxBoxSizer(wxHORIZONTAL); + + m_textCtrlAddress = new wxTextCtrl(this, wxID_TEXTCTRLPAYTO, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + bSizer19->Add(m_textCtrlAddress, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + m_buttonPaste = new wxButton(this, wxID_BUTTONPASTE, wxT("&Paste"), wxDefaultPosition, wxSize(-1,-1), wxBU_EXACTFIT); + bSizer19->Add(m_buttonPaste, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5); + + m_buttonAddress = new wxButton(this, wxID_BUTTONADDRESSBOOK, wxT(" Address &Book..."), wxDefaultPosition, wxDefaultSize, 0); + bSizer19->Add(m_buttonAddress, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5); + + fgSizer1->Add(bSizer19, 1, wxEXPAND|wxRIGHT, 5); + + m_staticText19 = new wxStaticText(this, wxID_ANY, wxT("&Amount:"), wxDefaultPosition, wxSize(-1,-1), wxALIGN_RIGHT); + m_staticText19->Wrap(-1); + fgSizer1->Add(m_staticText19, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT|wxALIGN_RIGHT, 5); + + m_textCtrlAmount = new wxTextCtrl(this, wxID_TEXTCTRLAMOUNT, wxEmptyString, wxDefaultPosition, wxSize(145,-1), 0); + m_textCtrlAmount->SetMaxLength(20); + m_textCtrlAmount->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString)); + + fgSizer1->Add(m_textCtrlAmount, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + m_staticText20 = new wxStaticText(this, wxID_ANY, wxT("T&ransfer:"), wxDefaultPosition, wxSize(-1,-1), wxALIGN_RIGHT); + m_staticText20->Wrap(-1); + m_staticText20->Hide(); + + fgSizer1->Add(m_staticText20, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5); + + wxString m_choiceTransferTypeChoices[] = { wxT(" Standard") }; + int m_choiceTransferTypeNChoices = sizeof(m_choiceTransferTypeChoices) / sizeof(wxString); + m_choiceTransferType = new wxChoice(this, wxID_CHOICETRANSFERTYPE, wxDefaultPosition, wxDefaultSize, m_choiceTransferTypeNChoices, m_choiceTransferTypeChoices, 0); + m_choiceTransferType->SetSelection(0); + m_choiceTransferType->Hide(); + + fgSizer1->Add(m_choiceTransferType, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + + fgSizer1->Add(0, 3, 0, wxEXPAND, 5); + + + fgSizer1->Add(0, 0, 0, wxEXPAND, 5); + + bSizer21->Add(fgSizer1, 0, wxEXPAND|wxLEFT, 5); + + wxBoxSizer* bSizer672; + bSizer672 = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer* bSizer681; + bSizer681 = new wxBoxSizer(wxVERTICAL); + + m_staticTextFrom = new wxStaticText(this, wxID_ANY, wxT("&From:"), wxDefaultPosition, wxDefaultSize, 0); + m_staticTextFrom->Wrap(-1); + bSizer681->Add(m_staticTextFrom, 0, wxBOTTOM|wxLEFT, 5); + + m_textCtrlFrom = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + bSizer681->Add(m_textCtrlFrom, 0, wxLEFT|wxEXPAND, 5); + + bSizer672->Add(bSizer681, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5); + + bSizer21->Add(bSizer672, 0, wxEXPAND, 5); + + wxBoxSizer* bSizer67; + bSizer67 = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer* bSizer68; + bSizer68 = new wxBoxSizer(wxVERTICAL); + + m_staticTextMessage = new wxStaticText(this, wxID_ANY, wxT("&Message:"), wxDefaultPosition, wxDefaultSize, 0); + m_staticTextMessage->Wrap(-1); + bSizer68->Add(m_staticTextMessage, 0, wxTOP|wxBOTTOM|wxLEFT, 5); + + m_textCtrlMessage = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + bSizer68->Add(m_textCtrlMessage, 1, wxEXPAND|wxLEFT, 5); + + bSizer67->Add(bSizer68, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5); + + bSizer21->Add(bSizer67, 1, wxEXPAND, 5); + + wxBoxSizer* bSizer23; + bSizer23 = new wxBoxSizer(wxHORIZONTAL); + + + bSizer23->Add(0, 0, 1, wxEXPAND, 5); + + m_buttonSend = new wxButton(this, wxID_BUTTONSEND, wxT("&Send"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonSend->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString)); + m_buttonSend->SetMinSize(wxSize(85,25)); + + bSizer23->Add(m_buttonSend, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer23->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer21->Add(bSizer23, 0, wxEXPAND, 5); + + this->SetSizer(bSizer21); + this->Layout(); + + // Connect Events + m_textCtrlAddress->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_textCtrlAddress->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(CSendDialogBase::OnTextAddress), NULL, this); + m_buttonPaste->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonPaste), NULL, this); + m_buttonAddress->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonAddressBook), NULL, this); + m_textCtrlAmount->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_textCtrlAmount->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(CSendDialogBase::OnKillFocusAmount), NULL, this); + m_textCtrlFrom->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_textCtrlMessage->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_buttonSend->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonSend), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonCancel), NULL, this); +} + +CSendDialogBase::~CSendDialogBase() +{ + // Disconnect Events + m_textCtrlAddress->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_textCtrlAddress->Disconnect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(CSendDialogBase::OnTextAddress), NULL, this); + m_buttonPaste->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonPaste), NULL, this); + m_buttonAddress->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonAddressBook), NULL, this); + m_textCtrlAmount->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_textCtrlAmount->Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(CSendDialogBase::OnKillFocusAmount), NULL, this); + m_textCtrlFrom->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_textCtrlMessage->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CSendDialogBase::OnKeyDown), NULL, this); + m_buttonSend->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonSend), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendDialogBase::OnButtonCancel), NULL, this); +} + +CSendingDialogBase::CSendingDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer68; + bSizer68 = new wxBoxSizer(wxVERTICAL); + + m_staticTextSending = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,14), 0); + m_staticTextSending->Wrap(-1); + bSizer68->Add(m_staticTextSending, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 8); + + m_textCtrlStatus = new wxTextCtrl(this, wxID_ANY, wxT("\n\nConnecting..."), wxDefaultPosition, wxDefaultSize, wxTE_CENTRE|wxTE_MULTILINE|wxTE_NO_VSCROLL|wxTE_READONLY|wxNO_BORDER); + m_textCtrlStatus->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + + bSizer68->Add(m_textCtrlStatus, 1, wxEXPAND|wxRIGHT|wxLEFT, 10); + + wxBoxSizer* bSizer69; + bSizer69 = new wxBoxSizer(wxHORIZONTAL); + + + bSizer69->Add(0, 0, 1, wxEXPAND, 5); + + m_buttonOK = new wxButton(this, wxID_ANY, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonOK->Enable(false); + m_buttonOK->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonOK, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer68->Add(bSizer69, 0, wxEXPAND, 5); + + this->SetSizer(bSizer68); + this->Layout(); + + // Connect Events + this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CSendingDialogBase::OnClose)); + this->Connect(wxEVT_PAINT, wxPaintEventHandler(CSendingDialogBase::OnPaint)); + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendingDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendingDialogBase::OnButtonCancel), NULL, this); +} + +CSendingDialogBase::~CSendingDialogBase() +{ + // Disconnect Events + this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CSendingDialogBase::OnClose)); + this->Disconnect(wxEVT_PAINT, wxPaintEventHandler(CSendingDialogBase::OnPaint)); + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendingDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CSendingDialogBase::OnButtonCancel), NULL, this); +} + +CYourAddressDialogBase::CYourAddressDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer68; + bSizer68 = new wxBoxSizer(wxVERTICAL); + + + bSizer68->Add(0, 5, 0, wxEXPAND, 5); + + m_staticText45 = new wxStaticText(this, wxID_ANY, wxT("These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window."), wxDefaultPosition, wxDefaultSize, 0); + m_staticText45->Wrap(590); + bSizer68->Add(m_staticText45, 0, wxALL, 5); + + m_listCtrl = new wxListCtrl(this, wxID_LISTCTRL, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_ASCENDING); + bSizer68->Add(m_listCtrl, 1, wxALL|wxEXPAND, 5); + + wxBoxSizer* bSizer69; + bSizer69 = new wxBoxSizer(wxHORIZONTAL); + + + bSizer69->Add(0, 0, 1, wxEXPAND, 5); + + m_buttonRename = new wxButton(this, wxID_BUTTONRENAME, wxT("&Edit..."), wxDefaultPosition, wxDefaultSize, 0); + m_buttonRename->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonRename, 0, wxALL, 5); + + m_buttonNew = new wxButton(this, wxID_BUTTONNEW, wxT("&New Address..."), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonNew->SetMinSize(wxSize(110,25)); + + bSizer69->Add(m_buttonNew, 0, wxALL, 5); + + m_buttonCopy = new wxButton(this, wxID_BUTTONCOPY, wxT("&Copy to Clipboard"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonCopy->SetMinSize(wxSize(120,25)); + + bSizer69->Add(m_buttonCopy, 0, wxALL, 5); + + m_buttonOK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonOK->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonOK, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonCancel->Hide(); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer68->Add(bSizer69, 0, wxEXPAND, 5); + + this->SetSizer(bSizer68); + this->Layout(); + + // Connect Events + this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CYourAddressDialogBase::OnClose)); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler(CYourAddressDialogBase::OnListEndLabelEdit), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CYourAddressDialogBase::OnListItemActivated), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(CYourAddressDialogBase::OnListItemSelected), NULL, this); + m_buttonRename->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonRename), NULL, this); + m_buttonNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonNew), NULL, this); + m_buttonCopy->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonCopy), NULL, this); + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonCancel), NULL, this); +} + +CYourAddressDialogBase::~CYourAddressDialogBase() +{ + // Disconnect Events + this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CYourAddressDialogBase::OnClose)); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler(CYourAddressDialogBase::OnListEndLabelEdit), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CYourAddressDialogBase::OnListItemActivated), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(CYourAddressDialogBase::OnListItemSelected), NULL, this); + m_buttonRename->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonRename), NULL, this); + m_buttonNew->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonNew), NULL, this); + m_buttonCopy->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonCopy), NULL, this); + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CYourAddressDialogBase::OnButtonCancel), NULL, this); +} + +CAddressBookDialogBase::CAddressBookDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer68; + bSizer68 = new wxBoxSizer(wxVERTICAL); + + + bSizer68->Add(0, 5, 0, wxEXPAND, 5); + + m_staticText55 = new wxStaticText(this, wxID_ANY, wxT("Bitcoin Address"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText55->Wrap(-1); + m_staticText55->Hide(); + + bSizer68->Add(m_staticText55, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + m_listCtrl = new wxListCtrl(this, wxID_LISTCTRL, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_ASCENDING); + bSizer68->Add(m_listCtrl, 1, wxALL|wxEXPAND, 5); + + wxBoxSizer* bSizer69; + bSizer69 = new wxBoxSizer(wxHORIZONTAL); + + + bSizer69->Add(0, 0, 1, wxEXPAND, 5); + + m_buttonEdit = new wxButton(this, wxID_BUTTONEDIT, wxT("&Edit..."), wxDefaultPosition, wxDefaultSize, 0); + m_buttonEdit->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonEdit, 0, wxALL, 5); + + m_buttonNew = new wxButton(this, wxID_BUTTONNEW, wxT("&New Address..."), wxDefaultPosition, wxDefaultSize, 0); + m_buttonNew->SetMinSize(wxSize(110,25)); + + bSizer69->Add(m_buttonNew, 0, wxALL, 5); + + m_buttonDelete = new wxButton(this, wxID_BUTTONDELETE, wxT("&Delete"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonDelete->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonDelete, 0, wxALL, 5); + + m_buttonOK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonOK->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonOK, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer69->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer68->Add(bSizer69, 0, wxEXPAND, 5); + + this->SetSizer(bSizer68); + this->Layout(); + + // Connect Events + this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CAddressBookDialogBase::OnClose)); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler(CAddressBookDialogBase::OnListEndLabelEdit), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CAddressBookDialogBase::OnListItemActivated), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(CAddressBookDialogBase::OnListItemSelected), NULL, this); + m_buttonEdit->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonEdit), NULL, this); + m_buttonNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonNew), NULL, this); + m_buttonDelete->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonDelete), NULL, this); + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonCancel), NULL, this); +} + +CAddressBookDialogBase::~CAddressBookDialogBase() +{ + // Disconnect Events + this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CAddressBookDialogBase::OnClose)); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler(CAddressBookDialogBase::OnListEndLabelEdit), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CAddressBookDialogBase::OnListItemActivated), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(CAddressBookDialogBase::OnListItemSelected), NULL, this); + m_buttonEdit->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonEdit), NULL, this); + m_buttonNew->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonNew), NULL, this); + m_buttonDelete->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonDelete), NULL, this); + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CAddressBookDialogBase::OnButtonCancel), NULL, this); +} + +CProductsDialogBase::CProductsDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer22; + bSizer22 = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* bSizer23; + bSizer23 = new wxBoxSizer(wxHORIZONTAL); + + m_comboBoxCategory = new wxComboBox(this, wxID_ANY, wxT("(Any Category)"), wxDefaultPosition, wxSize(150,-1), 0, NULL, 0); + m_comboBoxCategory->Append(wxT("(Any Category)")); + bSizer23->Add(m_comboBoxCategory, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlSearch = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + bSizer23->Add(m_textCtrlSearch, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonSearch = new wxButton(this, wxID_ANY, wxT("&Search"), wxDefaultPosition, wxDefaultSize, 0); + bSizer23->Add(m_buttonSearch, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + bSizer22->Add(bSizer23, 0, wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT, 5); + + m_listCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT); + bSizer22->Add(m_listCtrl, 1, wxALL|wxEXPAND, 5); + + this->SetSizer(bSizer22); + this->Layout(); + + // Connect Events + m_comboBoxCategory->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(CProductsDialogBase::OnCombobox), NULL, this); + m_textCtrlSearch->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CProductsDialogBase::OnKeyDown), NULL, this); + m_buttonSearch->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CProductsDialogBase::OnButtonSearch), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CProductsDialogBase::OnListItemActivated), NULL, this); +} + +CProductsDialogBase::~CProductsDialogBase() +{ + // Disconnect Events + m_comboBoxCategory->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(CProductsDialogBase::OnCombobox), NULL, this); + m_textCtrlSearch->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CProductsDialogBase::OnKeyDown), NULL, this); + m_buttonSearch->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CProductsDialogBase::OnButtonSearch), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CProductsDialogBase::OnListItemActivated), NULL, this); +} + +CEditProductDialogBase::CEditProductDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENU)); + + wxBoxSizer* bSizer20; + bSizer20 = new wxBoxSizer(wxVERTICAL); + + m_scrolledWindow = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL); + m_scrolledWindow->SetScrollRate(5, 5); + m_scrolledWindow->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + wxBoxSizer* bSizer21; + bSizer21 = new wxBoxSizer(wxVERTICAL); + + wxFlexGridSizer* fgSizer8; + fgSizer8 = new wxFlexGridSizer(0, 2, 0, 0); + fgSizer8->AddGrowableCol(1); + fgSizer8->SetFlexibleDirection(wxBOTH); + fgSizer8->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + + m_staticText106 = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Category"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + m_staticText106->Wrap(-1); + fgSizer8->Add(m_staticText106, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5); + + m_comboBoxCategory = new wxComboBox(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0); + m_comboBoxCategory->SetMinSize(wxSize(180,-1)); + + fgSizer8->Add(m_comboBoxCategory, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_staticText108 = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Title"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + m_staticText108->Wrap(-1); + fgSizer8->Add(m_staticText108, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5); + + m_textCtrlTitle = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + fgSizer8->Add(m_textCtrlTitle, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5); + + m_staticText107 = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Price"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + m_staticText107->Wrap(-1); + fgSizer8->Add(m_staticText107, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5); + + m_textCtrlPrice = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlPrice->SetMinSize(wxSize(105,-1)); + + fgSizer8->Add(m_textCtrlPrice, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + bSizer21->Add(fgSizer8, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5); + + m_staticText22 = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Page 1: Description"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText22->Wrap(-1); + bSizer21->Add(m_staticText22, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + m_textCtrlDescription = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + m_textCtrlDescription->SetMinSize(wxSize(-1,170)); + + bSizer21->Add(m_textCtrlDescription, 0, wxALL|wxEXPAND, 5); + + m_staticText23 = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Page 2: Order Form"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText23->Wrap(-1); + bSizer21->Add(m_staticText23, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + m_textCtrlInstructions = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + m_textCtrlInstructions->SetMinSize(wxSize(-1,120)); + + bSizer21->Add(m_textCtrlInstructions, 0, wxEXPAND|wxALL, 5); + + fgSizer5 = new wxFlexGridSizer(0, 3, 0, 0); + fgSizer5->AddGrowableCol(1); + fgSizer5->SetFlexibleDirection(wxBOTH); + fgSizer5->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + + m_staticText24 = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Label"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText24->Wrap(-1); + fgSizer5->Add(m_staticText24, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5); + + m_staticText25 = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Comma separated list of choices, or leave blank for text field"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText25->Wrap(-1); + fgSizer5->Add(m_staticText25, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5); + + + fgSizer5->Add(0, 0, 1, wxEXPAND, 5); + + m_textCtrlLabel0 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel0->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel0, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField0 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField0, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel0 = new wxButton(m_scrolledWindow, wxID_DEL0, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel0, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlLabel1 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel1->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel1, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField1 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField1, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel1 = new wxButton(m_scrolledWindow, wxID_DEL1, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel1, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel2 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel2->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel2, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField2 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField2, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel2 = new wxButton(m_scrolledWindow, wxID_DEL2, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel2, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel3 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel3->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel3, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField3 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField3, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel3 = new wxButton(m_scrolledWindow, wxID_DEL3, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel3, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel4 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel4->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel4, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField4 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField4, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel4 = new wxButton(m_scrolledWindow, wxID_DEL4, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel4, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel5 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel5->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel5, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField5 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField5, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel5 = new wxButton(m_scrolledWindow, wxID_DEL5, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel5, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel6 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel6->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel6, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField6 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField6, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel6 = new wxButton(m_scrolledWindow, wxID_DEL6, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel6, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel7 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel7->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel7, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField7 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField7, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel7 = new wxButton(m_scrolledWindow, wxID_DEL7, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel7, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel8 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel8->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel8, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField8 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField8, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel8 = new wxButton(m_scrolledWindow, wxID_DEL8, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel8, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel9 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel9->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel9, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField9 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField9, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel9 = new wxButton(m_scrolledWindow, wxID_DEL9, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel9, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel10 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel10->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel10, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField10 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField10, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel10 = new wxButton(m_scrolledWindow, wxID_DEL10, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel10, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel11 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel11->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel11, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField11 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField11, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel11 = new wxButton(m_scrolledWindow, wxID_DEL11, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel11, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel12 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel12->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel12, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField12 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField12, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel12 = new wxButton(m_scrolledWindow, wxID_DEL12, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel12, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel13 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel13->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel13, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField13 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField13, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel13 = new wxButton(m_scrolledWindow, wxID_DEL13, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel13, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel14 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel14->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel14, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField14 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField14, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel14 = new wxButton(m_scrolledWindow, wxID_DEL14, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel14, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel15 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel15->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel15, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField15 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField15, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel15 = new wxButton(m_scrolledWindow, wxID_DEL15, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel15, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel16 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel16->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel16, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField16 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField16, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel16 = new wxButton(m_scrolledWindow, wxID_DEL16, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel16, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel17 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel17->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel17, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField17 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField17, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel17 = new wxButton(m_scrolledWindow, wxID_DEL17, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel17, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel18 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel18->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel18, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField18 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField18, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel18 = new wxButton(m_scrolledWindow, wxID_DEL18, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel18, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + m_textCtrlLabel19 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_textCtrlLabel19->SetMinSize(wxSize(150,-1)); + + fgSizer5->Add(m_textCtrlLabel19, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5); + + m_textCtrlField19 = new wxTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,-1), 0); + fgSizer5->Add(m_textCtrlField19, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5); + + m_buttonDel19 = new wxButton(m_scrolledWindow, wxID_DEL19, wxT("Delete"), wxDefaultPosition, wxSize(60,20), 0); + fgSizer5->Add(m_buttonDel19, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5); + + bSizer21->Add(fgSizer5, 0, wxEXPAND, 5); + + wxBoxSizer* bSizer25; + bSizer25 = new wxBoxSizer(wxHORIZONTAL); + + m_buttonAddField = new wxButton(m_scrolledWindow, wxID_ANY, wxT("&Add Field"), wxDefaultPosition, wxDefaultSize, 0); + bSizer25->Add(m_buttonAddField, 0, wxALL, 5); + + bSizer21->Add(bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5); + + m_scrolledWindow->SetSizer(bSizer21); + m_scrolledWindow->Layout(); + bSizer21->Fit(m_scrolledWindow); + bSizer20->Add(m_scrolledWindow, 1, wxEXPAND|wxALL, 5); + + wxBoxSizer* bSizer26; + bSizer26 = new wxBoxSizer(wxHORIZONTAL); + + m_buttonOK = new wxButton(this, wxID_BUTTONSEND, wxT("&Send"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonOK->SetMinSize(wxSize(85,25)); + + bSizer26->Add(m_buttonOK, 0, wxALL, 5); + + m_buttonPreview = new wxButton(this, wxID_BUTTONPREVIEW, wxT("&Preview"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonPreview->SetMinSize(wxSize(85,25)); + + bSizer26->Add(m_buttonPreview, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer26->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer20->Add(bSizer26, 0, wxALIGN_RIGHT, 5); + + this->SetSizer(bSizer20); + this->Layout(); + + // Connect Events + m_textCtrlTitle->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlPrice->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlDescription->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlInstructions->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlLabel0->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField0->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel0->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel0), NULL, this); + m_textCtrlLabel1->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField1->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel1->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel1), NULL, this); + m_textCtrlLabel2->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField2->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel2->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel2), NULL, this); + m_textCtrlLabel3->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField3->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel3->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel3), NULL, this); + m_textCtrlLabel4->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField4->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel4->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel4), NULL, this); + m_textCtrlLabel5->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField5->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel5->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel5), NULL, this); + m_textCtrlLabel6->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField6->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel6->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel6), NULL, this); + m_textCtrlLabel7->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField7->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel7->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel7), NULL, this); + m_textCtrlLabel8->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField8->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel8->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel8), NULL, this); + m_textCtrlLabel9->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField9->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel9->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel9), NULL, this); + m_textCtrlLabel10->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField10->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel10->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel10), NULL, this); + m_textCtrlLabel11->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField11->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel11->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel11), NULL, this); + m_textCtrlLabel12->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField12->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel12->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel12), NULL, this); + m_textCtrlLabel13->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField13->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel13->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel13), NULL, this); + m_textCtrlLabel14->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField14->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel14->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel14), NULL, this); + m_textCtrlLabel15->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField15->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel15->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel15), NULL, this); + m_textCtrlLabel16->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField16->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel16->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel16), NULL, this); + m_textCtrlLabel17->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField17->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel17->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel17), NULL, this); + m_textCtrlLabel18->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField18->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel18->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel18), NULL, this); + m_textCtrlLabel19->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField19->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel19->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel19), NULL, this); + m_buttonAddField->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonAddField), NULL, this); + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonSend), NULL, this); + m_buttonPreview->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonPreview), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonCancel), NULL, this); +} + +CEditProductDialogBase::~CEditProductDialogBase() +{ + // Disconnect Events + m_textCtrlTitle->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlPrice->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlDescription->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlInstructions->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlLabel0->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField0->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel0->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel0), NULL, this); + m_textCtrlLabel1->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField1->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel1), NULL, this); + m_textCtrlLabel2->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField2->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel2->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel2), NULL, this); + m_textCtrlLabel3->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField3->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel3->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel3), NULL, this); + m_textCtrlLabel4->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField4->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel4->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel4), NULL, this); + m_textCtrlLabel5->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField5->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel5->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel5), NULL, this); + m_textCtrlLabel6->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField6->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel6->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel6), NULL, this); + m_textCtrlLabel7->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField7->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel7->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel7), NULL, this); + m_textCtrlLabel8->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField8->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel8->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel8), NULL, this); + m_textCtrlLabel9->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField9->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel9->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel9), NULL, this); + m_textCtrlLabel10->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField10->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel10->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel10), NULL, this); + m_textCtrlLabel11->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField11->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel11->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel11), NULL, this); + m_textCtrlLabel12->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField12->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel12->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel12), NULL, this); + m_textCtrlLabel13->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField13->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel13->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel13), NULL, this); + m_textCtrlLabel14->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField14->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel14->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel14), NULL, this); + m_textCtrlLabel15->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField15->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel15->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel15), NULL, this); + m_textCtrlLabel16->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField16->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel16->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel16), NULL, this); + m_textCtrlLabel17->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField17->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel17->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel17), NULL, this); + m_textCtrlLabel18->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField18->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel18->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel18), NULL, this); + m_textCtrlLabel19->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_textCtrlField19->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditProductDialogBase::OnKeyDown), NULL, this); + m_buttonDel19->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonDel19), NULL, this); + m_buttonAddField->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonAddField), NULL, this); + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonSend), NULL, this); + m_buttonPreview->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonPreview), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditProductDialogBase::OnButtonCancel), NULL, this); +} + +CViewProductDialogBase::CViewProductDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENU)); + + wxBoxSizer* bSizer20; + bSizer20 = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* bSizer116; + bSizer116 = new wxBoxSizer(wxHORIZONTAL); + + m_htmlWinReviews = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); + m_htmlWinReviews->Hide(); + + bSizer116->Add(m_htmlWinReviews, 1, wxALL|wxEXPAND, 5); + + m_scrolledWindow = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL); + m_scrolledWindow->SetScrollRate(5, 5); + m_scrolledWindow->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + wxBoxSizer* bSizer21; + bSizer21 = new wxBoxSizer(wxVERTICAL); + + m_richTextHeading = new wxRichTextCtrl(m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1,50), wxTE_READONLY|wxNO_BORDER); + bSizer21->Add(m_richTextHeading, 0, wxEXPAND, 5); + + m_staticTextInstructions = new wxStaticText(m_scrolledWindow, wxID_ANY, wxT("Order Form instructions here\nmultiple lines\n1\n2\n3\n4\n5\n6"), wxDefaultPosition, wxDefaultSize, 0); + m_staticTextInstructions->Wrap(-1); + bSizer21->Add(m_staticTextInstructions, 0, wxALL|wxEXPAND, 5); + + wxBoxSizer* bSizer25; + bSizer25 = new wxBoxSizer(wxHORIZONTAL); + + m_buttonSubmitForm = new wxButton(m_scrolledWindow, wxID_BUTTONSAMPLE, wxT("&Submit"), wxDefaultPosition, wxDefaultSize, 0); + bSizer25->Add(m_buttonSubmitForm, 0, wxALL, 5); + + m_buttonCancelForm = new wxButton(m_scrolledWindow, wxID_CANCEL2, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0); + bSizer25->Add(m_buttonCancelForm, 0, wxALL, 5); + + bSizer21->Add(bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5); + + m_scrolledWindow->SetSizer(bSizer21); + m_scrolledWindow->Layout(); + bSizer21->Fit(m_scrolledWindow); + bSizer116->Add(m_scrolledWindow, 1, wxEXPAND|wxALL, 5); + + bSizer20->Add(bSizer116, 1, wxEXPAND, 5); + + wxBoxSizer* bSizer26; + bSizer26 = new wxBoxSizer(wxHORIZONTAL); + + m_buttonBack = new wxButton(this, wxID_BUTTONBACK, wxT("< &Back "), wxDefaultPosition, wxDefaultSize, 0); + m_buttonBack->Enable(false); + m_buttonBack->SetMinSize(wxSize(85,25)); + + bSizer26->Add(m_buttonBack, 0, wxALL, 5); + + m_buttonNext = new wxButton(this, wxID_BUTTONNEXT, wxT(" &Next >"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonNext->SetMinSize(wxSize(85,25)); + + bSizer26->Add(m_buttonNext, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer26->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer20->Add(bSizer26, 0, wxALIGN_RIGHT, 5); + + this->SetSizer(bSizer20); + this->Layout(); + + // Connect Events + m_buttonSubmitForm->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonSubmitForm), NULL, this); + m_buttonCancelForm->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonCancelForm), NULL, this); + m_buttonBack->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonBack), NULL, this); + m_buttonNext->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonNext), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonCancel), NULL, this); +} + +CViewProductDialogBase::~CViewProductDialogBase() +{ + // Disconnect Events + m_buttonSubmitForm->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonSubmitForm), NULL, this); + m_buttonCancelForm->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonCancelForm), NULL, this); + m_buttonBack->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonBack), NULL, this); + m_buttonNext->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonNext), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewProductDialogBase::OnButtonCancel), NULL, this); +} + +CViewOrderDialogBase::CViewOrderDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENU)); + + wxBoxSizer* bSizer20; + bSizer20 = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* bSizer116; + bSizer116 = new wxBoxSizer(wxHORIZONTAL); + + m_htmlWin = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); + bSizer116->Add(m_htmlWin, 1, wxALL|wxEXPAND, 5); + + bSizer20->Add(bSizer116, 1, wxEXPAND, 5); + + wxBoxSizer* bSizer26; + bSizer26 = new wxBoxSizer(wxHORIZONTAL); + + m_buttonOK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonOK->SetMinSize(wxSize(85,25)); + + bSizer26->Add(m_buttonOK, 0, wxALL, 5); + + bSizer20->Add(bSizer26, 0, wxALIGN_RIGHT, 5); + + this->SetSizer(bSizer20); + this->Layout(); + + // Connect Events + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewOrderDialogBase::OnButtonOK), NULL, this); +} + +CViewOrderDialogBase::~CViewOrderDialogBase() +{ + // Disconnect Events + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CViewOrderDialogBase::OnButtonOK), NULL, this); +} + +CEditReviewDialogBase::CEditReviewDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENU)); + + wxBoxSizer* bSizer112; + bSizer112 = new wxBoxSizer(wxVERTICAL); + + + bSizer112->Add(0, 3, 0, 0, 5); + + m_staticTextSeller = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_staticTextSeller->Wrap(-1); + bSizer112->Add(m_staticTextSeller, 0, wxALL|wxEXPAND, 5); + + + bSizer112->Add(0, 3, 0, 0, 5); + + m_staticText110 = new wxStaticText(this, wxID_ANY, wxT("Rating"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText110->Wrap(-1); + bSizer112->Add(m_staticText110, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + wxString m_choiceStarsChoices[] = { wxT(" 1 star"), wxT(" 2 stars"), wxT(" 3 stars"), wxT(" 4 stars"), wxT(" 5 stars") }; + int m_choiceStarsNChoices = sizeof(m_choiceStarsChoices) / sizeof(wxString); + m_choiceStars = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceStarsNChoices, m_choiceStarsChoices, 0); + m_choiceStars->SetSelection(0); + bSizer112->Add(m_choiceStars, 0, wxALL, 5); + + m_staticText43 = new wxStaticText(this, wxID_ANY, wxT("Review"), wxDefaultPosition, wxDefaultSize, 0); + m_staticText43->Wrap(-1); + bSizer112->Add(m_staticText43, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + m_textCtrlReview = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + bSizer112->Add(m_textCtrlReview, 1, wxALL|wxEXPAND, 5); + + wxBoxSizer* bSizer113; + bSizer113 = new wxBoxSizer(wxHORIZONTAL); + + m_buttonSubmit = new wxButton(this, wxID_SUBMIT, wxT("&Submit"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonSubmit->SetMinSize(wxSize(85,25)); + + bSizer113->Add(m_buttonSubmit, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer113->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer112->Add(bSizer113, 0, wxALIGN_RIGHT, 5); + + this->SetSizer(bSizer112); + this->Layout(); + + // Connect Events + m_textCtrlReview->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditReviewDialogBase::OnKeyDown), NULL, this); + m_buttonSubmit->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditReviewDialogBase::OnButtonSubmit), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditReviewDialogBase::OnButtonCancel), NULL, this); +} + +CEditReviewDialogBase::~CEditReviewDialogBase() +{ + // Disconnect Events + m_textCtrlReview->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CEditReviewDialogBase::OnKeyDown), NULL, this); + m_buttonSubmit->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditReviewDialogBase::OnButtonSubmit), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CEditReviewDialogBase::OnButtonCancel), NULL, this); +} + +CPokerLobbyDialogBase::CPokerLobbyDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + + wxBoxSizer* bSizer156; + bSizer156 = new wxBoxSizer(wxHORIZONTAL); + + m_treeCtrl = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_HIDE_ROOT|wxTR_LINES_AT_ROOT); + m_treeCtrl->SetMinSize(wxSize(130,-1)); + + bSizer156->Add(m_treeCtrl, 0, wxEXPAND|wxTOP|wxBOTTOM|wxLEFT, 5); + + wxBoxSizer* bSizer172; + bSizer172 = new wxBoxSizer(wxVERTICAL); + + m_listCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT); + bSizer172->Add(m_listCtrl, 1, wxEXPAND|wxALL, 5); + + m_buttonNewTable = new wxButton(this, wxID_OPENNEWTABLE, wxT("&Open New Table"), wxDefaultPosition, wxDefaultSize, 0); + bSizer172->Add(m_buttonNewTable, 0, wxALL, 5); + + bSizer156->Add(bSizer172, 1, wxEXPAND, 5); + + this->SetSizer(bSizer156); + this->Layout(); + + // Connect Events + m_treeCtrl->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler(CPokerLobbyDialogBase::OnTreeSelChanged), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CPokerLobbyDialogBase::OnListItemActivated), NULL, this); + m_listCtrl->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(CPokerLobbyDialogBase::OnListItemSelected), NULL, this); + m_buttonNewTable->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerLobbyDialogBase::OnButtonNewTable), NULL, this); +} + +CPokerLobbyDialogBase::~CPokerLobbyDialogBase() +{ + // Disconnect Events + m_treeCtrl->Disconnect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler(CPokerLobbyDialogBase::OnTreeSelChanged), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(CPokerLobbyDialogBase::OnListItemActivated), NULL, this); + m_listCtrl->Disconnect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(CPokerLobbyDialogBase::OnListItemSelected), NULL, this); + m_buttonNewTable->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerLobbyDialogBase::OnButtonNewTable), NULL, this); +} + +CPokerDialogBase::CPokerDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer174; + bSizer174 = new wxBoxSizer(wxVERTICAL); + + m_checkSitOut = new wxCheckBox(this, wxID_ANY, wxT("Deal Me Out"), wxDefaultPosition, wxDefaultSize, 0); + + bSizer174->Add(m_checkSitOut, 0, wxALL, 5); + + m_buttonDealHand = new wxButton(this, wxID_DEALHAND, wxT("&Deal Hand"), wxDefaultPosition, wxSize(150,25), 0); + bSizer174->Add(m_buttonDealHand, 0, wxALL, 5); + + m_buttonFold = new wxButton(this, wxID_FOLD, wxT("&Fold"), wxDefaultPosition, wxSize(80,25), 0); + bSizer174->Add(m_buttonFold, 0, wxALL, 5); + + m_buttonCall = new wxButton(this, wxID_CALL, wxT("&Call"), wxDefaultPosition, wxSize(80,25), 0); + bSizer174->Add(m_buttonCall, 0, wxALL, 5); + + m_buttonRaise = new wxButton(this, wxID_RAISE, wxT("&Raise"), wxDefaultPosition, wxSize(80,25), 0); + bSizer174->Add(m_buttonRaise, 0, wxALL, 5); + + m_buttonLeaveTable = new wxButton(this, wxID_LEAVETABLE, wxT("&Leave Table"), wxDefaultPosition, wxSize(90,25), 0); + bSizer174->Add(m_buttonLeaveTable, 0, wxALL, 5); + + m_textDitchPlayer = new wxTextCtrl(this, wxID_DITCHPLAYER, wxEmptyString, wxDefaultPosition, wxSize(45,-1), wxTE_PROCESS_ENTER); + bSizer174->Add(m_textDitchPlayer, 0, wxALL, 5); + + m_checkPreFold = new wxCheckBox(this, wxID_ANY, wxT("FOLD"), wxDefaultPosition, wxSize(100,-1), 0); + + bSizer174->Add(m_checkPreFold, 0, wxALL, 5); + + m_checkPreCall = new wxCheckBox(this, wxID_ANY, wxT("CALL"), wxDefaultPosition, wxSize(100,-1), 0); + + bSizer174->Add(m_checkPreCall, 0, wxALL, 5); + + m_checkPreCallAny = new wxCheckBox(this, wxID_ANY, wxT("CALL ANY"), wxDefaultPosition, wxSize(100,-1), 0); + + bSizer174->Add(m_checkPreCallAny, 0, wxALL, 5); + + m_checkPreRaise = new wxCheckBox(this, wxID_ANY, wxT("RAISE"), wxDefaultPosition, wxSize(100,-1), 0); + + bSizer174->Add(m_checkPreRaise, 0, wxALL, 5); + + m_checkPreRaiseAny = new wxCheckBox(this, wxID_ANY, wxT("RAISE ANY"), wxDefaultPosition, wxSize(100,-1), 0); + + bSizer174->Add(m_checkPreRaiseAny, 0, wxALL, 5); + + this->SetSizer(bSizer174); + this->Layout(); + m_statusBar = this->CreateStatusBar(1, wxST_SIZEGRIP, wxID_ANY); + + // Connect Events + this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CPokerDialogBase::OnClose)); + this->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_MOTION, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Connect(wxEVT_PAINT, wxPaintEventHandler(CPokerDialogBase::OnPaint)); + this->Connect(wxEVT_SIZE, wxSizeEventHandler(CPokerDialogBase::OnSize)); + m_checkSitOut->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckSitOut), NULL, this); + m_buttonDealHand->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonDealHand), NULL, this); + m_buttonFold->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonFold), NULL, this); + m_buttonCall->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonCall), NULL, this); + m_buttonRaise->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonRaise), NULL, this); + m_buttonLeaveTable->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonLeaveTable), NULL, this); + m_textDitchPlayer->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(CPokerDialogBase::OnDitchPlayer), NULL, this); + m_checkPreFold->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreFold), NULL, this); + m_checkPreCall->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreCall), NULL, this); + m_checkPreCallAny->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreCallAny), NULL, this); + m_checkPreRaise->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreRaise), NULL, this); + m_checkPreRaiseAny->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreRaiseAny), NULL, this); +} + +CPokerDialogBase::~CPokerDialogBase() +{ + // Disconnect Events + this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CPokerDialogBase::OnClose)); + this->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_MIDDLE_UP, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_RIGHT_UP, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_MOTION, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(CPokerDialogBase::OnMouseEvents)); + this->Disconnect(wxEVT_PAINT, wxPaintEventHandler(CPokerDialogBase::OnPaint)); + this->Disconnect(wxEVT_SIZE, wxSizeEventHandler(CPokerDialogBase::OnSize)); + m_checkSitOut->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckSitOut), NULL, this); + m_buttonDealHand->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonDealHand), NULL, this); + m_buttonFold->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonFold), NULL, this); + m_buttonCall->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonCall), NULL, this); + m_buttonRaise->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonRaise), NULL, this); + m_buttonLeaveTable->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnButtonLeaveTable), NULL, this); + m_textDitchPlayer->Disconnect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(CPokerDialogBase::OnDitchPlayer), NULL, this); + m_checkPreFold->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreFold), NULL, this); + m_checkPreCall->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreCall), NULL, this); + m_checkPreCallAny->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreCallAny), NULL, this); + m_checkPreRaise->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreRaise), NULL, this); + m_checkPreRaiseAny->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CPokerDialogBase::OnCheckPreRaiseAny), NULL, this); +} + +CGetTextFromUserDialogBase::CGetTextFromUserDialogBase(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +{ + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer* bSizer79; + bSizer79 = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* bSizer81; + bSizer81 = new wxBoxSizer(wxVERTICAL); + + + bSizer81->Add(0, 0, 1, wxEXPAND, 5); + + m_staticTextMessage1 = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_staticTextMessage1->Wrap(-1); + bSizer81->Add(m_staticTextMessage1, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + m_textCtrl1 = new wxTextCtrl(this, wxID_TEXTCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + bSizer81->Add(m_textCtrl1, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5); + + m_staticTextMessage2 = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_staticTextMessage2->Wrap(-1); + m_staticTextMessage2->Hide(); + + bSizer81->Add(m_staticTextMessage2, 0, wxTOP|wxRIGHT|wxLEFT, 5); + + m_textCtrl2 = new wxTextCtrl(this, wxID_TEXTCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + m_textCtrl2->Hide(); + + bSizer81->Add(m_textCtrl2, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5); + + + bSizer81->Add(0, 0, 1, wxEXPAND, 5); + + bSizer79->Add(bSizer81, 1, wxEXPAND|wxALL, 10); + + wxBoxSizer* bSizer80; + bSizer80 = new wxBoxSizer(wxHORIZONTAL); + + + bSizer80->Add(0, 0, 1, wxEXPAND, 5); + + m_buttonOK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxSize(-1,-1), 0); + m_buttonOK->SetMinSize(wxSize(85,25)); + + bSizer80->Add(m_buttonOK, 0, wxALL, 5); + + m_buttonCancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0); + m_buttonCancel->SetMinSize(wxSize(85,25)); + + bSizer80->Add(m_buttonCancel, 0, wxALL, 5); + + bSizer79->Add(bSizer80, 0, wxEXPAND, 5); + + this->SetSizer(bSizer79); + this->Layout(); + + // Connect Events + this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CGetTextFromUserDialogBase::OnClose)); + m_textCtrl1->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CGetTextFromUserDialogBase::OnKeyDown), NULL, this); + m_textCtrl2->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CGetTextFromUserDialogBase::OnKeyDown), NULL, this); + m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CGetTextFromUserDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CGetTextFromUserDialogBase::OnButtonCancel), NULL, this); +} + +CGetTextFromUserDialogBase::~CGetTextFromUserDialogBase() +{ + // Disconnect Events + this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(CGetTextFromUserDialogBase::OnClose)); + m_textCtrl1->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CGetTextFromUserDialogBase::OnKeyDown), NULL, this); + m_textCtrl2->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(CGetTextFromUserDialogBase::OnKeyDown), NULL, this); + m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CGetTextFromUserDialogBase::OnButtonOK), NULL, this); + m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CGetTextFromUserDialogBase::OnButtonCancel), NULL, this); +} diff --git a/uibase.h b/uibase.h new file mode 100644 index 000000000..bfcd8eccb --- /dev/null +++ b/uibase.h @@ -0,0 +1,723 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 16 2008) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __uibase__ +#define __uibase__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +#define wxID_MAINFRAME 1000 +#define wxID_OPTIONSGENERATEBITCOINS 1001 +#define wxID_BUTTONSEND 1002 +#define wxID_BUTTONRECEIVE 1003 +#define wxID_TEXTCTRLADDRESS 1004 +#define wxID_BUTTONCOPY 1005 +#define wxID_BUTTONCHANGE 1006 +#define wxID_TRANSACTIONFEE 1007 +#define wxID_TEXTCTRLPAYTO 1008 +#define wxID_BUTTONPASTE 1009 +#define wxID_BUTTONADDRESSBOOK 1010 +#define wxID_TEXTCTRLAMOUNT 1011 +#define wxID_CHOICETRANSFERTYPE 1012 +#define wxID_LISTCTRL 1013 +#define wxID_BUTTONRENAME 1014 +#define wxID_BUTTONNEW 1015 +#define wxID_BUTTONEDIT 1016 +#define wxID_BUTTONDELETE 1017 +#define wxID_DEL0 1018 +#define wxID_DEL1 1019 +#define wxID_DEL2 1020 +#define wxID_DEL3 1021 +#define wxID_DEL4 1022 +#define wxID_DEL5 1023 +#define wxID_DEL6 1024 +#define wxID_DEL7 1025 +#define wxID_DEL8 1026 +#define wxID_DEL9 1027 +#define wxID_DEL10 1028 +#define wxID_DEL11 1029 +#define wxID_DEL12 1030 +#define wxID_DEL13 1031 +#define wxID_DEL14 1032 +#define wxID_DEL15 1033 +#define wxID_DEL16 1034 +#define wxID_DEL17 1035 +#define wxID_DEL18 1036 +#define wxID_DEL19 1037 +#define wxID_BUTTONPREVIEW 1038 +#define wxID_BUTTONSAMPLE 1039 +#define wxID_CANCEL2 1040 +#define wxID_BUTTONBACK 1041 +#define wxID_BUTTONNEXT 1042 +#define wxID_SUBMIT 1043 +#define wxID_OPENNEWTABLE 1044 +#define wxID_DEALHAND 1045 +#define wxID_FOLD 1046 +#define wxID_CALL 1047 +#define wxID_RAISE 1048 +#define wxID_LEAVETABLE 1049 +#define wxID_DITCHPLAYER 1050 +#define wxID_TEXTCTRL 1051 + +/////////////////////////////////////////////////////////////////////////////// +/// Class CMainFrameBase +/////////////////////////////////////////////////////////////////////////////// +class CMainFrameBase : public wxFrame +{ +private: + +protected: + wxMenuBar* m_menubar; + wxMenu* m_menuFile; + wxMenu* m_menuHelp; + wxToolBar* m_toolBar; + wxStatusBar* m_statusBar; + + wxStaticText* m_staticText32; + wxTextCtrl* m_textCtrlAddress; + wxButton* m_buttonCopy; + wxButton* m_button91; + + wxPanel* m_panel14; + wxStaticText* m_staticText41; + wxStaticText* m_staticTextBalance; + + wxChoice* m_choiceFilter; + wxNotebook* m_notebook; + wxPanel* m_panel7; + wxPanel* m_panel9; + wxPanel* m_panel8; + wxPanel* m_panel10; + wxPanel* m_panel11; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose(wxCloseEvent& event){ event.Skip(); } + virtual void OnIdle(wxIdleEvent& event){ event.Skip(); } + virtual void OnMouseEvents(wxMouseEvent& event){ event.Skip(); } + virtual void OnPaint(wxPaintEvent& event){ event.Skip(); } + virtual void OnMenuFileExit(wxCommandEvent& event){ event.Skip(); } + virtual void OnMenuOptionsGenerate(wxCommandEvent& event){ event.Skip(); } + virtual void OnMenuOptionsChangeYourAddress(wxCommandEvent& event){ event.Skip(); } + virtual void OnMenuOptionsOptions(wxCommandEvent& event){ event.Skip(); } + virtual void OnMenuHelpAbout(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonSend(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonAddressBook(wxCommandEvent& event){ event.Skip(); } + virtual void OnKeyDown(wxKeyEvent& event){ event.Skip(); } + virtual void OnMouseEventsAddress(wxMouseEvent& event){ event.Skip(); } + virtual void OnSetFocusAddress(wxFocusEvent& event){ event.Skip(); } + virtual void OnButtonCopy(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonChange(wxCommandEvent& event){ event.Skip(); } + virtual void OnListColBeginDrag(wxListEvent& event){ event.Skip(); } + virtual void OnListItemActivatedAllTransactions(wxListEvent& event){ event.Skip(); } + virtual void OnPaintListCtrl(wxPaintEvent& event){ event.Skip(); } + virtual void OnListItemActivatedOrdersSent(wxListEvent& event){ event.Skip(); } + virtual void OnListItemActivatedProductsSent(wxListEvent& event){ event.Skip(); } + virtual void OnListItemActivatedOrdersReceived(wxListEvent& event){ event.Skip(); } + + +public: + wxMenu* m_menuOptions; + wxListCtrl* m_listCtrl; + wxListCtrl* m_listCtrlEscrows; + wxListCtrl* m_listCtrlOrdersSent; + wxListCtrl* m_listCtrlProductsSent; + wxListCtrl* m_listCtrlOrdersReceived; + CMainFrameBase(wxWindow* parent, wxWindowID id = wxID_MAINFRAME, const wxString& title = wxT("Bitcoin"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(705,484), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL); + ~CMainFrameBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CTxDetailsDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CTxDetailsDialogBase : public wxDialog +{ +private: + +protected: + wxHtmlWindow* m_htmlWin; + wxButton* m_buttonOK; + + // Virtual event handlers, overide them in your derived class + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + + +public: + CTxDetailsDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Transaction Details"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(620,450), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); + ~CTxDetailsDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class COptionsDialogBase +/////////////////////////////////////////////////////////////////////////////// +class COptionsDialogBase : public wxDialog +{ +private: + +protected: + + wxStaticText* m_staticText32; + wxStaticText* m_staticText31; + wxTextCtrl* m_textCtrlTransactionFee; + wxButton* m_buttonOK; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnKillFocusTransactionFee(wxFocusEvent& event){ event.Skip(); } + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + COptionsDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(500,261), long style = wxDEFAULT_DIALOG_STYLE); + ~COptionsDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CAboutDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CAboutDialogBase : public wxDialog +{ +private: + +protected: + + + wxStaticText* m_staticText40; + + wxStaticText* m_staticTextMain; + + + wxButton* m_buttonOK; + + // Virtual event handlers, overide them in your derived class + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + + +public: + wxStaticText* m_staticTextVersion; + CAboutDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("About Bitcoin"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(507,298), long style = wxDEFAULT_DIALOG_STYLE); + ~CAboutDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CSendDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CSendDialogBase : public wxDialog +{ +private: + +protected: + + + wxStaticText* m_staticText14; + + wxStaticBitmap* m_bitmapCheckMark; + wxStaticText* m_staticText36; + wxTextCtrl* m_textCtrlAddress; + wxButton* m_buttonPaste; + wxButton* m_buttonAddress; + wxStaticText* m_staticText19; + wxTextCtrl* m_textCtrlAmount; + wxStaticText* m_staticText20; + wxChoice* m_choiceTransferType; + + + wxStaticText* m_staticTextFrom; + wxTextCtrl* m_textCtrlFrom; + wxStaticText* m_staticTextMessage; + wxTextCtrl* m_textCtrlMessage; + + wxButton* m_buttonSend; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnKeyDown(wxKeyEvent& event){ event.Skip(); } + virtual void OnTextAddress(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonPaste(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonAddressBook(wxCommandEvent& event){ event.Skip(); } + virtual void OnKillFocusAmount(wxFocusEvent& event){ event.Skip(); } + virtual void OnButtonSend(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + CSendDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Send Coins"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(675,312), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); + ~CSendDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CSendingDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CSendingDialogBase : public wxDialog +{ +private: + +protected: + wxStaticText* m_staticTextSending; + wxTextCtrl* m_textCtrlStatus; + + wxButton* m_buttonOK; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose(wxCloseEvent& event){ event.Skip(); } + virtual void OnPaint(wxPaintEvent& event){ event.Skip(); } + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + CSendingDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Sending..."), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(442,151), long style = wxDEFAULT_DIALOG_STYLE); + ~CSendingDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CYourAddressDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CYourAddressDialogBase : public wxDialog +{ +private: + +protected: + + wxStaticText* m_staticText45; + wxListCtrl* m_listCtrl; + + wxButton* m_buttonRename; + wxButton* m_buttonNew; + wxButton* m_buttonCopy; + wxButton* m_buttonOK; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose(wxCloseEvent& event){ event.Skip(); } + virtual void OnListEndLabelEdit(wxListEvent& event){ event.Skip(); } + virtual void OnListItemActivated(wxListEvent& event){ event.Skip(); } + virtual void OnListItemSelected(wxListEvent& event){ event.Skip(); } + virtual void OnButtonRename(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonNew(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCopy(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + CYourAddressDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Your Bitcoin Addresses"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(610,390), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); + ~CYourAddressDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CAddressBookDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CAddressBookDialogBase : public wxDialog +{ +private: + +protected: + + wxStaticText* m_staticText55; + wxListCtrl* m_listCtrl; + + wxButton* m_buttonEdit; + wxButton* m_buttonNew; + wxButton* m_buttonDelete; + wxButton* m_buttonOK; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose(wxCloseEvent& event){ event.Skip(); } + virtual void OnListEndLabelEdit(wxListEvent& event){ event.Skip(); } + virtual void OnListItemActivated(wxListEvent& event){ event.Skip(); } + virtual void OnListItemSelected(wxListEvent& event){ event.Skip(); } + virtual void OnButtonEdit(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonNew(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDelete(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + wxButton* m_buttonCancel; + CAddressBookDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Address Book"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(610,390), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); + ~CAddressBookDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CProductsDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CProductsDialogBase : public wxDialog +{ +private: + +protected: + wxComboBox* m_comboBoxCategory; + wxTextCtrl* m_textCtrlSearch; + wxButton* m_buttonSearch; + wxListCtrl* m_listCtrl; + + // Virtual event handlers, overide them in your derived class + virtual void OnCombobox(wxCommandEvent& event){ event.Skip(); } + virtual void OnKeyDown(wxKeyEvent& event){ event.Skip(); } + virtual void OnButtonSearch(wxCommandEvent& event){ event.Skip(); } + virtual void OnListItemActivated(wxListEvent& event){ event.Skip(); } + + +public: + CProductsDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Marketplace"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(708,535), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); + ~CProductsDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CEditProductDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CEditProductDialogBase : public wxFrame +{ +private: + +protected: + wxScrolledWindow* m_scrolledWindow; + wxStaticText* m_staticText106; + wxComboBox* m_comboBoxCategory; + wxStaticText* m_staticText108; + wxTextCtrl* m_textCtrlTitle; + wxStaticText* m_staticText107; + wxTextCtrl* m_textCtrlPrice; + wxStaticText* m_staticText22; + wxTextCtrl* m_textCtrlDescription; + wxStaticText* m_staticText23; + wxTextCtrl* m_textCtrlInstructions; + wxStaticText* m_staticText24; + wxStaticText* m_staticText25; + + wxTextCtrl* m_textCtrlLabel0; + wxTextCtrl* m_textCtrlField0; + wxButton* m_buttonDel0; + wxTextCtrl* m_textCtrlLabel1; + wxTextCtrl* m_textCtrlField1; + wxButton* m_buttonDel1; + wxTextCtrl* m_textCtrlLabel2; + wxTextCtrl* m_textCtrlField2; + wxButton* m_buttonDel2; + wxTextCtrl* m_textCtrlLabel3; + wxTextCtrl* m_textCtrlField3; + wxButton* m_buttonDel3; + wxTextCtrl* m_textCtrlLabel4; + wxTextCtrl* m_textCtrlField4; + wxButton* m_buttonDel4; + wxTextCtrl* m_textCtrlLabel5; + wxTextCtrl* m_textCtrlField5; + wxButton* m_buttonDel5; + wxTextCtrl* m_textCtrlLabel6; + wxTextCtrl* m_textCtrlField6; + wxButton* m_buttonDel6; + wxTextCtrl* m_textCtrlLabel7; + wxTextCtrl* m_textCtrlField7; + wxButton* m_buttonDel7; + wxTextCtrl* m_textCtrlLabel8; + wxTextCtrl* m_textCtrlField8; + wxButton* m_buttonDel8; + wxTextCtrl* m_textCtrlLabel9; + wxTextCtrl* m_textCtrlField9; + wxButton* m_buttonDel9; + wxTextCtrl* m_textCtrlLabel10; + wxTextCtrl* m_textCtrlField10; + wxButton* m_buttonDel10; + wxTextCtrl* m_textCtrlLabel11; + wxTextCtrl* m_textCtrlField11; + wxButton* m_buttonDel11; + wxTextCtrl* m_textCtrlLabel12; + wxTextCtrl* m_textCtrlField12; + wxButton* m_buttonDel12; + wxTextCtrl* m_textCtrlLabel13; + wxTextCtrl* m_textCtrlField13; + wxButton* m_buttonDel13; + wxTextCtrl* m_textCtrlLabel14; + wxTextCtrl* m_textCtrlField14; + wxButton* m_buttonDel14; + wxTextCtrl* m_textCtrlLabel15; + wxTextCtrl* m_textCtrlField15; + wxButton* m_buttonDel15; + wxTextCtrl* m_textCtrlLabel16; + wxTextCtrl* m_textCtrlField16; + wxButton* m_buttonDel16; + wxTextCtrl* m_textCtrlLabel17; + wxTextCtrl* m_textCtrlField17; + wxButton* m_buttonDel17; + wxTextCtrl* m_textCtrlLabel18; + wxTextCtrl* m_textCtrlField18; + wxButton* m_buttonDel18; + wxTextCtrl* m_textCtrlLabel19; + wxTextCtrl* m_textCtrlField19; + wxButton* m_buttonDel19; + wxButton* m_buttonAddField; + wxButton* m_buttonOK; + wxButton* m_buttonPreview; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnKeyDown(wxKeyEvent& event){ event.Skip(); } + virtual void OnButtonDel0(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel1(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel2(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel3(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel4(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel5(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel6(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel7(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel8(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel9(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel10(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel11(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel12(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel13(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel14(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel15(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel16(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel17(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel18(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDel19(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonAddField(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonSend(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonPreview(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + wxFlexGridSizer* fgSizer5; + CEditProductDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Edit Product"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(660,640), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL); + ~CEditProductDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CViewProductDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CViewProductDialogBase : public wxFrame +{ +private: + +protected: + wxHtmlWindow* m_htmlWinReviews; + wxScrolledWindow* m_scrolledWindow; + wxRichTextCtrl* m_richTextHeading; + wxStaticText* m_staticTextInstructions; + wxButton* m_buttonSubmitForm; + wxButton* m_buttonCancelForm; + wxButton* m_buttonBack; + wxButton* m_buttonNext; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnButtonSubmitForm(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancelForm(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonBack(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonNext(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + CViewProductDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Order Form"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(630,520), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL); + ~CViewProductDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CViewOrderDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CViewOrderDialogBase : public wxFrame +{ +private: + +protected: + wxHtmlWindow* m_htmlWin; + wxButton* m_buttonOK; + + // Virtual event handlers, overide them in your derived class + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + + +public: + CViewOrderDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("View Order"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(630,520), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL); + ~CViewOrderDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CEditReviewDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CEditReviewDialogBase : public wxFrame +{ +private: + +protected: + + wxStaticText* m_staticTextSeller; + + wxStaticText* m_staticText110; + wxChoice* m_choiceStars; + wxStaticText* m_staticText43; + wxTextCtrl* m_textCtrlReview; + wxButton* m_buttonSubmit; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnKeyDown(wxKeyEvent& event){ event.Skip(); } + virtual void OnButtonSubmit(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + CEditReviewDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Enter Review"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(630,440), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL); + ~CEditReviewDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CPokerLobbyDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CPokerLobbyDialogBase : public wxFrame +{ +private: + +protected: + wxTreeCtrl* m_treeCtrl; + wxListCtrl* m_listCtrl; + wxButton* m_buttonNewTable; + + // Virtual event handlers, overide them in your derived class + virtual void OnTreeSelChanged(wxTreeEvent& event){ event.Skip(); } + virtual void OnListItemActivated(wxListEvent& event){ event.Skip(); } + virtual void OnListItemSelected(wxListEvent& event){ event.Skip(); } + virtual void OnButtonNewTable(wxCommandEvent& event){ event.Skip(); } + + +public: + CPokerLobbyDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Poker Lobby"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(586,457), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL); + ~CPokerLobbyDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CPokerDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CPokerDialogBase : public wxFrame +{ +private: + +protected: + wxButton* m_buttonDealHand; + wxButton* m_buttonFold; + wxButton* m_buttonCall; + wxButton* m_buttonRaise; + wxButton* m_buttonLeaveTable; + wxTextCtrl* m_textDitchPlayer; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose(wxCloseEvent& event){ event.Skip(); } + virtual void OnMouseEvents(wxMouseEvent& event){ event.Skip(); } + virtual void OnPaint(wxPaintEvent& event){ event.Skip(); } + virtual void OnSize(wxSizeEvent& event){ event.Skip(); } + virtual void OnCheckSitOut(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonDealHand(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonFold(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCall(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonRaise(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonLeaveTable(wxCommandEvent& event){ event.Skip(); } + virtual void OnDitchPlayer(wxCommandEvent& event){ event.Skip(); } + virtual void OnCheckPreFold(wxCommandEvent& event){ event.Skip(); } + virtual void OnCheckPreCall(wxCommandEvent& event){ event.Skip(); } + virtual void OnCheckPreCallAny(wxCommandEvent& event){ event.Skip(); } + virtual void OnCheckPreRaise(wxCommandEvent& event){ event.Skip(); } + virtual void OnCheckPreRaiseAny(wxCommandEvent& event){ event.Skip(); } + + +public: + wxCheckBox* m_checkSitOut; + wxCheckBox* m_checkPreFold; + wxCheckBox* m_checkPreCall; + wxCheckBox* m_checkPreCallAny; + wxCheckBox* m_checkPreRaise; + wxCheckBox* m_checkPreRaiseAny; + wxStatusBar* m_statusBar; + CPokerDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Poker"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(806,550), long style = wxDEFAULT_FRAME_STYLE|wxFRAME_NO_TASKBAR|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL); + ~CPokerDialogBase(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class CGetTextFromUserDialogBase +/////////////////////////////////////////////////////////////////////////////// +class CGetTextFromUserDialogBase : public wxDialog +{ +private: + +protected: + + wxStaticText* m_staticTextMessage1; + wxTextCtrl* m_textCtrl1; + wxStaticText* m_staticTextMessage2; + wxTextCtrl* m_textCtrl2; + + + wxButton* m_buttonOK; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose(wxCloseEvent& event){ event.Skip(); } + virtual void OnKeyDown(wxKeyEvent& event){ event.Skip(); } + virtual void OnButtonOK(wxCommandEvent& event){ event.Skip(); } + virtual void OnButtonCancel(wxCommandEvent& event){ event.Skip(); } + + +public: + CGetTextFromUserDialogBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(403,138), long style = wxDEFAULT_DIALOG_STYLE); + ~CGetTextFromUserDialogBase(); + +}; + +#endif //__uibase__ diff --git a/uint256.h b/uint256.h new file mode 100644 index 000000000..9a0c77049 --- /dev/null +++ b/uint256.h @@ -0,0 +1,750 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int64; +typedef unsigned long long uint64; +#endif +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define for if (false) ; else for +#endif + + +inline int Testuint256AdHoc(vector vArg); + + + +// We have to keep a separate base class without constructors +// so the compiler will let us use it in a union +template +class base_uint +{ +protected: + enum { WIDTH=BITS/32 }; + unsigned int pn[WIDTH]; +public: + + bool operator!() const + { + for (int i = 0; i < WIDTH; i++) + if (pn[i] != 0) + return false; + return true; + } + + const base_uint operator~() const + { + base_uint ret; + for (int i = 0; i < WIDTH; i++) + ret.pn[i] = ~pn[i]; + return ret; + } + + const base_uint operator-() const + { + base_uint ret; + for (int i = 0; i < WIDTH; i++) + ret.pn[i] = ~pn[i]; + ret++; + return ret; + } + + + base_uint& operator=(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + return *this; + } + + base_uint& operator^=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] ^= b.pn[i]; + return *this; + } + + base_uint& operator&=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] &= b.pn[i]; + return *this; + } + + base_uint& operator|=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] |= b.pn[i]; + return *this; + } + + base_uint& operator^=(uint64 b) + { + pn[0] ^= (unsigned int)b; + pn[1] ^= (unsigned int)(b >> 32); + return *this; + } + + base_uint& operator&=(uint64 b) + { + pn[0] &= (unsigned int)b; + pn[1] &= (unsigned int)(b >> 32); + return *this; + } + + base_uint& operator|=(uint64 b) + { + pn[0] |= (unsigned int)b; + pn[1] |= (unsigned int)(b >> 32); + return *this; + } + + base_uint& operator<<=(unsigned int shift) + { + base_uint a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) + { + if (i+k+1 < WIDTH && shift != 0) + pn[i+k+1] |= (a.pn[i] >> (32-shift)); + if (i+k < WIDTH) + pn[i+k] |= (a.pn[i] << shift); + } + return *this; + } + + base_uint& operator>>=(unsigned int shift) + { + base_uint a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) + { + if (i-k-1 >= 0 && shift != 0) + pn[i-k-1] |= (a.pn[i] << (32-shift)); + if (i-k >= 0) + pn[i-k] |= (a.pn[i] >> shift); + } + return *this; + } + + base_uint& operator+=(const base_uint& b) + { + uint64 carry = 0; + for (int i = 0; i < WIDTH; i++) + { + uint64 n = carry + pn[i] + b.pn[i]; + pn[i] = n & 0xffffffff; + carry = n >> 32; + } + return *this; + } + + base_uint& operator-=(const base_uint& b) + { + *this += -b; + return *this; + } + + base_uint& operator+=(uint64 b64) + { + base_uint b; + b = b64; + *this += b; + return *this; + } + + base_uint& operator-=(uint64 b64) + { + base_uint b; + b = b64; + *this += -b; + return *this; + } + + + base_uint& operator++() + { + // prefix operator + int i = 0; + while (++pn[i] == 0 && i < WIDTH-1) + i++; + return *this; + } + + const base_uint operator++(int) + { + // postfix operator + const base_uint ret = *this; + ++(*this); + return ret; + } + + base_uint& operator--() + { + // prefix operator + int i = 0; + while (--pn[i] == -1 && i < WIDTH-1) + i++; + return *this; + } + + const base_uint operator--(int) + { + // postfix operator + const base_uint ret = *this; + --(*this); + return ret; + } + + + friend inline bool operator<(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] < b.pn[i]) + return true; + else if (a.pn[i] > b.pn[i]) + return false; + } + return false; + } + + friend inline bool operator<=(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] < b.pn[i]) + return true; + else if (a.pn[i] > b.pn[i]) + return false; + } + return true; + } + + friend inline bool operator>(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] > b.pn[i]) + return true; + else if (a.pn[i] < b.pn[i]) + return false; + } + return false; + } + + friend inline bool operator>=(const base_uint& a, const base_uint& b) + { + for (int i = base_uint::WIDTH-1; i >= 0; i--) + { + if (a.pn[i] > b.pn[i]) + return true; + else if (a.pn[i] < b.pn[i]) + return false; + } + return true; + } + + friend inline bool operator==(const base_uint& a, const base_uint& b) + { + for (int i = 0; i < base_uint::WIDTH; i++) + if (a.pn[i] != b.pn[i]) + return false; + return true; + } + + friend inline bool operator==(const base_uint& a, uint64 b) + { + if (a.pn[0] != (unsigned int)b) + return false; + if (a.pn[1] != (unsigned int)(b >> 32)) + return false; + for (int i = 2; i < base_uint::WIDTH; i++) + if (a.pn[i] != 0) + return false; + return true; + } + + friend inline bool operator!=(const base_uint& a, const base_uint& b) + { + return (!(a == b)); + } + + friend inline bool operator!=(const base_uint& a, uint64 b) + { + return (!(a == b)); + } + + + + std::string GetHex() const + { + char psz[sizeof(pn)*2 + 1]; + for (int i = 0; i < sizeof(pn); i++) + sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); + return string(psz, psz + sizeof(pn)*2); + } + + void SetHex(const std::string& str) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + + // skip 0x + const char* psz = str.c_str(); + while (isspace(*psz)) + psz++; + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + while (isspace(*psz)) + psz++; + + // hex string to uint + static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + const char* pbegin = psz; + while (phexdigit[*psz] || *psz == '0') + psz++; + psz--; + unsigned char* p1 = (unsigned char*)pn; + unsigned char* pend = p1 + WIDTH * 4; + while (psz >= pbegin && p1 < pend) + { + *p1 = phexdigit[(unsigned char)*psz--]; + if (psz >= pbegin) + { + *p1 |= (phexdigit[(unsigned char)*psz--] << 4); + p1++; + } + } + } + + std::string ToString() const + { + return (GetHex()); + } + + unsigned char* begin() + { + return (unsigned char*)&pn[0]; + } + + unsigned char* end() + { + return (unsigned char*)&pn[WIDTH]; + } + + unsigned int size() + { + return sizeof(pn); + } + + + unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const + { + return sizeof(pn); + } + + template + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const + { + s.write((char*)pn, sizeof(pn)); + } + + template + void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) + { + s.read((char*)pn, sizeof(pn)); + } + + + friend class uint160; + friend class uint256; + friend inline int Testuint256AdHoc(vector vArg); +}; + +typedef base_uint<160> base_uint160; +typedef base_uint<256> base_uint256; + + + +// +// uint160 and uint256 could be implemented as templates, but to keep +// compile errors and debugging cleaner, they're copy and pasted. +// It's safe to search and replace 160 with 256 and vice versa. +// + + + +////////////////////////////////////////////////////////////////////////////// +// +// uint160 +// + +class uint160 : public base_uint160 +{ +public: + typedef base_uint160 basetype; + + uint160() + { + } + + uint160(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } + + uint160& operator=(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + return *this; + } + + uint160(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + } + + uint160& operator=(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + return *this; + } + + explicit uint160(const std::string& str) + { + SetHex(str); + } + + explicit uint160(const std::vector& vch) + { + if (vch.size() == sizeof(pn)) + memcpy(pn, &vch[0], sizeof(pn)); + else + *this = 0; + } +}; + +inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } +inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } +inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; } +inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; } +inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; } +inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; } + +inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } +inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } +inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } +inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; } +inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; } + +inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } +inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } +inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } +inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } +inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } +inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } + +inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; } +inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; } +inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; } +inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; } +inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; } +inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; } + +inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } +inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } +inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } +inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } +inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } +inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// uint256 +// + +class uint256 : public base_uint256 +{ +public: + typedef base_uint256 basetype; + + uint256() + { + } + + uint256(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } + + uint256& operator=(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + return *this; + } + + uint256(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + } + + uint256& operator=(uint64 b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + return *this; + } + + explicit uint256(const std::string& str) + { + SetHex(str); + } + + explicit uint256(const std::vector& vch) + { + if (vch.size() == sizeof(pn)) + memcpy(pn, &vch[0], sizeof(pn)); + else + *this = 0; + } +}; + +inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; } +inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; } +inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } +inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; } +inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; } +inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; } + +inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; } +inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; } +inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; } +inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; } +inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; } + +inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } +inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } +inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } +inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } +inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } +inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } +inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } +inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } +inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } +inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } +inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } + +inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; } +inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; } +inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; } +inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; } +inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; } +inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; } +inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; } +inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; } +inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; } +inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; } +inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; } + +inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } +inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } +inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } +inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } +inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } +inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } +inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } +inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } +inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } +inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } +inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } + + + + + + + + + + + + +inline int Testuint256AdHoc(vector vArg) +{ + uint256 g(0); + + + printf("%s\n", g.ToString().c_str()); + g--; printf("g--\n"); + printf("%s\n", g.ToString().c_str()); + g--; printf("g--\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + g++; printf("g++\n"); + printf("%s\n", g.ToString().c_str()); + + + + uint256 a(7); + printf("a=7\n"); + printf("%s\n", a.ToString().c_str()); + + uint256 b; + printf("b undefined\n"); + printf("%s\n", b.ToString().c_str()); + int c = 3; + + a = c; + a.pn[3] = 15; + printf("%s\n", a.ToString().c_str()); + uint256 k(c); + + a = 5; + a.pn[3] = 15; + printf("%s\n", a.ToString().c_str()); + b = 1; + b <<= 52; + + a |= b; + + a ^= 0x500; + + printf("a %s\n", a.ToString().c_str()); + + a = a | b | (uint256)0x1000; + + + printf("a %s\n", a.ToString().c_str()); + printf("b %s\n", b.ToString().c_str()); + + a = 0xfffffffe; + a.pn[4] = 9; + + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + a++; + printf("%s\n", a.ToString().c_str()); + + a--; + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + uint256 d = a--; + printf("%s\n", d.ToString().c_str()); + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + a--; + printf("%s\n", a.ToString().c_str()); + + d = a; + + printf("%s\n", d.ToString().c_str()); + for (int i = uint256::WIDTH-1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n"); + + uint256 neg = d; + neg = ~neg; + printf("%s\n", neg.ToString().c_str()); + + + uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111"); + printf("\n"); + printf("%s\n", e.ToString().c_str()); + + + printf("\n"); + uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111"); + uint256 x2; + printf("%s\n", x1.ToString().c_str()); + for (int i = 0; i < 270; i += 4) + { + x2 = x1 << i; + printf("%s\n", x2.ToString().c_str()); + } + + printf("\n"); + printf("%s\n", x1.ToString().c_str()); + for (int i = 0; i < 270; i += 4) + { + x2 = x1; + x2 >>= i; + printf("%s\n", x2.ToString().c_str()); + } + + + for (int i = 0; i < 100; i++) + { + uint256 k = (~uint256(0) >> i); + printf("%s\n", k.ToString().c_str()); + } + + for (int i = 0; i < 100; i++) + { + uint256 k = (~uint256(0) << i); + printf("%s\n", k.ToString().c_str()); + } + + return (0); +} diff --git a/uiproject.fbp b/uiproject.fbp new file mode 100644 index 000000000..49b1fefaa --- /dev/null +++ b/uiproject.fbp @@ -0,0 +1,11860 @@ + + + + + + C++ + 1 + UTF-8 + connect + uibase + 1000 + none + 0 + + + . + + 1 + 0 + 0 + + wxSYS_COLOUR_BTNFACE + + + 1 + + + + 0 + wxID_MAINFRAME + + + CMainFrameBase + + 705,484 + wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER + + Bitcoin + + + + wxTAB_TRAVERSAL + 1 + + + + OnClose + + + + + OnIdle + + + + + + + + + + + + OnMouseEvents + + OnPaint + + + + + + + + 240,240,240 + + 1 + + + 0 + wxID_ANY + MyMenuBar + + + m_menubar + protected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &File + m_menuFile + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + E&xit + m_menuFileExit + none + + + OnMenuFileExit + + + + + &Options + m_menuOptions + public + + + 0 + 1 + + wxID_OPTIONSGENERATEBITCOINS + wxITEM_CHECK + &Generate Coins + m_menuOptionsGenerateBitcoins + none + + + OnMenuOptionsGenerate + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + &Change Your Address... + m_menuChangeYourAddress + none + + + OnMenuOptionsChangeYourAddress + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + &Options... + m_menuOptionsOptions + none + + + OnMenuOptionsOptions + + + + + &Help + m_menuHelp + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + &About... + m_menuHelpAbout + none + + + OnMenuHelpAbout + + + + + + + 20,20 + + 1 + + ,90,90,-1,70,0 + 0 + wxID_ANY + + + + m_toolBar + 1 + protected + + 1 + -1,-1 + wxTB_FLAT|wxTB_HORZ_TEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + send20; Load From Resource + wxID_BUTTONSEND + wxITEM_NORMAL + &Send Coins + m_tool1 + + + + OnButtonSend + + + + + + addressbook20; Load From Resource + wxID_BUTTONRECEIVE + wxITEM_NORMAL + &Address Book + m_tool2 + + + + OnButtonAddressBook + + + + + + + 240,240,240 + + 1 + + 1 + + 0 + wxID_ANY + + + m_statusBar + protected + + + wxST_SIZEGRIP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer2 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 2 + protected + 0 + + + + 5 + wxEXPAND|wxRIGHT|wxLEFT + 0 + + + bSizer85 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Your Bitcoin Address: + + + m_staticText32 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + wxSYS_COLOUR_MENU + + 1 + + + 0 + wxID_TEXTCTRLADDRESS + -1,-1 + 0 + -1,-1 + m_textCtrlAddress + protected + + 250,-1 + wxTE_READONLY + + + + + + + + + + OnKeyDown + + + + + + + + + + + OnMouseEventsAddress + + + + + + OnSetFocusAddress + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONCOPY + &Copy to Clipboard + + + m_buttonCopy + protected + + + wxBU_EXACTFIT + + + + + + OnButtonCopy + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxRIGHT + 0 + + + + 0 + 1 + + + 1 + wxID_BUTTONCHANGE + C&hange... + + + m_button91 + protected + + + + + + + + + OnButtonChange + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 0 + protected + 0 + + + + + + 5 + wxEXPAND + 0 + + + bSizer3 + wxHORIZONTAL + none + + 5 + wxEXPAND|wxALIGN_BOTTOM|wxALL + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_panel14 + protected + + + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer66 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Balance: + + + m_staticText41 + protected + + -1,15 + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + wxSYS_COLOUR_WINDOW + + 1 + + ,90,90,8,70,0 + 0 + wxID_ANY + + + + m_staticTextBalance + protected + + 120,15 + wxALIGN_RIGHT|wxST_NO_AUTORESIZE + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 0 + protected + 0 + + + + 5 + wxALIGN_BOTTOM|wxTOP|wxRIGHT|wxLEFT + 0 + + + " All" " Sent" " Received" " In Progress" + + 1 + + + 1 + wxID_ANY + + + m_choiceFilter + protected + + 0 + 110,-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + + + 1 + + + 0 + wxID_ANY + + + m_notebook + protected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + All Transactions + 0 + + + + 1 + + + 0 + wxID_ANY + + + m_panel7 + protected + + + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer157 + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_listCtrl + public + + + wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_DESCENDING + + + + + wxALWAYS_SHOW_SB + + + + + + + + + + + + + + + OnListColBeginDrag + + + + + + + + + OnListItemActivatedAllTransactions + + + + + + + + + + + + + OnPaintListCtrl + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer_TabsForFutureUse + wxVERTICAL + none + + 5 + wxEXPAND | wxALL + 1 + + + + 1 + + + 1 + wxID_ANY + + + m_panel9 + protected + + + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer159 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_listCtrlEscrows + public + + + wxLC_NO_SORT_HEADER|wxLC_REPORT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 1 + + + + 1 + + + 1 + wxID_ANY + + + m_panel8 + protected + + + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer158 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_listCtrlOrdersSent + public + + + wxLC_NO_SORT_HEADER|wxLC_REPORT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListItemActivatedOrdersSent + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 1 + + + + 1 + + + 1 + wxID_ANY + + + m_panel10 + protected + + + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer160 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_listCtrlProductsSent + public + + + wxLC_NO_SORT_HEADER|wxLC_REPORT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListItemActivatedProductsSent + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 1 + + + + 1 + + + 1 + wxID_ANY + + + m_panel11 + protected + + + + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer161 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_listCtrlOrdersReceived + public + + + wxLC_NO_SORT_HEADER|wxLC_REPORT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListItemActivatedOrdersReceived + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CTxDetailsDialogBase + + 620,450 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Transaction Details + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer64 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizer66 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_htmlWin + protected + + + wxHW_SCROLLBAR_AUTO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bSizer65 + wxVERTICAL + none + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OK + OK + + + m_buttonOK + protected + + 85,25 + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + COptionsDialogBase + + 500,261 + wxDEFAULT_DIALOG_STYLE + + Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer55 + wxVERTICAL + none + + 5 + wxEXPAND|wxLEFT + 1 + + + bSizer57 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 20 + protected + 0 + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + + + 1 + + + 0 + wxID_ANY + Optional transaction fee you give to the nodes that process your transactions. + + + m_staticText32 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer56 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Transaction fee: + + + m_staticText31 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_TRANSACTIONFEE + + 0 + + m_textCtrlTransactionFee + protected + + 70,-1 + + + + + + + + + + + + + OnKillFocusTransactionFee + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bSizer58 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OK + OK + + + m_buttonOK + protected + + 85,25 + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + -1,-1 + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CAboutDialogBase + + 507,298 + wxDEFAULT_DIALOG_STYLE + + About Bitcoin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer60 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizer62 + wxHORIZONTAL + none + + 5 + wxEXPAND + 0 + + 0 + protected + 60 + + + + 5 + wxEXPAND + 1 + + + bSizer63 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 50 + protected + 0 + + + + 5 + wxEXPAND + 0 + + + bSizer64 + wxHORIZONTAL + none + + 5 + wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + Tahoma,90,92,10,74,0 + 0 + wxID_ANY + Bitcoin + + + m_staticText40 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxRIGHT + 0 + + + + 1 + + Tahoma,90,90,10,74,0 + 0 + wxID_ANY + version + + + m_staticTextVersion + public + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 4 + protected + 0 + + + + 5 + wxALL + 0 + + + + 1 + + + 0 + wxID_ANY + Copyright © 2009 Satoshi Nakamoto. This is experimental software. Do not rely on it for actual financial transactions. Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com). + + + m_staticTextMain + protected + + + + + + + + + 400 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer61 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OK + OK + + + m_buttonOK + protected + + 85,25 + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CSendDialogBase + + 675,312 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Send Coins + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer21 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 5 + protected + 0 + + + + 5 + wxEXPAND|wxLEFT + 0 + + 2 + wxBOTH + 1 + + 0 + + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 3 + 0 + + 5 + wxEXPAND + 0 + + 0 + protected + 0 + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Enter the recipient's IP address (e.g. 123.45.6.7) for online transfer with comments and confirmation, or Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) if recipient is not online. + + + m_staticText14 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxLEFT + 1 + + 70,-1 + bSizer47 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + check; Load From Icon Resource [-1; -1] + + 1 + + + 0 + wxID_ANY + + + m_bitmapCheckMark + protected + + 16,16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Pay &To: + + + m_staticText36 + protected + + -1,-1 + wxALIGN_RIGHT + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT + 1 + + + bSizer19 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 1 + + + + 1 + + + 0 + wxID_TEXTCTRLPAYTO + + 0 + + m_textCtrlAddress + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + OnTextAddress + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONPASTE + &Paste + + + m_buttonPaste + protected + + -1,-1 + wxBU_EXACTFIT + + + + + + OnButtonPaste + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONADDRESSBOOK + Address &Book... + + + m_buttonAddress + protected + + + + + + + + + OnButtonAddressBook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT|wxALIGN_RIGHT + 0 + + + + 1 + + + 0 + wxID_ANY + &Amount: + + + m_staticText19 + protected + + -1,-1 + wxALIGN_RIGHT + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + + + 1 + + ,90,90,-1,70,0 + 0 + wxID_TEXTCTRLAMOUNT + + 20 + + m_textCtrlAmount + protected + + 145,-1 + + + + + + + + + + + OnKeyDown + + OnKillFocusAmount + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 1 + wxID_ANY + T&ransfer: + + + m_staticText20 + protected + + -1,-1 + wxALIGN_RIGHT + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + + " Standard" + + 1 + + + 1 + wxID_CHOICETRANSFERTYPE + + + m_choiceTransferType + protected + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 3 + protected + 0 + + + + 5 + wxEXPAND + 0 + + 0 + protected + 0 + + + + + + 5 + wxEXPAND + 0 + + + bSizer672 + wxHORIZONTAL + none + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + + bSizer681 + wxVERTICAL + none + + 5 + wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + &From: + + + m_staticTextFrom + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxLEFT|wxEXPAND + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + + m_textCtrlFrom + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer67 + wxHORIZONTAL + none + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + + bSizer68 + wxVERTICAL + none + + 5 + wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + &Message: + + + m_staticTextMessage + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxLEFT + 1 + + + + 1 + + + 0 + wxID_ANY + + 0 + + m_textCtrlMessage + protected + + + wxTE_MULTILINE + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer23 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + + + 0 + 1 + + ,90,90,-1,70,0 + 0 + wxID_BUTTONSEND + &Send + + 85,25 + m_buttonSend + protected + + -1,-1 + + + + + + + OnButtonSend + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + -1,-1 + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CSendingDialogBase + + 442,151 + wxDEFAULT_DIALOG_STYLE + + Sending... + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + OnPaint + + + + + + + + + bSizer68 + wxVERTICAL + none + + 8 + wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + + + + m_staticTextSending + protected + + -1,14 + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxEXPAND|wxRIGHT|wxLEFT + 1 + + wxSYS_COLOUR_BTNFACE + + 1 + + + 0 + wxID_ANY + + 0 + + m_textCtrlStatus + protected + + + wxTE_CENTRE|wxTE_MULTILINE|wxTE_NO_VSCROLL|wxTE_READONLY + + + Connecting... + + + wxNO_BORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer69 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + + + 0 + 0 + + + 0 + wxID_ANY + OK + + 85,25 + m_buttonOK + protected + + + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + -1,-1 + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CYourAddressDialogBase + + 610,390 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Your Bitcoin Addresses + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer68 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 5 + protected + 0 + + + + 5 + wxALL + 0 + + + + 1 + + + 0 + wxID_ANY + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window. + + + m_staticText45 + protected + + + + + + + + + 590 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_LISTCTRL + + + m_listCtrl + protected + + + wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_ASCENDING + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListEndLabelEdit + + OnListItemActivated + + + + + OnListItemSelected + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer69 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONRENAME + &Edit... + + 85,25 + m_buttonRename + protected + + + + + + + + + OnButtonRename + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONNEW + &New Address... + + 110,25 + m_buttonNew + protected + + -1,-1 + + + + + + + OnButtonNew + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONCOPY + &Copy to Clipboard + + 120,25 + m_buttonCopy + protected + + -1,-1 + + + + + + + OnButtonCopy + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OK + OK + + 85,25 + m_buttonOK + protected + + + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 1 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + -1,-1 + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CAddressBookDialogBase + + 610,390 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Address Book + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer68 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 5 + protected + 0 + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 1 + wxID_ANY + Bitcoin Address + + + m_staticText55 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_LISTCTRL + + + m_listCtrl + protected + + + wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_ASCENDING + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListEndLabelEdit + + OnListItemActivated + + + + + OnListItemSelected + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer69 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONEDIT + &Edit... + + 85,25 + m_buttonEdit + protected + + + + + + + + + OnButtonEdit + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONNEW + &New Address... + + 110,25 + m_buttonNew + protected + + + + + + + + + OnButtonNew + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONDELETE + &Delete + + 85,25 + m_buttonDelete + protected + + + + + + + + + OnButtonDelete + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OK + OK + + 85,25 + m_buttonOK + protected + + -1,-1 + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + public + + -1,-1 + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CProductsDialogBase + + 708,535 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Marketplace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer22 + wxVERTICAL + none + + 5 + wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT + 0 + + + bSizer23 + wxHORIZONTAL + none + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + "(Any Category)" + + 1 + + + 0 + wxID_ANY + + + m_comboBoxCategory + protected + + 150,-1 + + + + (Any Category) + + + + + OnCombobox + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 1 + + + + 1 + + + 0 + wxID_ANY + + 0 + + m_textCtrlSearch + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 0 + 1 + + + 0 + wxID_ANY + &Search + + + m_buttonSearch + protected + + + + + + + + + OnButtonSearch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_listCtrl + protected + + + wxLC_NO_SORT_HEADER|wxLC_REPORT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListItemActivated + + + + + + + + + + + + + + + + + + + + + + + + + wxSYS_COLOUR_MENU + + + 1 + + + + 0 + wxID_ANY + + + CEditProductDialogBase + + 660,640 + wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER + + Edit Product + + + + wxTAB_TRAVERSAL + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer20 + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 1 + + wxSYS_COLOUR_WINDOW + + 1 + + + 0 + wxID_ANY + + + m_scrolledWindow + protected + + 5 + 5 + + + + + + wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer21 + wxVERTICAL + none + + 5 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 2 + wxBOTH + 1 + + 0 + + fgSizer8 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Category + + + m_staticText106 + protected + + + wxALIGN_RIGHT + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + + 1 + + + 0 + wxID_ANY + + 180,-1 + m_comboBoxCategory + protected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Title + + + m_staticText108 + protected + + + wxALIGN_RIGHT + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + 0 + + m_textCtrlTitle + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Price + + + m_staticText107 + protected + + + wxALIGN_RIGHT + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 105,-1 + m_textCtrlPrice + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Page 1: Description + + + m_staticText22 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + -1,170 + m_textCtrlDescription + protected + + + wxTE_MULTILINE + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Page 2: Order Form + + + m_staticText23 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + -1,120 + m_textCtrlInstructions + protected + + + wxTE_MULTILINE + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 3 + wxBOTH + 1 + + 0 + + fgSizer5 + wxFLEX_GROWMODE_SPECIFIED + public + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Label + + + m_staticText24 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Comma separated list of choices, or leave blank for text field + + + m_staticText25 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel0 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField0 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL + 0 + + + + 0 + 1 + + + 0 + wxID_DEL0 + Delete + + -1,-1 + m_buttonDel0 + protected + + 60,20 + + + + + + + OnButtonDel0 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel1 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField1 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL1 + Delete + + -1,-1 + m_buttonDel1 + protected + + 60,20 + + + + + + + OnButtonDel1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel2 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField2 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL2 + Delete + + -1,-1 + m_buttonDel2 + protected + + 60,20 + + + + + + + OnButtonDel2 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel3 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField3 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL3 + Delete + + -1,-1 + m_buttonDel3 + protected + + 60,20 + + + + + + + OnButtonDel3 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel4 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField4 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL4 + Delete + + -1,-1 + m_buttonDel4 + protected + + 60,20 + + + + + + + OnButtonDel4 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel5 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField5 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL5 + Delete + + -1,-1 + m_buttonDel5 + protected + + 60,20 + + + + + + + OnButtonDel5 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel6 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField6 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL6 + Delete + + -1,-1 + m_buttonDel6 + protected + + 60,20 + + + + + + + OnButtonDel6 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel7 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField7 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL7 + Delete + + -1,-1 + m_buttonDel7 + protected + + 60,20 + + + + + + + OnButtonDel7 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel8 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField8 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL8 + Delete + + -1,-1 + m_buttonDel8 + protected + + 60,20 + + + + + + + OnButtonDel8 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel9 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField9 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL9 + Delete + + -1,-1 + m_buttonDel9 + protected + + 60,20 + + + + + + + OnButtonDel9 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel10 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField10 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL10 + Delete + + -1,-1 + m_buttonDel10 + protected + + 60,20 + + + + + + + OnButtonDel10 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel11 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField11 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL11 + Delete + + -1,-1 + m_buttonDel11 + protected + + 60,20 + + + + + + + OnButtonDel11 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel12 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField12 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL12 + Delete + + -1,-1 + m_buttonDel12 + protected + + 60,20 + + + + + + + OnButtonDel12 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel13 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField13 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL13 + Delete + + -1,-1 + m_buttonDel13 + protected + + 60,20 + + + + + + + OnButtonDel13 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel14 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField14 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL14 + Delete + + -1,-1 + m_buttonDel14 + protected + + 60,20 + + + + + + + OnButtonDel14 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel15 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField15 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL15 + Delete + + -1,-1 + m_buttonDel15 + protected + + 60,20 + + + + + + + OnButtonDel15 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel16 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField16 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL16 + Delete + + -1,-1 + m_buttonDel16 + protected + + 60,20 + + + + + + + OnButtonDel16 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel17 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField17 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL17 + Delete + + -1,-1 + m_buttonDel17 + protected + + 60,20 + + + + + + + OnButtonDel17 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel18 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField18 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL18 + Delete + + -1,-1 + m_buttonDel18 + protected + + 60,20 + + + + + + + OnButtonDel18 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + + 0 + 150,-1 + m_textCtrlLabel19 + protected + + + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + -1,-1 + 0 + -1,-1 + m_textCtrlField19 + protected + + -1,-1 + + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + + + 0 + 1 + + + 0 + wxID_DEL19 + Delete + + -1,-1 + m_buttonDel19 + protected + + 60,20 + + + + + + + OnButtonDel19 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_HORIZONTAL + 0 + + + bSizer25 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_ANY + &Add Field + + + m_buttonAddField + protected + + + + + + + + + OnButtonAddField + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bSizer26 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONSEND + &Send + + 85,25 + m_buttonOK + protected + + + + + + + + + OnButtonSend + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONPREVIEW + &Preview + + 85,25 + m_buttonPreview + protected + + + + + + + + + OnButtonPreview + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wxSYS_COLOUR_MENU + + + 1 + + + + 0 + wxID_ANY + + + CViewProductDialogBase + + 630,520 + wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER + + Order Form + + + + wxTAB_TRAVERSAL + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer20 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizer116 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 1 + wxID_ANY + + + m_htmlWinReviews + protected + + + wxHW_SCROLLBAR_AUTO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 1 + + wxSYS_COLOUR_WINDOW + + 1 + + + 0 + wxID_ANY + + + m_scrolledWindow + protected + + 5 + 5 + + + + + + wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer21 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + + + 1 + + + 0 + wxID_ANY + + -1,-1 + m_richTextHeading + protected + + -1,50 + wxTE_READONLY + + + + + wxNO_BORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + + + 1 + + + 0 + wxID_ANY + Order Form instructions here multiple lines 1 2 3 4 5 6 + + + m_staticTextInstructions + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_HORIZONTAL + 0 + + + bSizer25 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONSAMPLE + &Submit + + -1,-1 + m_buttonSubmitForm + protected + + + + + + + + + OnButtonSubmitForm + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL2 + Cancel + + + m_buttonCancelForm + protected + + + + + + + + + OnButtonCancelForm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bSizer26 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + + 0 + 0 + + + 0 + wxID_BUTTONBACK + < &Back + + 85,25 + m_buttonBack + protected + + + + + + + + + OnButtonBack + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_BUTTONNEXT + &Next > + + 85,25 + m_buttonNext + protected + + + + + + + + + OnButtonNext + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wxSYS_COLOUR_MENU + + + 1 + + + + 0 + wxID_ANY + + + CViewOrderDialogBase + + 630,520 + wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER + + View Order + + + + wxTAB_TRAVERSAL + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer20 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizer116 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_htmlWin + protected + + + wxHW_SCROLLBAR_AUTO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bSizer26 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OK + OK + + 85,25 + m_buttonOK + protected + + + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wxSYS_COLOUR_MENU + + + 1 + + + + 0 + wxID_ANY + + + CEditReviewDialogBase + + 630,440 + wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER + + Enter Review + + + + wxTAB_TRAVERSAL + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer112 + wxVERTICAL + none + + 5 + + 0 + + 3 + protected + 0 + + + + 5 + wxALL|wxEXPAND + 0 + + + + 1 + + + 0 + wxID_ANY + + + + m_staticTextSeller + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + 0 + + 3 + protected + 0 + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Rating + + + m_staticText110 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + " 1 star" " 2 stars" " 3 stars" " 4 stars" " 5 stars" + + 1 + + + 0 + wxID_ANY + + + m_choiceStars + protected + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + Review + + + m_staticText43 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + + + 0 + wxID_ANY + + 0 + + m_textCtrlReview + protected + + + wxTE_MULTILINE + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + + bSizer113 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_SUBMIT + &Submit + + 85,25 + m_buttonSubmit + protected + + + + + + + + + OnButtonSubmit + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wxSYS_COLOUR_BTNFACE + + + 1 + + + + 0 + wxID_ANY + + + CPokerLobbyDialogBase + + 586,457 + wxDEFAULT_FRAME_STYLE + + Poker Lobby + + + + wxTAB_TRAVERSAL + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer156 + wxHORIZONTAL + none + + 5 + wxEXPAND|wxTOP|wxBOTTOM|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + + 130,-1 + m_treeCtrl + protected + + + wxTR_HAS_BUTTONS|wxTR_HIDE_ROOT|wxTR_LINES_AT_ROOT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnTreeSelChanged + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer172 + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_listCtrl + protected + + + wxLC_NO_SORT_HEADER|wxLC_REPORT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnListItemActivated + + + + + OnListItemSelected + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OPENNEWTABLE + &Open New Table + + + m_buttonNewTable + protected + + + + + + + + + OnButtonNewTable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CPokerDialogBase + + 806,550 + wxDEFAULT_FRAME_STYLE|wxFRAME_NO_TASKBAR + + Poker + + + + wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL + 1 + + + + OnClose + + + + + + + + + + + + + + + + + OnMouseEvents + + OnPaint + + + + + OnSize + + + + bSizer174 + wxVERTICAL + none + + 5 + wxALL + 0 + + + 0 + + 1 + + + 0 + wxID_ANY + Deal Me Out + + + m_checkSitOut + public + + + + + + + + + + OnCheckSitOut + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_DEALHAND + &Deal Hand + + + m_buttonDealHand + protected + + 150,25 + + + + + + + OnButtonDealHand + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_FOLD + &Fold + + + m_buttonFold + protected + + 80,25 + + + + + + + OnButtonFold + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CALL + &Call + + + m_buttonCall + protected + + 80,25 + + + + + + + OnButtonCall + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_RAISE + &Raise + + + m_buttonRaise + protected + + 80,25 + + + + + + + OnButtonRaise + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_LEAVETABLE + &Leave Table + + + m_buttonLeaveTable + protected + + 90,25 + + + + + + + OnButtonLeaveTable + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 1 + + + 0 + wxID_DITCHPLAYER + + 0 + + m_textDitchPlayer + protected + + 45,-1 + wxTE_PROCESS_ENTER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnDitchPlayer + + + + + + + 5 + wxALL + 0 + + + 0 + + 1 + + + 0 + wxID_ANY + FOLD + + + m_checkPreFold + public + + 100,-1 + + + + + + + + OnCheckPreFold + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + 0 + + 1 + + + 0 + wxID_ANY + CALL + + + m_checkPreCall + public + + 100,-1 + + + + + + + + OnCheckPreCall + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + 0 + + 1 + + + 0 + wxID_ANY + CALL ANY + + + m_checkPreCallAny + public + + 100,-1 + + + + + + + + OnCheckPreCallAny + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + 0 + + 1 + + + 0 + wxID_ANY + RAISE + + + m_checkPreRaise + public + + 100,-1 + + + + + + + + OnCheckPreRaise + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + 0 + + 1 + + + 0 + wxID_ANY + RAISE ANY + + + m_checkPreRaiseAny + public + + 100,-1 + + + + + + + + OnCheckPreRaiseAny + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + 1 + + 0 + wxID_ANY + + + m_statusBar + public + + + wxST_SIZEGRIP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 0 + wxID_ANY + + + CGetTextFromUserDialogBase + + 403,138 + wxDEFAULT_DIALOG_STYLE + + + + + + + + + + OnClose + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer79 + wxVERTICAL + none + + 10 + wxEXPAND|wxALL + 1 + + + bSizer81 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 0 + wxID_ANY + + + + m_staticTextMessage1 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL + 0 + + + + 1 + + + 0 + wxID_TEXTCTRL + + 0 + + m_textCtrl1 + protected + + + wxTE_PROCESS_ENTER + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + + + 1 + + + 1 + wxID_ANY + + + + m_staticTextMessage2 + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL + 0 + + + + 1 + + + 1 + wxID_TEXTCTRL + + 0 + + m_textCtrl2 + protected + + + wxTE_PROCESS_ENTER + + + + + + + + + + OnKeyDown + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + 5 + wxEXPAND + 0 + + + bSizer80 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_OK + OK + + 85,25 + m_buttonOK + protected + + -1,-1 + + + + + + + OnButtonOK + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + + + 0 + 1 + + + 0 + wxID_CANCEL + Cancel + + 85,25 + m_buttonCancel + protected + + + + + + + + + OnButtonCancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/util.cpp b/util.cpp new file mode 100644 index 000000000..9c0ab142e --- /dev/null +++ b/util.cpp @@ -0,0 +1,383 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "headers.h" + + + +bool fDebug = false; + + + + +// Init openssl library multithreading support +static HANDLE* lock_cs; + +void win32_locking_callback(int mode, int type, const char* file, int line) +{ + if (mode & CRYPTO_LOCK) + WaitForSingleObject(lock_cs[type], INFINITE); + else + ReleaseMutex(lock_cs[type]); +} + +// Init +class CInit +{ +public: + CInit() + { + // Init openssl library multithreading support + lock_cs = (HANDLE*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(HANDLE)); + for (int i = 0; i < CRYPTO_num_locks(); i++) + lock_cs[i] = CreateMutex(NULL,FALSE,NULL); + CRYPTO_set_locking_callback(win32_locking_callback); + + // Seed random number generator with screen scrape and other hardware sources + RAND_screen(); + + // Seed random number generator with perfmon data + RandAddSeed(true); + } + ~CInit() + { + // Shutdown openssl library multithreading support + CRYPTO_set_locking_callback(NULL); + for (int i =0 ; i < CRYPTO_num_locks(); i++) + CloseHandle(lock_cs[i]); + OPENSSL_free(lock_cs); + } +} +instance_of_cinit; + + + + +void RandAddSeed(bool fPerfmon) +{ + // Seed with CPU performance counter + LARGE_INTEGER PerformanceCount; + QueryPerformanceCounter(&PerformanceCount); + RAND_add(&PerformanceCount, sizeof(PerformanceCount), 1.5); + memset(&PerformanceCount, 0, sizeof(PerformanceCount)); + + static int64 nLastPerfmon; + if (fPerfmon || GetTime() > nLastPerfmon + 5 * 60) + { + nLastPerfmon = GetTime(); + + // Seed with the entire set of perfmon data + unsigned char pdata[250000]; + memset(pdata, 0, sizeof(pdata)); + unsigned long nSize = sizeof(pdata); + long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize); + RegCloseKey(HKEY_PERFORMANCE_DATA); + if (ret == ERROR_SUCCESS) + { + uint256 hash; + SHA256(pdata, nSize, (unsigned char*)&hash); + RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash))); + hash = 0; + memset(pdata, 0, nSize); + + time_t nTime; + time(&nTime); + struct tm* ptmTime = gmtime(&nTime); + char pszTime[200]; + strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime); + printf("%s RandAddSeed() got %d bytes of performance data\n", pszTime, nSize); + } + } +} + + + + + + + + + + +// Safer snprintf +// - prints up to limit-1 characters +// - output string is always null terminated even if limit reached +// - return value is the number of characters actually printed +int my_snprintf(char* buffer, size_t limit, const char* format, ...) +{ + if (limit == 0) + return 0; + va_list arg_ptr; + va_start(arg_ptr, format); + int ret = _vsnprintf(buffer, limit, format, arg_ptr); + va_end(arg_ptr); + if (ret < 0 || ret >= limit) + { + ret = limit - 1; + buffer[limit-1] = 0; + } + return ret; +} + + +string strprintf(const char* format, ...) +{ + char buffer[50000]; + char* p = buffer; + int limit = sizeof(buffer); + int ret; + loop + { + va_list arg_ptr; + va_start(arg_ptr, format); + ret = _vsnprintf(p, limit, format, arg_ptr); + va_end(arg_ptr); + if (ret >= 0 && ret < limit) + break; + if (p != buffer) + delete p; + limit *= 2; + p = new char[limit]; + if (p == NULL) + throw std::bad_alloc(); + } +#ifdef _MSC_VER + // msvc optimisation + if (p == buffer) + return string(p, p+ret); +#endif + string str(p, p+ret); + if (p != buffer) + delete p; + return str; +} + + +bool error(const char* format, ...) +{ + char buffer[50000]; + int limit = sizeof(buffer); + va_list arg_ptr; + va_start(arg_ptr, format); + int ret = _vsnprintf(buffer, limit, format, arg_ptr); + va_end(arg_ptr); + if (ret < 0 || ret >= limit) + { + ret = limit - 1; + buffer[limit-1] = 0; + } + printf("ERROR: %s\n", buffer); + return false; +} + + +void PrintException(std::exception* pex, const char* pszThread) +{ + char pszModule[260]; + pszModule[0] = '\0'; + GetModuleFileName(NULL, pszModule, sizeof(pszModule)); + _strlwr(pszModule); + char pszMessage[1000]; + if (pex) + snprintf(pszMessage, sizeof(pszMessage), + "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); + else + snprintf(pszMessage, sizeof(pszMessage), + "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); + printf("\n\n************************\n%s", pszMessage); + if (wxTheApp) + wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR); + throw; + //DebugBreak(); +} + + +void ParseString(const string& str, char c, vector& v) +{ + unsigned int i1 = 0; + unsigned int i2; + do + { + i2 = str.find(c, i1); + v.push_back(str.substr(i1, i2-i1)); + i1 = i2+1; + } + while (i2 != str.npos); +} + + +string FormatMoney(int64 n, bool fPlus) +{ + n /= CENT; + string str = strprintf("%I64d.%02I64d", (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100); + for (int i = 6; i < str.size(); i += 4) + if (isdigit(str[str.size() - i - 1])) + str.insert(str.size() - i, 1, ','); + if (n < 0) + str.insert((unsigned int)0, 1, '-'); + else if (fPlus && n > 0) + str.insert((unsigned int)0, 1, '+'); + return str; +} + +bool ParseMoney(const char* pszIn, int64& nRet) +{ + string strWhole; + int64 nCents = 0; + const char* p = pszIn; + while (isspace(*p)) + p++; + for (; *p; p++) + { + if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4])) + continue; + if (*p == '.') + { + p++; + if (isdigit(*p)) + { + nCents = 10 * (*p++ - '0'); + if (isdigit(*p)) + nCents += (*p++ - '0'); + } + break; + } + if (isspace(*p)) + break; + if (!isdigit(*p)) + return false; + strWhole.insert(strWhole.end(), *p); + } + for (; *p; p++) + if (!isspace(*p)) + return false; + if (strWhole.size() > 14) + return false; + if (nCents < 0 || nCents > 99) + return false; + int64 nWhole = atoi64(strWhole); + int64 nPreValue = nWhole * 100 + nCents; + int64 nValue = nPreValue * CENT; + if (nValue / CENT != nPreValue) + return false; + if (nValue / COIN != nWhole) + return false; + nRet = nValue; + return true; +} + + + + + + + + + + +bool FileExists(const char* psz) +{ +#ifdef WIN32 + return GetFileAttributes(psz) != -1; +#else + return access(psz, 0) != -1; +#endif +} + +int GetFilesize(FILE* file) +{ + int nSavePos = ftell(file); + int nFilesize = -1; + if (fseek(file, 0, SEEK_END) == 0) + nFilesize = ftell(file); + fseek(file, nSavePos, SEEK_SET); + return nFilesize; +} + + + + + + + + +uint64 GetRand(uint64 nMax) +{ + if (nMax == 0) + return 0; + + // The range of the random source must be a multiple of the modulus + // to give every possible output value an equal possibility + uint64 nRange = (_UI64_MAX / nMax) * nMax; + uint64 nRand = 0; + do + RAND_bytes((unsigned char*)&nRand, sizeof(nRand)); + while (nRand >= nRange); + return (nRand % nMax); +} + + + + + + + + + + +// +// "Never go to sea with two chronometers; take one or three." +// Our three chronometers are: +// - System clock +// - Median of other server's clocks +// - NTP servers +// +// note: NTP isn't implemented yet, so until then we just use the median +// of other nodes clocks to correct ours. +// + +int64 GetTime() +{ + return time(NULL); +} + +static int64 nTimeOffset = 0; + +int64 GetAdjustedTime() +{ + return GetTime() + nTimeOffset; +} + +void AddTimeData(unsigned int ip, int64 nTime) +{ + int64 nOffsetSample = nTime - GetTime(); + + // Ignore duplicates + static set setKnown; + if (!setKnown.insert(ip).second) + return; + + // Add data + static vector vTimeOffsets; + if (vTimeOffsets.empty()) + vTimeOffsets.push_back(0); + vTimeOffsets.push_back(nOffsetSample); + printf("Added time data, samples %d, ip %08x, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), ip, vTimeOffsets.back(), vTimeOffsets.back()/60); + if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) + { + sort(vTimeOffsets.begin(), vTimeOffsets.end()); + int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2]; + nTimeOffset = nMedian; + if ((nMedian > 0 ? nMedian : -nMedian) > 5 * 60) + { + // Only let other nodes change our clock so far before we + // go to the NTP servers + /// todo: Get time from NTP servers, then set a flag + /// to make sure it doesn't get changed again + } + foreach(int64 n, vTimeOffsets) + printf("%+I64d ", n); + printf("| nTimeOffset = %+I64d (%+I64d minutes)\n", nTimeOffset, nTimeOffset/60); + } +} diff --git a/util.h b/util.h new file mode 100644 index 000000000..97617ab49 --- /dev/null +++ b/util.h @@ -0,0 +1,399 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int64; +typedef unsigned long long uint64; +#endif +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define for if (false) ; else for +#endif + +#ifndef _MSC_VER +#define __forceinline inline +#endif + +#define foreach BOOST_FOREACH +#define loop for (;;) +#define BEGIN(a) ((char*)&(a)) +#define END(a) ((char*)&((&(a))[1])) +#define UBEGIN(a) ((unsigned char*)&(a)) +#define UEND(a) ((unsigned char*)&((&(a))[1])) +#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) + +#ifdef _WINDOWS +#define printf OutputDebugStringF +#endif + +#ifdef snprintf +#undef snprintf +#endif +#define snprintf my_snprintf + +#ifndef PRId64 +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MSVCRT__) +#define PRId64 "I64d" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#else +#define PRId64 "lld" +#define PRIu64 "llu" +#define PRIx64 "llx" +#endif +#endif + +// This is needed because the foreach macro can't get over the comma in pair +#define PAIRTYPE(t1, t2) pair + +// Used to bypass the rule against non-const reference to temporary +// where it makes sense with wrappers such as CFlatData or CTxDB +template +inline T& REF(const T& val) +{ + return (T&)val; +} + + + + + + + + + +extern bool fDebug; + +void RandAddSeed(bool fPerfmon=false); +int my_snprintf(char* buffer, size_t limit, const char* format, ...); +string strprintf(const char* format, ...); +bool error(const char* format, ...); +void PrintException(std::exception* pex, const char* pszThread); +void ParseString(const string& str, char c, vector& v); +string FormatMoney(int64 n, bool fPlus=false); +bool ParseMoney(const char* pszIn, int64& nRet); +bool FileExists(const char* psz); +int GetFilesize(FILE* file); +uint64 GetRand(uint64 nMax); +int64 GetTime(); +int64 GetAdjustedTime(); +void AddTimeData(unsigned int ip, int64 nTime); + + + + + + + + + + + + +// Wrapper to automatically initialize critical section +// Could use wxCriticalSection for portability, but it doesn't support TryEnterCriticalSection +class CCriticalSection +{ +protected: + CRITICAL_SECTION cs; +public: + char* pszFile; + int nLine; + explicit CCriticalSection() { InitializeCriticalSection(&cs); } + ~CCriticalSection() { DeleteCriticalSection(&cs); } + void Enter() { EnterCriticalSection(&cs); } + void Leave() { LeaveCriticalSection(&cs); } + bool TryEnter() { return TryEnterCriticalSection(&cs); } + CRITICAL_SECTION* operator&() { return &cs; } +}; + +// Automatically leave critical section when leaving block, needed for exception safety +class CCriticalBlock +{ +protected: + CRITICAL_SECTION* pcs; +public: + CCriticalBlock(CRITICAL_SECTION& csIn) { pcs = &csIn; EnterCriticalSection(pcs); } + CCriticalBlock(CCriticalSection& csIn) { pcs = &csIn; EnterCriticalSection(pcs); } + ~CCriticalBlock() { LeaveCriticalSection(pcs); } +}; + +// WARNING: This will catch continue and break! +// break is caught with an assertion, but there's no way to detect continue. +// I'd rather be careful than suffer the other more error prone syntax. +// The compiler will optimise away all this loop junk. +#define CRITICAL_BLOCK(cs) \ + for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \ + for (CCriticalBlock criticalblock(cs); fcriticalblockonce && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0) + +class CTryCriticalBlock +{ +protected: + CRITICAL_SECTION* pcs; +public: + CTryCriticalBlock(CRITICAL_SECTION& csIn) { pcs = (TryEnterCriticalSection(&csIn) ? &csIn : NULL); } + CTryCriticalBlock(CCriticalSection& csIn) { pcs = (TryEnterCriticalSection(&csIn) ? &csIn : NULL); } + ~CTryCriticalBlock() { if (pcs) LeaveCriticalSection(pcs); } + bool Entered() { return pcs != NULL; } +}; + +#define TRY_CRITICAL_BLOCK(cs) \ + for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by TRY_CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \ + for (CTryCriticalBlock criticalblock(cs); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()) && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0) + + + + + + + + + + + + +inline string i64tostr(int64 n) +{ + return strprintf("%"PRId64, n); +} + +inline string itostr(int n) +{ + return strprintf("%d", n); +} + +inline int64 atoi64(const char* psz) +{ +#ifdef _MSC_VER + return _atoi64(psz); +#else + return strtoll(psz, NULL, 10); +#endif +} + +inline int64 atoi64(const string& str) +{ +#ifdef _MSC_VER + return _atoi64(str.c_str()); +#else + return strtoll(str.c_str(), NULL, 10); +#endif +} + +inline int atoi(const string& str) +{ + return atoi(str.c_str()); +} + +inline int roundint(double d) +{ + return (int)(d > 0 ? d + 0.5 : d - 0.5); +} + +template +string HexStr(const T itbegin, const T itend, bool fSpaces=true) +{ + const unsigned char* pbegin = (const unsigned char*)&itbegin[0]; + const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]); + string str; + for (const unsigned char* p = pbegin; p != pend; p++) + str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p); + return str; +} + +template +string HexNumStr(const T itbegin, const T itend, bool f0x=true) +{ + const unsigned char* pbegin = (const unsigned char*)&itbegin[0]; + const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]); + string str = (f0x ? "0x" : ""); + for (const unsigned char* p = pend-1; p >= pbegin; p--) + str += strprintf("%02X", *p); + return str; +} + +template +void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true) +{ + printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str()); +} + + + + + + + + +inline int OutputDebugStringF(const char* pszFormat, ...) +{ +#ifdef __WXDEBUG__ + // log file + FILE* fileout = fopen("debug.log", "a"); + if (fileout) + { + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + vfprintf(fileout, pszFormat, arg_ptr); + va_end(arg_ptr); + fclose(fileout); + } + + // accumulate a line at a time + static CCriticalSection cs_OutputDebugStringF; + CRITICAL_BLOCK(cs_OutputDebugStringF) + { + static char pszBuffer[50000]; + static char* pend; + if (pend == NULL) + pend = pszBuffer; + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + int limit = END(pszBuffer) - pend - 2; + int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr); + va_end(arg_ptr); + if (ret < 0 || ret >= limit) + { + pend = END(pszBuffer) - 2; + *pend++ = '\n'; + } + else + pend += ret; + *pend = '\0'; + char* p1 = pszBuffer; + char* p2; + while (p2 = strchr(p1, '\n')) + { + p2++; + char c = *p2; + *p2 = '\0'; + OutputDebugString(p1); + *p2 = c; + p1 = p2; + } + if (p1 != pszBuffer) + memmove(pszBuffer, p1, pend - p1 + 1); + pend -= (p1 - pszBuffer); + return ret; + } +#endif + + if (!wxTheApp) + { + // print to console + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + vprintf(pszFormat, arg_ptr); + va_end(arg_ptr); + } + return 0; +} + + + + + + + + + +inline void heapchk() +{ + if (_heapchk() != _HEAPOK) + DebugBreak(); +} + +// Randomize the stack to help protect against buffer overrun exploits +#define IMPLEMENT_RANDOMIZE_STACK(ThreadFn) \ + { \ + static char nLoops; \ + if (nLoops <= 0) \ + nLoops = GetRand(50) + 1; \ + if (nLoops-- > 1) \ + { \ + ThreadFn; \ + return; \ + } \ + } + +#define CATCH_PRINT_EXCEPTION(pszFn) \ + catch (std::exception& e) { \ + PrintException(&e, (pszFn)); \ + } catch (...) { \ + PrintException(NULL, (pszFn)); \ + } + + + + + + + + + +template +inline uint256 Hash(const T1 pbegin, const T1 pend) +{ + uint256 hash1; + SHA256((unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +template +inline uint256 Hash(const T1 p1begin, const T1 p1end, + const T2 p2begin, const T2 p2end) +{ + uint256 hash1; + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, (unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0])); + SHA256_Update(&ctx, (unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0])); + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +template +inline uint256 Hash(const T1 p1begin, const T1 p1end, + const T2 p2begin, const T2 p2end, + const T3 p3begin, const T3 p3end) +{ + uint256 hash1; + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, (unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0])); + SHA256_Update(&ctx, (unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0])); + SHA256_Update(&ctx, (unsigned char*)&p3begin[0], (p3end - p3begin) * sizeof(p3begin[0])); + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +template +uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=VERSION) +{ + // Most of the time is spent allocating and deallocating CDataStream's + // buffer. If this ever needs to be optimized further, make a CStaticStream + // class with its buffer on the stack. + CDataStream ss(nType, nVersion); + ss.reserve(10000); + ss << obj; + return Hash(ss.begin(), ss.end()); +} + +inline uint160 Hash160(const vector& vch) +{ + uint256 hash1; + SHA256(&vch[0], vch.size(), (unsigned char*)&hash1); + uint160 hash2; + RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +}