diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4179c76 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.pyc +*~ +sphinx/build +build +dist +src/bitcoin_python.egg-info diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..c28fc44 --- /dev/null +++ b/COPYING @@ -0,0 +1,20 @@ +Copyright (c) 2010-2011 Bitcoin-Python developers +Copyright (c) 2016 VERGE-Python developers + +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/Changelog b/Changelog new file mode 100644 index 0000000..3758045 --- /dev/null +++ b/Changelog @@ -0,0 +1,400 @@ +2014-03-02 17:55:05 -0600 Naveen Garg + + * add importprivkey method + +2014-02-26 15:34:39 -0800 Peter Harrington + + * Update config.py + +2014-01-28 19:58:26 +0100 Jean-Christophe Saad-Dupuy + + * updated changelog + +2014-01-28 19:26:06 +0100 Jean-Christophe Saad-Dupuy + + * Version bump (tag: v0.1.2) + +2014-01-28 11:31:13 -0600 benfbat + + * Update config.py + +2014-01-27 23:08:33 +0100 Jean-Christophe Saad-Dupuy + + * Added support for loading verge.conf under windows + +2014-01-26 23:00:57 +0100 jcsaaddupuy + + * Update README.rst + +2014-01-26 23:06:44 +0100 Jean-Christophe Saad-Dupuy + + * markdown + +2014-01-26 23:05:31 +0100 Jean-Christophe Saad-Dupuy + + * updated verge-qt connection instructions + +2014-01-22 02:26:02 +0100 Jean-Christophe Saad-Dupuy + + * fixed markdown + +2014-01-22 02:24:44 +0100 Jean-Christophe Saad-Dupuy + + * Added instruction for connection with verge-t + +2014-01-21 18:51:36 +0100 Jean-Christophe Saad-Dupuy + + * Updated documentation link + +2014-01-21 18:41:36 +0100 Jean-Christophe Saad-Dupuy + + * Updated changelog (tag: v0.1.1) + +2014-01-21 18:41:09 +0100 Jean-Christophe Saad-Dupuy + + * updated version in documentation + +2014-01-21 09:55:38 +0100 jcsaaddupuy + + * Update README.rst + +2014-01-20 21:17:42 +0100 Jean-Christophe Saad-Dupuy + + * Removed pip instructions + +2014-01-20 20:52:44 +0100 Jean-Christophe Saad-Dupuy + + * bump version + +2014-01-20 20:52:18 +0100 Jean-Christophe Saad-Dupuy + + * Removed uggly print + +2014-01-20 20:43:03 +0100 jcsaaddupuy + + * Update README.rst + +2014-01-20 20:35:00 +0100 Jean-Christophe Saad-Dupuy + + * Updated tests + +2014-01-20 20:31:26 +0100 Jean-Christophe Saad-Dupuy + + * Fixed markdown typo + +2014-01-20 20:27:42 +0100 Jean-Christophe Saad-Dupuy + + * version reset (dogedev) + +2014-01-20 20:26:08 +0100 Jean-Christophe Saad-Dupuy + + * Updated documentation + +2014-01-20 19:58:38 +0100 Jean-Christophe Saad-Dupuy + + * changed default rpc port + +2014-01-20 19:41:43 +0100 Jean-Christophe Saad-Dupuy + + * Migration bitcoin -> verge + +2014-01-20 19:12:31 +0100 Jean-Christophe Saad-Dupuy + + * Changed bitcoin -> verge + +2013-12-26 10:33:05 +0100 Wladimir J. van der Laan + + * fix documentation for sendtoaddress + +2013-12-01 01:05:30 -0500 jon + + * Changed iterkeys() to keys() to make the code python3 compatible. The method keys() exists in both python 2 and 3 but keysiter() does not exist in python 3 since keys() by defaults returns an iterator. + +2013-10-29 12:02:27 -0200 Leandro Boscariol + + * Made sure the code will raise InsufficientFunds or stop + +2013-10-29 11:14:15 -0200 Leandro Boscariol + + * Work around to raise InsufficientFunds exception when needed + +2013-09-27 15:49:55 +0200 Nicolas Kuttler + + * Add signmessage and verifymessage support + +2013-09-27 14:29:31 +0200 Nicolas Kuttler + + * Add --noremote option + +2013-09-27 13:08:17 +0200 Nicolas Kuttler + + * Make the test runs configurable + +2013-09-11 18:16:59 +0200 mUniKeS + + * Add gettxout function + +2013-09-02 19:46:04 +0200 Wladimir J. van der Laan + + * connect_to_local: check cfg for None + +2013-05-30 17:59:03 +0200 Oliver Gasser + + * Add dumpprivkey() function. + +2013-05-30 16:48:03 +0200 Oliver Gasser + + * Use items() instead of iteritems(). + +2013-04-25 08:27:27 +0300 Aviad Reich + + * pep8 styling conventions + +2013-04-24 22:39:24 -0600 Jeff Cook + + * Raise a TransportException on HTTP 403. + +2013-04-24 22:39:06 -0600 Jeff Cook + + * Define TransportException exception class. + +2013-04-22 14:05:03 +0400 Nikolay Belikov + + * + Added exception wrapper into AuthServiceProxy + +2013-04-21 08:56:40 -0600 Jeff Cook + + * Inform user when 403 Forbidden is sent by bitcoind. + +2013-04-21 13:07:59 +0300 Aviad Reich + + * add tests for connect_to_remote. SSL is Faulty + +2013-04-17 12:49:35 +0400 Nikolay Belikov + + * ! Minor code style fixes + +2013-04-16 18:46:46 +0400 Nikolay Belikov + + * Major overhaul of AuthServiceProxy + +2013-04-14 21:35:38 -0500 Jason Kölker + + * Allow getbalance default account with minconf=0 + +2013-03-30 16:32:59 +0100 Wladimir J. van der Laan + + * bump version number to 0.3 (tag: v0.3) + +2013-03-30 16:13:06 +0100 Aviad Reich + + * add keypoolrefill method + +2013-03-20 00:33:59 +0200 Aviad Reich + + * raw transaction support added + +2013-03-21 14:41:33 +0200 Aviad Reich + + * cherry pick to fix dont_raise so it only blocks the correct exceptions to return a boolean (origin/wallet_locking) + +2013-03-29 10:15:09 +0300 Aviad Reich + + * ignore dist and python_egg + +2013-03-23 19:08:46 +0000 Aviad Reich + + * deprecated getblocknumber - use getblockcount instead + +2013-03-19 23:01:18 +0200 Aviad Reich + + * add wallet locking/unlocking support + +2013-03-19 14:42:26 +0200 Aviad Reich + + * in listtransactions, iterate all accounts if account is None (origin/listtransactions) + +2013-03-19 11:16:38 +0200 Aviad Reich + + * listaccounts can return a dictionary from account names to their balance if the param as_dict is True, update tests. (origin/listaccounts) + +2013-03-19 09:44:20 +0200 Aviad Reich + + * add tests for listunspent and getmininginfo + +2013-03-18 08:18:23 +0200 Aviad Reich + + * refactor __repr__ + +2013-03-17 09:43:44 +0200 Aviad Reich + + * flake8 style conventions fixes + +2013-03-18 00:13:42 +0200 Aviad Reich + + * add listunspent method + +2013-03-17 23:46:44 +0200 Aviad Reich + + * add support for getmininginfo + +2013-03-17 16:37:09 +0200 Aviad Reich + + * Issue #15: add from parameter to listtransactions + +2013-03-15 22:14:10 +0100 David Barton + + * Fixed usage.rst broken links + +2013-03-14 09:26:23 +0200 Aviad Reich + + * connect_to_local(): use default testnet port, when the config file has testnet=x + +2013-02-10 17:35:14 +0100 Adrian + + * Add getrawtransaction method + +2013-01-16 03:28:11 +0100 Thomas Steen Rasmussen + + * fix bug when rpc reply error is null in json + +2012-12-12 00:14:34 +0100 Benoît HERVIER + + * There isn't always an error key in resp dict + +2012-12-12 00:12:40 +0100 Benoît HERVIER + + * There isn't always an error key in resp dict + +2012-12-12 00:10:41 +0100 Benoît HERVIER + + * Allow use of https + +2012-12-12 00:09:38 +0100 Benoît HERVIER + + * Allow use of https + +2012-10-29 16:46:18 +0100 Harald Schilly + + * assert that we are really in the testnet + +2012-10-28 23:25:25 +0100 Harald Schilly + + * optionally allow to pass in the path to the bitcoin.conf file if it is at a non-standard path + +2012-10-28 21:52:48 +0100 Harald Schilly + + * fixing tests + +2012-10-23 02:57:40 +0200 Thomas Steen Rasmussen + + * Add support for the 'verifymessage' RPC command + +2012-10-05 18:45:50 +0200 Wladimir J. van der Laan + + * Switch to jgarzik's jsonrpc implementation + +2012-10-05 18:32:23 +0200 Wladimir J. van der Laan + + * Use RPC error codes from bitcoin core source + +2012-07-15 12:07:53 +0400 Alexander Petrovich + + * Added listsinceblock, getblock, getblockhash + +2011-09-04 15:17:44 +0200 Jure Vrscaj + + * Added sendmany command. + +2011-08-24 17:28:14 +0000 toomanysecrets0 + + * Edited README.rst via GitHub + +2011-08-24 16:57:01 +0000 toomanysecrets0 + + * under new management + +2011-08-24 14:56:22 +0200 Wladimir J. van der Laan + + * update changelog + +2011-08-24 14:53:53 +0200 Wladimir J. van der Laan + + * allow listtransactions() (default to '' account), add test for gettransaction + +2011-08-24 11:20:43 +0200 Wladimir J. van der Laan + + * add license (MIT) (tag: v0.2) + +2011-08-24 23:00:01 +0300 Wladimir J. van der Laan + + * mention cheeseshop page + +2011-08-24 10:16:46 +0200 Wladimir J. van der Laan + + * link to new doc + +2011-08-24 10:09:12 +0200 Wladimir J. van der Laan + + * rename package to 'bitcoinrpc' + +2011-08-24 09:42:34 +0200 Wladimir J. van der Laan + + * add neccesary metadata + +2011-08-24 09:22:43 +0200 Witchspace + + * Version bump + +2011-08-20 09:00:18 +0400 Alexander Petrovich + + * Edited src/bitcoin/connection.py via GitHub + +2011-07-04 13:52:17 +0100 Greg Hughes + + * Look in correct location for bitcoin.conf on Mac OS X + +2011-06-06 15:48:41 +0200 Daniel Poelzleithner + + * add minconf to getbalance + +2011-06-06 15:47:39 +0200 Daniel Poelzleithner + + * add listtransactions address filter + +2011-06-06 15:46:30 +0200 Daniel Poelzleithner + + * fix bug in listreceivedbyaddress + +2011-05-18 21:10:47 +0200 Witchspace + + * add TODOs + +2011-05-18 21:10:11 +0200 Witchspace + + * add TODOs + +2011-05-18 20:54:47 +0200 Witchspace + + * default rpcuser to '' + +2011-05-16 17:43:04 -0300 Carlos da Costa + + * Ignore comments in the read_config_file. Ignore lines without '='. + +2011-03-29 15:06:10 +0200 Jure Vrscaj + + * Added "listaccounts" command. + +2010-12-20 18:29:30 -0800 Stephen + + * Add import BitcoinConnection to connect_to_remote() + +2010-12-20 18:29:30 -0800 Stephen + + * Add import BitcoinConnection to connect_to_remote() + +2010-12-11 20:13:00 +0100 Witchspace + + * initial commit (tag: v0.1.0) + diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..14f1e06 --- /dev/null +++ b/README.rst @@ -0,0 +1,52 @@ +``` +____ _________________________ ________ ___________ +\ \ / /\_ _____/\______ \ / _____/ \_ _____/ + \ Y / | __)_ | _// \ ___ | __)_ + \ / | \ | | \\ \_\ \ | \ 2016 VERGE + \___/ /_______ / |____|_ / \______ //_______ / + \/ \/ \/ \/ +``` +# A Python library for the VERGE Client +It is a set of Python libraries that allows easy access to the +VERGE peer-to-peer cryptocurrency client API. + + +Installation instructions +=========================== + +verge-python uses setuptools for the install script. There are no dependencies apart from Python itself. + +:: + + $ python setup.py build + $ python setup.py install + + +Pypi / Cheeseshop +================== + +It is possible to install the package through Pypi (cheeseshop), see http://pypi.python.org/pypi?:action=display&name=verge-python +:: + $ pip install verge-python + # if not working, try + $ pip install --pre verge-python + +Connection to verge-qt +========================= + +If you want to connect to verge-qt, add server=1 in your VERGE.conf +:: + + rpcuser=vergerpcuser + rpcpassword=A RANDOM GENERATED PASSWORD + server=1 + +TODO +====== +These things still have to be added: + +- SSL support (including certificate verification) for managing remote verge daemons. + +verge-python is a fork of bitcoin-python : https://github.com/laanwj/bitcoin-python + + diff --git a/dist-tools/changelog.sh b/dist-tools/changelog.sh new file mode 100644 index 0000000..d977e15 --- /dev/null +++ b/dist-tools/changelog.sh @@ -0,0 +1,2 @@ +#!/bin/bash +git --no-pager log --no-merges --format="%ai %aN %n%n%x09* %s%d%n" diff --git a/doc/_sources/apireference.txt b/doc/_sources/apireference.txt new file mode 100644 index 0000000..795a567 --- /dev/null +++ b/doc/_sources/apireference.txt @@ -0,0 +1,13 @@ +================= + API reference +================= + +.. toctree:: + :maxdepth: 2 + + vergerpc.rst + vergerpc.connection.rst + vergerpc.exceptions.rst + vergerpc.data.rst + vergerpc.config.rst + diff --git a/doc/_sources/examples.txt b/doc/_sources/examples.txt new file mode 100644 index 0000000..3057b01 --- /dev/null +++ b/doc/_sources/examples.txt @@ -0,0 +1,43 @@ +**************************** + Examples +**************************** + +A basic program that uses ``python-verge`` looks like this: + +First, import the library and exceptions. + +:: + + import vergerpc + from vergerpc.exceptions import InsufficientFunds + +Then, we connect to the currently running ``verge`` instance of the current user on the local machine +with one call to +:func:`~vergerpc.connect_to_local`. This returns a :class:`~vergerpc.connection.VERGEConnection` objects: + +:: + + conn = vergerpc.connect_to_local() + +Try to move one verge from account ``testaccount`` to account ``testaccount2`` using +:func:`~vergerpc.connection.VERGEConnection.move`. Catch the :class:`~vergerpc.exceptions.InsufficientFunds` +exception in the case the originating account is broke: + +:: + + try: + conn.move("testaccount", "testaccount2", 1.0) + except InsufficientFunds,e: + print "Account does not have enough funds available!" + + +Retrieve general server information with :func:`~vergerpc.connection.VERGEConnection.getinfo` and print some statistics: + +:: + + info = conn.getinfo() + print "Blocks: %i" % info.blocks + print "Connections: %i" % info.connections + print "Difficulty: %f" % info.difficulty + + diff --git a/doc/_sources/gettingstarted.txt b/doc/_sources/gettingstarted.txt new file mode 100644 index 0000000..4b34042 --- /dev/null +++ b/doc/_sources/gettingstarted.txt @@ -0,0 +1,11 @@ +================= + Getting Started +================= + +.. toctree:: + :maxdepth: 2 + + introduction.rst + usage.rst + examples.rst + diff --git a/doc/_sources/index.txt b/doc/_sources/index.txt new file mode 100644 index 0000000..92eeeb0 --- /dev/null +++ b/doc/_sources/index.txt @@ -0,0 +1,24 @@ +================================================== + verge-python - Easy-to-use VERGE API client. +================================================== + +``verge-python`` is a set of Python libraries that allows easy access to the +verge_ peer-to-peer cryptocurrency client API. + +Contents: + +.. toctree:: + :maxdepth: 2 + + gettingstarted.rst + apireference.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +.. _verge: http://vergecurrency.com/ + diff --git a/doc/_sources/introduction.txt b/doc/_sources/introduction.txt new file mode 100644 index 0000000..6990749 --- /dev/null +++ b/doc/_sources/introduction.txt @@ -0,0 +1,47 @@ +**************************** + Introduction +**************************** + +The goal of this library is to make it easier for: + +- Payment gateways to support VERGE +- Merchant sites to integrate VERGE payments directly +- Other services that require (micro-)payments to use VERGE + +In this initial release it implements a thin wrapper around the +VERGE JSON-RPC API. Using this API from Python directly is conceptually very simple, +here is the example from the API +documentation page: + +:: + + from jsonrpc import ServiceProxy + + access = ServiceProxy("http://user:password@127.0.0.1:20102") + access.getinfo() + access.listreceivedbyaddress(6) + access.sendtoaddress("D1yEmxiMso2RsFVfBcCa616npBvGgxiBX", 1000) + +However, this approach has some disadvantages, one thing is that error handling is complex, as it +requires manually checking the contents of :const:`JSONException` objects. + +``verge-python`` attempts to create an even more friendly interface by wrapping the JSON-RPC API. The major advantages +compared to a raw ``jsonrpc`` based approach are: + +- Better exception handling. Exceptions are converted to subclasses of :class:`~vergerpc.exceptions.VERGEException`. + +- Automatic verge configuration loading. In case the ``verge -server`` or ``verged`` program runs on the same + machine as the client script, and as the same user, the configuration file can automatically be parsed. This + makes it unneccesary to explicitly specify a *username* and *password*. Of course, this is still possible. + +- Documentation in Pythonish format. You are reading this right now. + +- The functions + :func:`~vergerpc.connection.VERGEConnection.getinfo`, :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaccount`, + :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaddress`, + :func:`~vergerpc.connection.VERGEConnection.listtransactions` and more return actual Python objects, instead of simply + dictionaries. This makes for cleaner code, as the fields can simply be addressed with ``x.foo`` instead of + ``x['foo']``. + +The plan for future releases is to add a more high-level interface on top of this. + diff --git a/doc/_sources/usage.txt b/doc/_sources/usage.txt new file mode 100644 index 0000000..5fd934d --- /dev/null +++ b/doc/_sources/usage.txt @@ -0,0 +1,120 @@ +================= + Usage +================= + +See also the `main verge documentation`_ for details and background on setting up and +using verged remotely. + +Setting up verge for remote control +------------------------------------- + +If you run VERGE with the ``-server`` argument, or if you run ``verged``, it can be controlled +either by sending it HTTP-JSON-RPC commands. + +However, beginning with VERGE 0.3.3 you must create a ``verge.conf`` file in the VERGE data directory +(default ``$HOME/.dogeconf``) and set an RPC password: + +:: + + rpcuser=anything + rpcpassword=anything + +Once that is done, the easiest way to check whether VERGE accepts remote commands is by running +VERGE again, with the command (and any parameters) as arguments. For example: + +:: + + $ verged getinfo + +Connecting to the wallet from Python +------------------------------------- + +There are two functions for this: + +*Connecting to local verge instance* + Use the function :func:`~vergerpc.connect_to_local`. This automagically + sorts out the connection to a verge process running on the current machine, + for the current user. + + :: + + conn = vergerpc.connect_to_local() + +*Connecting to a remote verge instance* + Use the function :func:`~vergerpc.connect_to_remote`. For this function + it is neccesary to explicitly specify a hostname and port to connect to, and + to provide user credentials for logging in. + + :: + + conn = vergerpc.connect_to_remote('foo', 'bar', host='payments.yoyodyne.com', port=20102) + + +How to use the API +------------------------------------- + +For basic sending and receiving of payments, the four most important methods are + +*Getting the current balance* + Use the method :func:`~vergerpc.connection.VERGEConnection.getbalance` to get the current server balance. + + :: + + print "Your balance is %f" % (conn.getbalance(),) + +*Check a customer address for validity and get information about it* + This can be done with the method :func:`~vergerpc.connection.VERGEConnection.validateaddress`. + + :: + + rv = conn.validateaddress(foo) + if rv.isvalid: + print "The address that you provided is valid" + else: + print "The address that you provided is invalid, please correct" + +*Sending payments* + The method :func:`~vergerpc.connection.VERGEConnection.sendtoaddress` sends a specified + amount of coins to a specified address. + + :: + + conn.sendtoaddress("DsTGAm1ApjEJfsWfAaRVaZHRm26mv5GL73", 20000.0) + +*Get a new address for accepting payments* + To accept payments, use the method :func:`~vergerpc.connection.VERGEConnection.getnewaddress` + to generate a new address. Give this address to the customer and store it in a safe place, to be able to check + when the payment to this address has been made. + + :: + + pay_to = conn.getnewaddress() + print "We will ship the pirate sandwidth after payment of 20000 coins to ", pay_to + +*Check how much has been received at a certain address* + The method :func:`~vergerpc.connection.VERGEConnection.getreceivedbyaddress` + returns how many verges have been received at a certain address. Together with the + previous function, this can be used to check whether a payment has been made + by the customer. + + :: + + amount = conn.getreceivedbyaddress(pay_to) + if amount > 20000.0: + print "Thanks, your sandwidth will be prepared and shipped." + + + + +The account API +------------------------------------- +More advanced usage of verge allows multiple accounts within one wallet. This +can be useful if you are writing software for a bank, or +simply want to have a clear separation between customers payments. + +For this, see the `Account API`_ documentation. + +.. _main bitcoin documentation: https://en.bitcoin.it/wiki/Main_Page +.. _account API: https://en.bitcoin.it/wiki/Accounts_explained + + diff --git a/doc/_sources/vergerpc.config.txt b/doc/_sources/vergerpc.config.txt new file mode 100644 index 0000000..50afc27 --- /dev/null +++ b/doc/_sources/vergerpc.config.txt @@ -0,0 +1,7 @@ +:mod:`vergerpc.config` --- Utilities for reading verge configuration files +==================================================================================== + +.. automodule:: vergerpc.config + :members: + :show-inheritance: + diff --git a/doc/_sources/vergerpc.connection.txt b/doc/_sources/vergerpc.connection.txt new file mode 100644 index 0000000..922fc9f --- /dev/null +++ b/doc/_sources/vergerpc.connection.txt @@ -0,0 +1,8 @@ +:mod:`vergerpc.connection` --- Connect to VERGE server via JSON-RPC +==================================================================================== + +.. automodule:: vergerpc.connection + :members: + :show-inheritance: + + diff --git a/doc/_sources/vergerpc.data.txt b/doc/_sources/vergerpc.data.txt new file mode 100644 index 0000000..fe3a16b --- /dev/null +++ b/doc/_sources/vergerpc.data.txt @@ -0,0 +1,7 @@ +:mod:`vergerpc.data` --- VERGE RPC service, data objects +==================================================================================== + +.. automodule:: vergerpc.data + :members: + :show-inheritance: + diff --git a/doc/_sources/vergerpc.exceptions.txt b/doc/_sources/vergerpc.exceptions.txt new file mode 100644 index 0000000..ae74eb7 --- /dev/null +++ b/doc/_sources/vergerpc.exceptions.txt @@ -0,0 +1,7 @@ +:mod:`vergerpc.exceptions` --- Exception definitions +==================================================================================== + +.. automodule:: vergerpc.exceptions + :members: + :show-inheritance: + diff --git a/doc/_sources/vergerpc.txt b/doc/_sources/vergerpc.txt new file mode 100644 index 0000000..e931a6b --- /dev/null +++ b/doc/_sources/vergerpc.txt @@ -0,0 +1,7 @@ +:mod:`vergerpc` --- Convenience functions +==================================================================================== + +.. automodule:: vergerpc + :members: + :show-inheritance: + diff --git a/doc/_sources/vergerpc.util.txt b/doc/_sources/vergerpc.util.txt new file mode 100644 index 0000000..81bb6db --- /dev/null +++ b/doc/_sources/vergerpc.util.txt @@ -0,0 +1,7 @@ +:mod:`vergerpc.util` --- Generic utilities used by verge client library +==================================================================================== + +.. automodule:: vergerpc.util + :members: + :show-inheritance: + diff --git a/doc/_static/ajax-loader.gif b/doc/_static/ajax-loader.gif new file mode 100644 index 0000000..61faf8c Binary files /dev/null and b/doc/_static/ajax-loader.gif differ diff --git a/doc/_static/basic.css b/doc/_static/basic.css new file mode 100644 index 0000000..c959cf0 --- /dev/null +++ b/doc/_static/basic.css @@ -0,0 +1,537 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 30px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/doc/_static/comment-bright.png b/doc/_static/comment-bright.png new file mode 100644 index 0000000..551517b Binary files /dev/null and b/doc/_static/comment-bright.png differ diff --git a/doc/_static/comment-close.png b/doc/_static/comment-close.png new file mode 100644 index 0000000..09b54be Binary files /dev/null and b/doc/_static/comment-close.png differ diff --git a/doc/_static/comment.png b/doc/_static/comment.png new file mode 100644 index 0000000..92feb52 Binary files /dev/null and b/doc/_static/comment.png differ diff --git a/doc/_static/default.css b/doc/_static/default.css new file mode 100644 index 0000000..e534a07 --- /dev/null +++ b/doc/_static/default.css @@ -0,0 +1,256 @@ +/* + * default.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- default theme. + * + * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + + + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} + +.warning tt { + background: #efc2c2; +} + +.note tt { + background: #d6d6d6; +} + +.viewcode-back { + font-family: sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} \ No newline at end of file diff --git a/doc/_static/doctools.js b/doc/_static/doctools.js new file mode 100644 index 0000000..2036e5f --- /dev/null +++ b/doc/_static/doctools.js @@ -0,0 +1,238 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/doc/_static/down-pressed.png b/doc/_static/down-pressed.png new file mode 100644 index 0000000..6f7ad78 Binary files /dev/null and b/doc/_static/down-pressed.png differ diff --git a/doc/_static/down.png b/doc/_static/down.png new file mode 100644 index 0000000..3003a88 Binary files /dev/null and b/doc/_static/down.png differ diff --git a/doc/_static/file.png b/doc/_static/file.png new file mode 100644 index 0000000..d18082e Binary files /dev/null and b/doc/_static/file.png differ diff --git a/doc/_static/jquery.js b/doc/_static/jquery.js new file mode 100644 index 0000000..3883779 --- /dev/null +++ b/doc/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/doc/_static/minus.png b/doc/_static/minus.png new file mode 100644 index 0000000..da1c562 Binary files /dev/null and b/doc/_static/minus.png differ diff --git a/doc/_static/plus.png b/doc/_static/plus.png new file mode 100644 index 0000000..b3cb374 Binary files /dev/null and b/doc/_static/plus.png differ diff --git a/doc/_static/pygments.css b/doc/_static/pygments.css new file mode 100644 index 0000000..d79caa1 --- /dev/null +++ b/doc/_static/pygments.css @@ -0,0 +1,62 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/doc/_static/searchtools.js b/doc/_static/searchtools.js new file mode 100644 index 0000000..f5c7e5f --- /dev/null +++ b/doc/_static/searchtools.js @@ -0,0 +1,622 @@ +/* + * searchtools.js_t + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilties for the full-text search. + * + * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + + +/** + * Simple result scoring code. + */ +var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [filename, title, anchor, descr, score] + // and returns the new score. + /* + score: function(result) { + return result[4]; + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: {0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5}, // used to be unimportantResults + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + // query found in terms + term: 5 +}; + + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, + dataType: "script", cache: true, + complete: function(jqxhr, textstatus) { + if (textstatus != "success") { + document.getElementById("searchindexloader").src = url; + } + }}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + var i; + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + } + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('

' + _('Searching') + '

').appendTo(this.out); + this.dots = $('').appendTo(this.title); + this.status = $('

').appendTo(this.out); + this.output = $('
'); + } + // Prettify the comment rating. + comment.pretty_rating = comment.rating + ' point' + + (comment.rating == 1 ? '' : 's'); + // Make a class (for displaying not yet moderated comments differently) + comment.css_class = comment.displayed ? '' : ' moderate'; + // Create a div for this comment. + var context = $.extend({}, opts, comment); + var div = $(renderTemplate(commentTemplate, context)); + + // If the user has voted on this comment, highlight the correct arrow. + if (comment.vote) { + var direction = (comment.vote == 1) ? 'u' : 'd'; + div.find('#' + direction + 'v' + comment.id).hide(); + div.find('#' + direction + 'u' + comment.id).show(); + } + + if (opts.moderator || comment.text != '[deleted]') { + div.find('a.reply').show(); + if (comment.proposal_diff) + div.find('#sp' + comment.id).show(); + if (opts.moderator && !comment.displayed) + div.find('#cm' + comment.id).show(); + if (opts.moderator || (opts.username == comment.username)) + div.find('#dc' + comment.id).show(); + } + return div; + } + + /** + * A simple template renderer. Placeholders such as <%id%> are replaced + * by context['id'] with items being escaped. Placeholders such as <#id#> + * are not escaped. + */ + function renderTemplate(template, context) { + var esc = $(document.createElement('div')); + + function handle(ph, escape) { + var cur = context; + $.each(ph.split('.'), function() { + cur = cur[this]; + }); + return escape ? esc.text(cur || "").html() : cur; + } + + return template.replace(/<([%#])([\w\.]*)\1>/g, function() { + return handle(arguments[2], arguments[1] == '%' ? true : false); + }); + } + + /** Flash an error message briefly. */ + function showError(message) { + $(document.createElement('div')).attr({'class': 'popup-error'}) + .append($(document.createElement('div')) + .attr({'class': 'error-message'}).text(message)) + .appendTo('body') + .fadeIn("slow") + .delay(2000) + .fadeOut("slow"); + } + + /** Add a link the user uses to open the comments popup. */ + $.fn.comment = function() { + return this.each(function() { + var id = $(this).attr('id').substring(1); + var count = COMMENT_METADATA[id]; + var title = count + ' comment' + (count == 1 ? '' : 's'); + var image = count > 0 ? opts.commentBrightImage : opts.commentImage; + var addcls = count == 0 ? ' nocomment' : ''; + $(this) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-open' + addcls, + id: 'ao' + id + }) + .append($(document.createElement('img')).attr({ + src: image, + alt: 'comment', + title: title + })) + .click(function(event) { + event.preventDefault(); + show($(this).attr('id').substring(2)); + }) + ) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-close hidden', + id: 'ah' + id + }) + .append($(document.createElement('img')).attr({ + src: opts.closeCommentImage, + alt: 'close', + title: 'close' + })) + .click(function(event) { + event.preventDefault(); + hide($(this).attr('id').substring(2)); + }) + ); + }); + }; + + var opts = { + processVoteURL: '/_process_vote', + addCommentURL: '/_add_comment', + getCommentsURL: '/_get_comments', + acceptCommentURL: '/_accept_comment', + deleteCommentURL: '/_delete_comment', + commentImage: '/static/_static/comment.png', + closeCommentImage: '/static/_static/comment-close.png', + loadingImage: '/static/_static/ajax-loader.gif', + commentBrightImage: '/static/_static/comment-bright.png', + upArrow: '/static/_static/up.png', + downArrow: '/static/_static/down.png', + upArrowPressed: '/static/_static/up-pressed.png', + downArrowPressed: '/static/_static/down-pressed.png', + voting: false, + moderator: false + }; + + if (typeof COMMENT_OPTIONS != "undefined") { + opts = jQuery.extend(opts, COMMENT_OPTIONS); + } + + var popupTemplate = '\ +
\ +

\ + Sort by:\ + best rated\ + newest\ + oldest\ +

\ +
Comments
\ +
\ + loading comments...
\ +
    \ +
    \ +

    Add a comment\ + (markup):

    \ +
    \ + reStructured text markup: *emph*, **strong**, \ + ``code``, \ + code blocks: :: and an indented block after blank line
    \ +
    \ + \ +

    \ + \ + Propose a change ▹\ + \ + \ + Propose a change ▿\ + \ +

    \ + \ + \ + \ + \ + \ +
    \ +
    '; + + var commentTemplate = '\ +
    \ +
    \ +
    \ + \ + \ + \ + \ + \ + \ +
    \ +
    \ + \ + \ + \ + \ + \ + \ +
    \ +
    \ +
    \ +

    \ + <%username%>\ + <%pretty_rating%>\ + <%time.delta%>\ +

    \ +
    <#text#>
    \ +

    \ + \ + reply ▿\ + proposal ▹\ + proposal ▿\ + \ + \ +

    \ +
    \
    +<#proposal_diff#>\
    +        
    \ +
      \ +
      \ +
      \ +
      \ + '; + + var replyTemplate = '\ +
    • \ +
      \ +
      \ + \ + \ + \ + \ + \ + \ +
      \ +
    • '; + + $(document).ready(function() { + init(); + }); +})(jQuery); + +$(document).ready(function() { + // add comment anchors for all paragraphs that are commentable + $('.sphinx-has-comment').comment(); + + // highlight search words in search results + $("div.context").each(function() { + var params = $.getQueryParameters(); + var terms = (params.q) ? params.q[0].split(/\s+/) : []; + var result = $(this); + $.each(terms, function() { + result.highlightText(this.toLowerCase(), 'highlighted'); + }); + }); + + // directly open comment window if requested + var anchor = document.location.hash; + if (anchor.substring(0, 9) == '#comment-') { + $('#ao' + anchor.substring(9)).click(); + document.location.hash = '#s' + anchor.substring(9); + } +}); diff --git a/doc/apireference.html b/doc/apireference.html new file mode 100644 index 0000000..94b6956 --- /dev/null +++ b/doc/apireference.html @@ -0,0 +1,125 @@ + + + + + + + + API reference — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + +
      + +
      +
      +

      Previous topic

      +

      Examples

      +

      Next topic

      +

      vergerpc — Convenience functions

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/examples.html b/doc/examples.html new file mode 100644 index 0000000..4ed55bc --- /dev/null +++ b/doc/examples.html @@ -0,0 +1,147 @@ + + + + + + + + Examples — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Examples

      +

      A basic program that uses python-verge looks like this:

      +

      First, import the library and exceptions.

      +
      import vergerpc
      +from vergerpc.exceptions import InsufficientFunds
      +
      +
      +

      Then, we connect to the currently running verge instance of the current user on the local machine +with one call to +connect_to_local(). This returns a VERGEConnection objects:

      +
      conn = vergerpc.connect_to_local()
      +
      +
      +

      Try to move one verge from account testaccount to account testaccount2 using +move(). Catch the InsufficientFunds +exception in the case the originating account is broke:

      +
      try:
      +    conn.move("testaccount", "testaccount2", 1.0)
      +except InsufficientFunds,e:
      +    print "Account does not have enough funds available!"
      +
      +
      +

      Retrieve general server information with getinfo() and print some statistics:

      +
      info = conn.getinfo()
      +print "Blocks: %i" % info.blocks
      +print "Connections: %i" % info.connections
      +print "Difficulty: %f" % info.difficulty
      +
      +
      +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      Usage

      +

      Next topic

      +

      API reference

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/genindex.html b/doc/genindex.html new file mode 100644 index 0000000..c2bf8f4 --- /dev/null +++ b/doc/genindex.html @@ -0,0 +1,595 @@ + + + + + + + + + Index — verge-python 0.1.3 documentation + + + + + + + + + + + + + +
      +
      +
      +
      + + +

      Index

      + +
      + A + | B + | C + | D + | G + | I + | J + | K + | L + | M + | N + | O + | R + | S + | T + | V + | W + +
      +

      A

      +
      + + +
      + +
      AccountInfo (class in vergerpc.data) +
      + + +
      AddressInfo (class in vergerpc.data) +
      + +
      + +
      AddressValidation (class in vergerpc.data) +
      + +
      + +

      B

      + + +
      + +
      backupwallet() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      C

      + + + +
      + +
      ClientException +
      + + +
      connect_to_local() (in module vergerpc) +
      + +
      + +
      connect_to_remote() (in module vergerpc) +
      + + +
      createrawtransaction() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      D

      + + + +
      + +
      decoderawtransaction() (vergerpc.connection.VERGEConnection method) +
      + + +
      VERGEConnection (class in vergerpc.connection) +
      + + +
      VERGEException +
      + + +
      vergerpc (module) +
      + + +
      vergerpc.config (module) +
      + + +
      vergerpc.connection (module) +
      + +
      + +
      vergerpc.data (module) +
      + + +
      vergerpc.exceptions (module) +
      + + +
      vergerpc.util (module) +
      + + +
      DownloadingBlocks +
      + + +
      DStruct (class in vergerpc.util) +
      + + +
      dumpprivkey() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      G

      + + + +
      + +
      getaccount() (vergerpc.connection.VERGEConnection method) +
      + + +
      getaccountaddress() (vergerpc.connection.VERGEConnection method) +
      + + +
      getaddressesbyaccount() (vergerpc.connection.VERGEConnection method) +
      + + +
      getbalance() (vergerpc.connection.VERGEConnection method) +
      + + +
      getblock() (vergerpc.connection.VERGEConnection method) +
      + + +
      getblockcount() (vergerpc.connection.VERGEConnection method) +
      + + +
      getblockhash() (vergerpc.connection.VERGEConnection method) +
      + + +
      getblocknumber() (vergerpc.connection.VERGEConnection method) +
      + + +
      getconnectioncount() (vergerpc.connection.VERGEConnection method) +
      + + +
      getdifficulty() (vergerpc.connection.VERGEConnection method) +
      + + +
      getgenerate() (vergerpc.connection.VERGEConnection method) +
      + +
      + +
      gethashespersec() (vergerpc.connection.VERGEConnection method) +
      + + +
      getinfo() (vergerpc.connection.VERGEConnection method) +
      + + +
      getmininginfo() (vergerpc.connection.VERGEConnection method) +
      + + +
      getnewaddress() (vergerpc.connection.VERGEConnection method) +
      + + +
      getrawtransaction() (vergerpc.connection.VERGEConnection method) +
      + + +
      getreceivedbyaccount() (vergerpc.connection.VERGEConnection method) +
      + + +
      getreceivedbyaddress() (vergerpc.connection.VERGEConnection method) +
      + + +
      gettransaction() (vergerpc.connection.VERGEConnection method) +
      + + +
      gettxout() (vergerpc.connection.VERGEConnection method) +
      + + +
      getwork() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      I

      + + + +
      + +
      importprivkey() (vergerpc.connection.VERGEConnection method) +
      + + +
      InsufficientFunds +
      + + +
      InvalidAccountName +
      + + +
      InvalidAddressOrKey +
      + +
      + +
      InvalidAmount (in module vergerpc.exceptions) +
      + + +
      InvalidParameter +
      + + +
      InvalidTransactionID (in module vergerpc.exceptions) +
      + +
      + +

      J

      + + +
      + +
      JSONTypeError +
      + +
      + +

      K

      + + + +
      + +
      KeypoolRanOut +
      + +
      + +
      keypoolrefill() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      L

      + + + +
      + +
      listaccounts() (vergerpc.connection.VERGEConnection method) +
      + + +
      listreceivedbyaccount() (vergerpc.connection.VERGEConnection method) +
      + + +
      listreceivedbyaddress() (vergerpc.connection.VERGEConnection method) +
      + +
      + +
      listtransactions() (vergerpc.connection.VERGEConnection method) +
      + + +
      listunspent() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      M

      + + + +
      + +
      MiningInfo (class in vergerpc.data) +
      + +
      + +
      move() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      N

      + + +
      + +
      NotConnected +
      + +
      + +

      O

      + + +
      + +
      OutOfMemory +
      + +
      + +

      R

      + + + +
      + +
      read_config_file() (in module vergerpc.config) +
      + +
      + +
      read_default_config() (in module vergerpc.config) +
      + +
      + +

      S

      + + + +
      + +
      SafeMode +
      + + +
      SendError (in module vergerpc.exceptions) +
      + + +
      sendfrom() (vergerpc.connection.VERGEConnection method) +
      + + +
      sendmany() (vergerpc.connection.VERGEConnection method) +
      + + +
      sendtoaddress() (vergerpc.connection.VERGEConnection method) +
      + + +
      ServerInfo (class in vergerpc.data) +
      + +
      + +
      setaccount() (vergerpc.connection.VERGEConnection method) +
      + + +
      setgenerate() (vergerpc.connection.VERGEConnection method) +
      + + +
      signmessage() (vergerpc.connection.VERGEConnection method) +
      + + +
      signrawtransaction() (vergerpc.connection.VERGEConnection method) +
      + + +
      stop() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      T

      + + + +
      + +
      TransactionInfo (class in vergerpc.data) +
      + +
      + +
      TransportException +
      + +
      + +

      V

      + + + +
      + +
      validateaddress() (vergerpc.connection.VERGEConnection method) +
      + +
      + +
      verifymessage() (vergerpc.connection.VERGEConnection method) +
      + +
      + +

      W

      + + + +
      + +
      WalletAlreadyUnlocked +
      + + +
      WalletEncryptionFailed +
      + + +
      WalletError +
      + + +
      walletlock() (vergerpc.connection.VERGEConnection method) +
      + + +
      walletpassphrase() (vergerpc.connection.VERGEConnection method) +
      + + +
      walletpassphrasechange() (vergerpc.connection.VERGEConnection method) +
      + +
      + +
      WalletPassphraseIncorrect +
      + + +
      WalletUnlockNeeded +
      + + +
      WalletWrongEncState +
      + + +
      WorkItem (class in vergerpc.data) +
      + + +
      wrap_exception() (in module vergerpc.exceptions) +
      + +
      + + + + + + +
      +
      + + + + + +
      +
      +
      + + + + + \ No newline at end of file diff --git a/doc/gettingstarted.html b/doc/gettingstarted.html new file mode 100644 index 0000000..a76934b --- /dev/null +++ b/doc/gettingstarted.html @@ -0,0 +1,129 @@ + + + + + + + + Getting Started — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + +
      + +
      +
      +

      Previous topic

      +

      verge-python - Easy-to-use VERGE API client.

      +

      Next topic

      +

      Introduction

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..7891851 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,143 @@ + + + + + + + + verge-python - Easy-to-use VERGE API client. — verge-python 0.1.3 documentation + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      verge-python - Easy-to-use VERGE API client.

      +

      verge-python is a set of Python libraries that allows easy access to the +verge peer-to-peer cryptocurrency client API.

      +

      Contents:

      + +
      +

      Indices and tables

      + +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Next topic

      +

      Getting Started

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/introduction.html b/doc/introduction.html new file mode 100644 index 0000000..d2bbcbf --- /dev/null +++ b/doc/introduction.html @@ -0,0 +1,155 @@ + + + + + + + + Introduction — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Introduction

      +

      The goal of this library is to make it easier for:

      +
        +
      • Payment gateways to support verge
      • +
      • Merchant sites to integrate verge payments directly
      • +
      • Other services that require (micro-)payments to use verge
      • +
      +

      In this initial release it implements a thin wrapper around the +VERGE JSON-RPC API. Using this API from Python directly is conceptually very simple, +here is the example from the API +documentation page:

      +
      from jsonrpc import ServiceProxy
      +
      +access = ServiceProxy("http://user:password@127.0.0.1:8332")
      +access.getinfo()
      +access.listreceivedbyaddress(6)
      +access.sendtoaddress("11yEmxiMso2RsFVfBcCa616npBvGgxiBX", 10)
      +
      +
      +

      However, this approach has some disadvantages, one thing is that error handling is complex, as it +requires manually checking the contents of JSONException objects.

      +

      verge-python attempts to create an even more friendly interface by wrapping the JSON-RPC API. The major advantages +compared to a raw jsonrpc based approach are:

      +
        +
      • Better exception handling. Exceptions are converted to subclasses of VERGEException.
      • +
      • Automatic verge configuration loading. In case the verge -server or verged program runs on the same +machine as the client script, and as the same user, the configuration file can automatically be parsed. This +makes it unneccesary to explicitly specify a username and password. Of course, this is still possible.
      • +
      • Documentation in Pythonish format. You are reading this right now.
      • +
      • The functions +getinfo(), listreceivedbyaccount(), +listreceivedbyaddress(), +listtransactions() and more return actual Python objects, instead of simply +dictionaries. This makes for cleaner code, as the fields can simply be addressed with x.foo instead of +x['foo'].
      • +
      +

      The plan for future releases is to add a more high-level interface on top of this.

      +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      Getting Started

      +

      Next topic

      +

      Usage

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/objects.inv b/doc/objects.inv new file mode 100644 index 0000000..7ed03ad Binary files /dev/null and b/doc/objects.inv differ diff --git a/doc/py-modindex.html b/doc/py-modindex.html new file mode 100644 index 0000000..0025ea8 --- /dev/null +++ b/doc/py-modindex.html @@ -0,0 +1,134 @@ + + + + + + + + Python Module Index — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + + +

      Python Module Index

      + +
      + d +
      + + + + + + + + + + + + + + + + + + + + + + +
       
      + d
      + vergerpc +
          + vergerpc.config +
          + vergerpc.connection +
          + vergerpc.data +
          + vergerpc.exceptions +
          + vergerpc.util +
      + + +
      +
      +
      +
      +
      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/search.html b/doc/search.html new file mode 100644 index 0000000..061804e --- /dev/null +++ b/doc/search.html @@ -0,0 +1,105 @@ + + + + + + + + Search — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +

      Search

      +
      + +

      + Please activate JavaScript to enable the search + functionality. +

      +
      +

      + From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

      +
      + + + +
      + +
      + +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/searchindex.js b/doc/searchindex.js new file mode 100644 index 0000000..76694eb --- /dev/null +++ b/doc/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({titles:["vergerpc.util — Generic utilities used by verge client library","vergerpc — Convenience functions","Examples","vergerpc.exceptions — Exception definitions","API reference","Introduction","vergerpc.data — VERGE RPC service, data objects","vergerpc.config — Utilities for reading verge configuration files","Getting Started","vergerpc.connection — Connect to VERGE server via JSON-RPC","Usage","verge-python - Easy-to-use VERGE API client."],objnames:{"0":["py","module","Python module"],"1":["py","exception","Python exception"],"2":["py","method","Python method"],"3":["py","class","Python class"],"4":["py","function","Python function"],"5":["py","attribute","Python attribute"]},objtypes:{"0":"py:module","1":"py:exception","2":"py:method","3":"py:class","4":"py:function","5":"py:attribute"},objects:{"":{vergerpc:[1,0,0,"-"]},"vergerpc.util":{DStruct:[0,3,1,""]},"vergerpc.connection":{VERGEConnection:[9,3,1,""]},vergerpc:{data:[6,0,0,"-"],config:[7,0,0,"-"],util:[0,0,0,"-"],connect_to_local:[1,4,1,""],exceptions:[3,0,0,"-"],connect_to_remote:[1,4,1,""],connection:[9,0,0,"-"]},"vergerpc.exceptions":{wrap_exception:[3,4,1,""],WalletError:[3,1,1,""],NotConnected:[3,1,1,""],SafeMode:[3,1,1,""],VERGEException:[3,1,1,""],DownloadingBlocks:[3,1,1,""],InvalidParameter:[3,1,1,""],WalletPassphraseIncorrect:[3,1,1,""],InvalidTransactionID:[3,5,1,""],WalletEncryptionFailed:[3,1,1,""],SendError:[3,5,1,""],WalletWrongEncState:[3,1,1,""],ClientException:[3,1,1,""],OutOfMemory:[3,1,1,""],TransportException:[3,1,1,""],WalletUnlockNeeded:[3,1,1,""],KeypoolRanOut:[3,1,1,""],WalletAlreadyUnlocked:[3,1,1,""],JSONTypeError:[3,1,1,""],InvalidAddressOrKey:[3,1,1,""],InsufficientFunds:[3,1,1,""],InvalidAmount:[3,5,1,""],InvalidAccountName:[3,1,1,""]},"vergerpc.data":{MiningInfo:[6,3,1,""],AccountInfo:[6,3,1,""],TransactionInfo:[6,3,1,""],WorkItem:[6,3,1,""],ServerInfo:[6,3,1,""],AddressInfo:[6,3,1,""],AddressValidation:[6,3,1,""]},"vergerpc.connection.VERGEConnection":{getaccountaddress:[9,2,1,""],listunspent:[9,2,1,""],getmininginfo:[9,2,1,""],getinfo:[9,2,1,""],getblock:[9,2,1,""],validateaddress:[9,2,1,""],getbalance:[9,2,1,""],listreceivedbyaccount:[9,2,1,""],sendfrom:[9,2,1,""],sendtoaddress:[9,2,1,""],stop:[9,2,1,""],backupwallet:[9,2,1,""],listtransactions:[9,2,1,""],keypoolrefill:[9,2,1,""],walletlock:[9,2,1,""],setaccount:[9,2,1,""],getrawtransaction:[9,2,1,""],getreceivedbyaccount:[9,2,1,""],decoderawtransaction:[9,2,1,""],getreceivedbyaddress:[9,2,1,""],move:[9,2,1,""],getgenerate:[9,2,1,""],setgenerate:[9,2,1,""],getconnectioncount:[9,2,1,""],signmessage:[9,2,1,""],gettransaction:[9,2,1,""],getblockcount:[9,2,1,""],getblocknumber:[9,2,1,""],verifymessage:[9,2,1,""],walletpassphrasechange:[9,2,1,""],getdifficulty:[9,2,1,""],getaddressesbyaccount:[9,2,1,""],walletpassphrase:[9,2,1,""],sendmany:[9,2,1,""],listaccounts:[9,2,1,""],dumpprivkey:[9,2,1,""],getaccount:[9,2,1,""],gettxout:[9,2,1,""],listreceivedbyaddress:[9,2,1,""],getwork:[9,2,1,""],getblockhash:[9,2,1,""],getnewaddress:[9,2,1,""],importprivkey:[9,2,1,""],gethashespersec:[9,2,1,""],createrawtransaction:[9,2,1,""],signrawtransaction:[9,2,1,""]},"vergerpc.config":{read_config_file:[7,4,1,""],read_default_config:[7,4,1,""]}},envversion:43,filenames:["vergerpc.util","vergerpc","examples","vergerpc.exceptions","apireference","introduction","vergerpc.data","vergerpc.config","gettingstarted","vergerpc.connection","usage","index"],terms:{currentblocktx:6,also:10,paytxfe:6,doe:2,credit:9,ran:3,etc:3,block:[3,9,2,6],spend:9,usag:[],even:5,clientexcept:3,raw:[9,5],again:[9,10],all:9,between:10,main:10,specifi:[9,5,10],get:[],time:9,proxi:6,getbal:[9,10],origin:2,argument:[9,1,7,10],about:[9,10],give:10,node:9,level:[3,5],isvalid:[6,10],signatur:9,dat:9,move:[9,2,6],access:[11,5],skip:9,args_t:[0,6],com:10,getconnectioncount:9,passphras:[3,9],invalidaccountnam:3,ismin:6,implement:5,enabl:[9,6],args_d:[0,6],last:9,associ:[9,6],pars:[5,7],tri:9,deni:3,program:[5,2],importprivkei:9,found:3,effici:0,output:9,insufficientfund:[3,2],load:5,friendli:5,handl:5,getgener:9,yoyodyn:10,timestamp:6,command:[3,10],same:5,unneccesari:5,either:[9,10],variou:9,"function":[],getinfo:[9,5,2,10,6],disadvantag:5,dont_rais:9,"class":[0,9,6,3],"case":[5,2],consid:9,abl:[9,10],insuffici:3,invalidtransactionid:3,server:[],util:[],sourc:9,connect_to_loc:[1,2,10],hashespersec:6,more:[0,5,10,3],createrawtransact:9,unspent:9,maxconf:9,account:[],wrap:5,pass:3,invalidparamet:3,p2p:3,raw_detail:3,error:[3,5,6,7],serial:9,verbos:9,thin:[9,5],getdifficulti:9,onc:10,readabl:9,retriev:2,actual:5,private_kei:9,out:[3,10],input:9,onli:[9,6],vergeconnect:[9,1,2],peer:[3,11],bar:10,broke:2,gettransact:9,four:10,easi:[],requir:[9,5],thank:10,call:[3,9,2],pay_to:10,given:[3,9],conceptu:5,automat:5,outofmemori:3,unlock:[3,9],incorrect:3,look:2,"true":[9,6],than:9,count:9,minconf:9,thi:[1,2,3,5,9,10],acct:9,defin:[3,9],unless:9,listunsp:9,proof:9,introduct:[],conf:10,altcoin:9,copi:9,queri:9,produc:9,conn:[9,2,10],oper:3,localhost:[9,1],validateaddress:[9,6,10],accountinfo:[9,6],must:10,you:[9,5,10],done:10,walletpassphras:[3,9],goal:5,first:[3,9,2,6],processor:[9,6],simpli:[5,10],fee:6,"default":[9,1,7,10],vergeaddress:9,code:[3,5],otheraccount:6,chain:9,transact:[3,9,6],password:[5,9,1,10],unicod:9,pleas:10,setaccount:9,credenti:10,add:[9,5],multipl:[9,10],specif:3,fund:[3,2,6],latest:9,dynam:0,script:5,verged:[3,5,10],enter:3,unexpect:3,never:3,support:5,own:1,make:5,unabl:7,transport:3,version:6,memori:[0,9,3],name:[3,9,6],after:[9,6,10],host:[9,1,10],certain:[9,10],most:[6,10],getreceivedbyaccount:9,testnet:6,transcat:9,gettxout:9,cryptocurr:11,disablesafemod:3,page:[11,5],befor:9,mode:3,separ:10,walletpassphraseincorrect:[3,9],gethashespersec:9,attempt:5,much:10,confirm:[9,6],list:9,directori:[9,7,10],ioerror:7,altern:1,easiest:10,subclass:5,should:9,walletalreadyunlock:3,occur:7,buffer:6,work:9,here:5,manual:5,fill:9,pythonish:5,thei:9,cleaner:5,from_:9,togeth:10,dstruct:[0,6],haven:9,machin:[5,1,2,10],minimum:9,site:5,previou:[9,10],jsonrpc:5,receiv:[3,9,6,10],human:9,getblocknumb:9,fail:[3,9],decod:9,high:5,filenam:[9,1,7],your:[9,10],compar:5,connect:[],"while":9,been:10,advanc:10,map:9,how:[],read_config_fil:7,approach:5,includeempti:9,simpl:[0,5,7],keep:9,redeemscript:9,serviceproxi:5,paramet:[3,9,10],base58:9,right:5,deprec:9,coin:[9,10],problem:3,midstat:6,per:[9,6],whether:[9,10],failur:3,mempool:9,transactioninfo:[9,6],standard:[1,7],from:[],sent:6,fromaccount:9,modul:11,blockchain:9,validat:6,open:7,two:10,success:9,precomput:6,solv:9,send:[9,6,10],"new":[9,10],convert:[3,5],getaccountaddress:9,getmininginfo:[9,6],allow:[9,10,11],integr:5,privat:9,signmessag:9,softwar:10,set:[],current:[7,9,2,10,6],remov:9,basic:[2,10],remot:[],perform:9,merchant:5,recommend:9,previous_transact:9,see:10,via:[],hostnam:10,limit:6,serverinfo:[9,6],valueerror:7,best:9,use_http:[9,1],which:[9,6],walletencryptionfail:3,mkzbybiq6dnoqekakpmjegydbw2yinqnht:9,locat:[1,7],senderror:3,signrawtransact:9,transportexcept:3,repres:9,listaccount:9,setgener:9,local:[1,2,10],gener:[],configur:[],rpc:[],oldest:6,categori:6,whose:9,walleterror:3,chang:9,pirat:10,search:11,possibl:[9,5],littl:6,transactiond:9,second:[9,6],sign:9,prepar:10,destin:9,timeout:9,recent:[9,6],form:9,longest:9,workitem:[9,6],vout:9,futur:5,"11yemximso2rsfvfbcca616npbvggxibx":5,number:[9,6],encod:9,sendmani:9,made:10,except:[],tovergeaddress:9,jsontypeerror:3,epoch:6,keypoolrefil:[3,9],explicitli:[5,10],getnewaddress:[9,10],were:6,safemod:3,as_dict:9,less:[0,9],begin:10,a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c:9,todict:9,dure:3,maxim:9,comment_to:9,none:[3,9,1,7],notconnect:3,object:[],clear:10,yet:9,accept:10,network:[3,6],instanc:[1,2,10],place:10,collect:0,rpcuser:10,sendfrom:9,mstgam1apjejfswfaarvazhrm26mv5gl73:10,least:9,each:9,howev:[5,10],verge:[],mine:9,depend:9,"try":2,alia:3,off:9,txid:[9,6],"float":9,submit:9,anoth:9,vergeexcept:[3,5],downloadingblock:3,target:6,ship:10,automag:10,listreceivedbyaddress:[9,5,6],read:[],detail:[9,10],config:[],easier:5,encrypt:[3,9,6],custom:10,authent:9,amount:[9,6,10],addressvalid:[9,6],verifymessag:9,backup:9,getreceivedbyaddress:[9,10],control:[],sinc:6,home:[7,10],background:10,path:[9,1,7],verifi:9,fals:[9,1,6],endian:6,hash1:6,print:[2,10],still:[3,5],utxo:9,hexstr:9,have:[2,10],file:[],download:3,unspecifi:3,behav:9,wrong:3,alreadi:3,unlimit:9,oldpassphras:9,pai:6,structur:0,els:10,dictionari:[9,5],type:[3,9],walletwrongencst:3,definit:[],document:[5,10],complex:5,getaddressesbyaccount:9,initi:5,statist:2,balanc:[9,6,10],instead:[9,5],real:6,plan:5,want:10,turn:9,complet:[3,9],python:[],round:9,decrypt:9,rais:[3,9,7],interfac:5,anyth:10,log:[9,10],unlocked_until:6,belong:9,some:[5,2],wallet:[],"catch":2,book:9,walletlock:9,json:[],comment:9,bool:9,releas:5,cours:5,non:[1,7],conveni:[],run:[3,5,2,10],half:6,vergerpc:[],sandwidth:10,like:[0,9,2],payment:[9,5,10],keypool:[3,9,6],check:[5,10],state:[3,9,6],total:[9,6],newpassphras:9,wrap_except:3,string:9,msg:3,exampl:[],foo:[5,10],stop:9,size:6,sort:10,invalidaddressorkei:3,mai:9,usernam:5,format:[9,5,6],wai:10,testaccount2:2,messag:[9,6],field:5,invalid:[3,10],addressinfo:[9,6],neccesari:10,mani:10,data:[],measur:9,getwork:[9,6],gatewai:5,content:[11,5],pool:[9,6],user:[1,2,5,7,9,10],connect_to_remot:[1,10],base:[0,9,5,6,3],contain:9,top:5,"public":9,mininginfo:[9,6],safe:[3,9,10],superclass:3,protocol:3,keypoolranout:3,delimit:7,getblock:9,getaccount:9,walletpassphrasechang:9,rescan:9,hash:[9,6],listreceivedbyaccount:[9,5,6],decoderawtransact:9,better:5,"import":[9,5,2,10],currentblocks:6,str:9,inform:[9,2,10,6],getrawtransact:9,within:10,method:[9,10],correct:10,difficulti:[9,2,6],provid:[3,9,10],backupwallet:9,jsonexcept:5,info:[9,2],port:[9,1,10],listtransact:[9,5,6],pooledtx:6,empti:9,sendtoaddress:[9,5,10],advantag:5,rpcpassword:10,servic:[],ani:[3,9,6,10],address:[3,9,5,6,10],avail:[9,2],thing:5,creat:[9,5,10],valid:[9,10],scriptpubkei:9,major:5,includ:[9,6],write:10,walletunlockneed:3,dogeconf:10,keypoololdest:6,genproclimit:[9,6],disabl:9,option:[9,1,7],builtin:[0,9,3],lock:[9,6],index:[9,11],nearest:9,wrapper:[9,5],getblockcount:9,veri:5,valu:9,transfer:9,http:[5,10],privkei:9,store:[9,10],directli:5,can:[9,5,10],when:10,invalidamount:3,paid:[9,6],around:[9,5],now:5,constructor:9,need:9,flexibl:0,kei:[3,9,6],process:10,testaccount:2,hex:9,read_default_config:7,"return":[1,2,5,6,9,10],micro:5,bank:10,getblockhash:9,dumpprivkei:9,toaccount:9,other:[3,9,5,6],enough:2,client:[],result:9,namedtupl:0},titleterms:{config:7,conveni:1,how:10,"function":1,introduct:5,object:6,set:10,easi:11,refer:4,remot:10,server:9,util:[0,7],control:10,exampl:2,usag:10,vergerpc:[0,1,3,7,6,9],python:[11,10],via:9,connect:[9,10],account:10,wallet:10,definit:3,indic:11,file:7,tabl:11,read:7,from:10,except:3,servic:6,data:6,librari:0,verge:[0,6,7,9,10,11],gener:0,json:9,get:8,configur:7,rpc:[9,6],api:[4,10,11],start:8,client:[0,11]}}) \ No newline at end of file diff --git a/doc/usage.html b/doc/usage.html new file mode 100644 index 0000000..88f729a --- /dev/null +++ b/doc/usage.html @@ -0,0 +1,226 @@ + + + + + + + + Usage — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Usage

      +

      See also the `main verge documentation`_ for details and background on setting up and +using verged remotely.

      +
      +

      Setting up verge for remote control

      +

      If you run VERGE with the -server argument, or if you run verged, it can be controlled +either by sending it HTTP-JSON-RPC commands.

      +

      However, beginning with VERGE 0.3.3 you must create a verge.conf file in the VERGE data directory +(default $HOME/.dogeconf) and set an RPC password:

      +
      rpcuser=anything
      +rpcpassword=anything
      +
      +
      +

      Once that is done, the easiest way to check whether VERGE accepts remote commands is by running +VERGE again, with the command (and any parameters) as arguments. For example:

      +
      $ verged getinfo
      +
      +
      +
      +
      +

      Connecting to the wallet from Python

      +

      There are two functions for this:

      +
      +
      Connecting to local verge instance
      +

      Use the function connect_to_local(). This automagically +sorts out the connection to a verge process running on the current machine, +for the current user.

      +
      conn = vergerpc.connect_to_local()
      +
      +
      +
      +
      Connecting to a remote verge instance
      +

      Use the function connect_to_remote(). For this function +it is neccesary to explicitly specify a hostname and port to connect to, and +to provide user credentials for logging in.

      +
      conn = vergerpc.connect_to_remote('foo', 'bar', host='payments.yoyodyne.com', port=8332)
      +
      +
      +
      +
      +
      +
      +

      How to use the API

      +

      For basic sending and receiving of payments, the four most important methods are

      +
      +
      Getting the current balance
      +

      Use the method getbalance() to get the current server balance.

      +
      print "Your balance is %f" % (conn.getbalance(),)
      +
      +
      +
      +
      Check a customer address for validity and get information about it
      +

      This can be done with the method validateaddress().

      +
      rv = conn.validateaddress(foo)
      +if rv.isvalid:
      +    print "The address that you provided is valid"
      +else:
      +    print "The address that you provided is invalid, please correct"
      +
      +
      +
      +
      Sending payments
      +

      The method sendtoaddress() sends a specified +amount of coins to a specified address.

      +
      conn.sendtoaddress("msTGAm1ApjEJfsWfAaRVaZHRm26mv5GL73", 20.0)
      +
      +
      +
      +
      Get a new address for accepting payments
      +

      To accept payments, use the method getnewaddress() +to generate a new address. Give this address to the customer and store it in a safe place, to be able to check +when the payment to this address has been made.

      +
      pay_to = conn.getnewaddress()
      +print "We will ship the pirate sandwidth after payment of 200 coins to ", pay_to
      +
      +
      +
      +
      Check how much has been received at a certain address
      +

      The method getreceivedbyaddress() +returns how many verges have been received at a certain address. Together with the +previous function, this can be used to check whether a payment has been made +by the customer.

      +
      amount = conn.getreceivedbyaddress(pay_to)
      +if amount > 200.0:
      +    print "Thanks, your sandwidth will be prepared and shipped."
      +
      +
      +
      +
      +
      +
      +

      The account API

      +

      More advanced usage of verge allows multiple accounts within one wallet. This +can be useful if you are writing software for a bank, or +simply want to have a clear separation between customers payments.

      +

      For this, see the Account API documentation.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Introduction

      +

      Next topic

      +

      Examples

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/vergerpc.config.html b/doc/vergerpc.config.html new file mode 100644 index 0000000..449c256 --- /dev/null +++ b/doc/vergerpc.config.html @@ -0,0 +1,128 @@ + + + + + + + + vergerpc.config — Utilities for reading verge configuration files — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      vergerpc.config — Utilities for reading verge configuration files

      +

      Utilities for reading verge configuration files.

      +
      +
      +vergerpc.config.read_config_file(filename)
      +

      Read a simple '='-delimited config file. +Raises IOError if unable to open file, or ValueError +if an parse error occurs.

      +
      + +
      +
      +vergerpc.config.read_default_config(filename=None)
      +

      Read verge default configuration from the current user’s home directory.

      +

      Arguments:

      +
        +
      • filename: Path to a configuration file in a non-standard location (optional)
      • +
      +
      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      vergerpc.data — VERGE RPC service, data objects

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/vergerpc.connection.html b/doc/vergerpc.connection.html new file mode 100644 index 0000000..e76c8ee --- /dev/null +++ b/doc/vergerpc.connection.html @@ -0,0 +1,690 @@ + + + + + + + + vergerpc.connection — Connect to VERGE server via JSON-RPC — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      vergerpc.connection — Connect to VERGE server via JSON-RPC

      +

      Connect to VERGE server via JSON-RPC.

      +
      +
      +class vergerpc.connection.VERGEConnection(user, password, host='localhost', port=20102, use_https=False)
      +

      Bases: builtins.object

      +

      A VERGEConnection object defines a connection to a verge server. +It is a thin wrapper around a JSON-RPC API connection.

      +

      Arguments to constructor:

      +
        +
      • user – Authenticate as user.
      • +
      • password – Authentication password.
      • +
      • host – VERGE JSON-RPC host.
      • +
      • port – VERGE JSON-RPC port.
      • +
      +
      +
      +backupwallet(destination)
      +

      Safely copies wallet.dat to destination, which can be a directory or a path +with filename.

      +

      Arguments: +- destination – directory or path with filename to backup wallet to.

      +
      + +
      +
      +createrawtransaction(inputs, outputs)
      +

      Creates a raw transaction spending given inputs +(a list of dictionaries, each containing a transaction id and an output number), +sending to given address(es).

      +

      Returns hex-encoded raw transaction.

      +

      Example usage: +>>> conn.createrawtransaction(

      +
      +
      +
      [{“txid”: “a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c”,
      +
      “vout”: 0}],
      +
      +

      {“DkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT”:50})

      +
      +

      Arguments:

      +
        +
      • inputs – A list of {“txid”: txid, “vout”: n} dictionaries.

        +
      • +
      • +
        outputs – A dictionary mapping (public) addresses to the amount
        +

        they are to be paid.

        +
        +
        +
      • +
      +
      + +
      +
      +decoderawtransaction(hexstring)
      +

      Produces a human-readable JSON object for a raw transaction.

      +

      Arguments:

      +
        +
      • hexstring – A hex string of the transaction to be decoded.
      • +
      +
      + +
      +
      +dumpprivkey(address)
      +

      Returns the private key belonging to <address>.

      +

      Arguments:

      +
        +
      • address – VERGE address whose private key should be returned.
      • +
      +
      + +
      +
      +getaccount(vergeaddress)
      +

      Returns the account associated with the given address.

      +

      Arguments:

      +
        +
      • vergeaddress – VERGE address to get account for.
      • +
      +
      + +
      +
      +getaccountaddress(account)
      +

      Returns the current verge address for receiving payments to an account.

      +

      Arguments:

      +
        +
      • account – Account for which the address should be returned.
      • +
      +
      + +
      +
      +getaddressesbyaccount(account)
      +

      Returns the list of addresses for the given account.

      +

      Arguments:

      +
        +
      • account – Account to get list of addresses for.
      • +
      +
      + +
      +
      +getbalance(account=None, minconf=None)
      +

      Get the current balance, either for an account or the total server balance.

      +

      Arguments: +- account – If this parameter is specified, returns the balance in the account. +- minconf – Minimum number of confirmations required for transferred balance.

      +
      + +
      +
      +getblock(hash)
      +

      Returns information about the given block hash.

      +
      + +
      +
      +getblockcount()
      +

      Returns the number of blocks in the longest block chain.

      +
      + +
      +
      +getblockhash(index)
      +

      Returns hash of block in best-block-chain at index.

      + +++ + + + +
      Parameters:index – index ob the block
      +
      + +
      +
      +getblocknumber()
      +

      Returns the block number of the latest block in the longest block chain. +Deprecated. Use getblockcount instead.

      +
      + +
      +
      +getconnectioncount()
      +

      Returns the number of connections to other nodes.

      +
      + +
      +
      +getdifficulty()
      +

      Returns the proof-of-work difficulty as a multiple of the minimum difficulty.

      +
      + +
      +
      +getgenerate()
      +

      Returns True or False, depending on whether generation is enabled.

      +
      + +
      +
      +gethashespersec()
      +

      Returns a recent hashes per second performance measurement while generating.

      +
      + +
      +
      +getinfo()
      +

      Returns an ServerInfo object containing various state info.

      +
      + +
      +
      +getmininginfo()
      +

      Returns an MiningInfo object containing various +mining state info.

      +
      + +
      +
      +getnewaddress(account=None)
      +

      Returns a new verge address for receiving payments.

      +

      Arguments:

      +
        +
      • account – If account is specified (recommended), it is added to the address book +so that payments received with the address will be credited to it.
      • +
      +
      + +
      +
      +getrawtransaction(txid, verbose=True)
      +

      Get transaction raw info

      +

      Arguments:

      +
        +
      • txid – Transactiond id for which the info should be returned.
      • +
      • verbose – If False, return only the “hex” of the transaction.
      • +
      +
      + +
      +
      +getreceivedbyaccount(account, minconf=1)
      +

      Returns the total amount received by addresses with an account in transactions with +at least a certain number of confirmations.

      +

      Arguments:

      +
        +
      • account – Account to query for total amount.
      • +
      • minconf – Number of confirmations to require, defaults to 1.
      • +
      +
      + +
      +
      +getreceivedbyaddress(vergeaddress, minconf=1)
      +

      Returns the total amount received by a verge address in transactions with at least a +certain number of confirmations.

      +

      Arguments:

      +
        +
      • vergeaddress – Address to query for total amount.
      • +
      • minconf – Number of confirmations to require, defaults to 1.
      • +
      +
      + +
      +
      +gettransaction(txid)
      +

      Get detailed information about transaction

      +

      Arguments:

      +
        +
      • txid – Transactiond id for which the info should be returned
      • +
      +
      + +
      +
      +gettxout(txid, index, mempool=True)
      +

      Returns details about an unspent transaction output (UTXO)

      +

      Arguments:

      +
        +
      • txid – Transactiond id for which the info should be returned.
      • +
      • index – The output index.
      • +
      • mempool – Add memory pool transactions.
      • +
      +
      + +
      +
      +getwork(data=None)
      +

      Get work for remote mining, or submit result. +If data is specified, the server tries to solve the block +using the provided data and returns True if it was successful. +If not, the function returns formatted hash data (WorkItem) +to work on.

      +

      Arguments:

      +
        +
      • data – Result from remote mining.
      • +
      +
      + +
      +
      +importprivkey(privkey, acct='', rescan=True)
      +

      import private key <privkey> to account [acct], optionally rescanning blockchain .

      +

      Arguments:

      +
        +
      • privkey – private key to import.
      • +
      • [acct] – name of account to associate with private key
      • +
      • [rescan] – rescan blockchain for transcations containing altcoin address associated with privkey
      • +
      +
      + +
      +
      +keypoolrefill()
      +

      Fills the keypool, requires wallet passphrase to be set.

      +
      + +
      +
      +listaccounts(minconf=1, as_dict=False)
      +

      Returns a list of account names.

      +

      Arguments:

      +
        +
      • minconf – Minimum number of confirmations before payments are included.
      • +
      • as_dict – Returns a dictionary of account names, with their balance as values.
      • +
      +
      + +
      +
      +listreceivedbyaccount(minconf=1, includeempty=False)
      +

      Returns a list of accounts.

      +

      Each account is represented with a AccountInfo object.

      +

      Arguments:

      +
        +
      • minconf – Minimum number of confirmations before payments are included.
      • +
      • includeempty – Whether to include addresses that haven’t received any payments.
      • +
      +
      + +
      +
      +listreceivedbyaddress(minconf=1, includeempty=False)
      +

      Returns a list of addresses.

      +

      Each address is represented with a AddressInfo object.

      +

      Arguments:

      +
        +
      • minconf – Minimum number of confirmations before payments are included.
      • +
      • includeempty – Whether to include addresses that haven’t received any payments.
      • +
      +
      + +
      +
      +listtransactions(account=None, count=10, from_=0, address=None)
      +

      Returns a list of the last transactions for an account.

      +

      Each transaction is represented with a TransactionInfo object.

      +

      Arguments:

      +
        +
      • +
        account – Account to list transactions from. Return transactions from
        +

        all accounts if None.

        +
        +
        +
      • +
      • count – Number of transactions to return.

        +
      • +
      • from_ – Skip the first <from_> transactions.

        +
      • +
      • address – Receive address to consider

        +
      • +
      +
      + +
      +
      +listunspent(minconf=1, maxconf=999999)
      +

      Returns a list of unspent transaction inputs in the wallet.

      +

      Arguments:

      +
        +
      • minconf – Minimum number of confirmations required to be listed.
      • +
      • maxconf – Maximal number of confirmations allowed to be listed.
      • +
      +
      + +
      +
      +move(fromaccount, toaccount, amount, minconf=1, comment=None)
      +

      Move from one account in your wallet to another.

      +

      Arguments:

      +
        +
      • fromaccount – Source account name.
      • +
      • toaccount – Destination account name.
      • +
      • amount – Amount to transfer.
      • +
      • minconf – Minimum number of confirmations required for transferred balance.
      • +
      • comment – Comment to add to transaction log.
      • +
      +
      + +
      +
      +sendfrom(fromaccount, tovergeaddress, amount, minconf=1, comment=None, comment_to=None)
      +

      Sends amount from account’s balance to vergeaddress. This method will fail +if there is less than amount verges with minconf confirmations in the account’s +balance (unless account is the empty-string-named default account; it +behaves like the sendtoaddress method). Returns transaction ID on success.

      +

      Arguments:

      +
        +
      • fromaccount – Account to send from.
      • +
      • tovergeaddress – VERGE address to send to.
      • +
      • amount – Amount to send (float, rounded to the nearest 0.01).
      • +
      • minconf – Minimum number of confirmations required for transferred balance.
      • +
      • comment – Comment for transaction.
      • +
      • comment_to – Comment for to-address.
      • +
      +
      + +
      +
      +sendmany(fromaccount, todict, minconf=1, comment=None)
      +

      Sends specified amounts from account’s balance to vergeaddresses. This method will fail +if there is less than total amount verges with minconf confirmations in the account’s +balance (unless account is the empty-string-named default account; Returns transaction ID +on success.

      +

      Arguments:

      +
        +
      • fromaccount – Account to send from.
      • +
      • todict – Dictionary with VERGE addresses as keys and amounts as values.
      • +
      • minconf – Minimum number of confirmations required for transferred balance.
      • +
      • comment – Comment for transaction.
      • +
      +
      + +
      +
      +sendtoaddress(vergeaddress, amount, comment=None, comment_to=None)
      +

      Sends amount from the server’s available balance to vergeaddress.

      +

      Arguments:

      +
        +
      • vergeaddress – VERGE address to send to.
      • +
      • amount – Amount to send (float, rounded to the nearest 0.00000001).
      • +
      • minconf – Minimum number of confirmations required for transferred balance.
      • +
      • comment – Comment for transaction.
      • +
      • comment_to – Comment for to-address.
      • +
      +
      + +
      +
      +setaccount(vergeaddress, account)
      +

      Sets the account associated with the given address.

      +

      Arguments:

      +
        +
      • vergeaddress – VERGE address to associate.
      • +
      • account – Account to associate the address to.
      • +
      +
      + +
      +
      +setgenerate(generate, genproclimit=None)
      +

      Enable or disable generation (mining) of coins.

      +

      Arguments:

      +
        +
      • generate – is True or False to turn generation on or off.
      • +
      • genproclimit – Number of processors that are used for generation, -1 is unlimited.
      • +
      +
      + +
      +
      +signmessage(address, message)
      +

      Sign messages, returns the signature

      + +++ + + + + + +
      Parameters:
        +
      • address (str or unicode) – VERGE address used to sign a message
      • +
      • message (str or unicode) – The message to sign
      • +
      +
      Return type:

      unicode

      +
      +
      + +
      +
      +signrawtransaction(hexstring, previous_transactions=None, private_keys=None)
      +

      Sign inputs for raw transaction (serialized, hex-encoded).

      +
      +
      Returns a dictionary with the keys:
      +
      “hex”: raw transaction with signature(s) (hex-encoded string) +“complete”: 1 if transaction has a complete set of signature(s), 0 if not
      +
      +

      Arguments:

      +
        +
      • hexstring – A hex string of the transaction to sign.

        +
      • +
      • +
        previous_transactions – A (possibly empty) list of dictionaries of the form:
        +

        {“txid”: txid, “vout”: n, “scriptPubKey”: hex, “redeemScript”: hex}, representing +previous transaction outputs that this transaction depends on but may not yet be +in the block chain.

        +
        +
        +
      • +
      • +
        private_keys – A (possibly empty) list of base58-encoded private
        +

        keys that, if given, will be the only keys used to sign the transaction.

        +
        +
        +
      • +
      +
      + +
      +
      +stop()
      +

      Stop verge server.

      +
      + +
      +
      +validateaddress(validateaddress)
      +

      Validate a verge address and return information for it.

      +

      The information is represented by a AddressValidation object.

      +

      Arguments: – Address to validate.

      +
        +
      • validateaddress
      • +
      +
      + +
      +
      +verifymessage(address, signature, message)
      +

      Verify a signed message

      + +++ + + + + + +
      Parameters:
        +
      • address (str or unicode) – VERGE address used to sign a message
      • +
      • signature (unicode) – The signature
      • +
      • message (str or unicode) – The message to sign
      • +
      +
      Return type:

      bool

      +
      +
      + +
      +
      +walletlock()
      +

      Removes the wallet encryption key from memory, locking the wallet. +After calling this method, you will need to call walletpassphrase +again before being able to call any methods which require the wallet +to be unlocked.

      +
      + +
      +
      +walletpassphrase(passphrase, timeout, dont_raise=False)
      +

      Stores the wallet decryption key in memory for <timeout> seconds.

      +
        +
      • passphrase – The wallet passphrase.

        +
      • +
      • +
        timeout – Time in seconds to keep the wallet unlocked
        +

        (by keeping the passphrase in memory).

        +
        +
        +
      • +
      • +
        dont_raise – instead of raising ~vergerpc.exceptions.WalletPassphraseIncorrect
        +

        return False.

        +
        +
        +
      • +
      +
      + +
      +
      +walletpassphrasechange(oldpassphrase, newpassphrase, dont_raise=False)
      +

      Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.

      +

      Arguments:

      +
        +
      • +
        dont_raise – instead of raising ~vergerpc.exceptions.WalletPassphraseIncorrect
        +

        return False.

        +
        +
        +
      • +
      +
      + +
      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      vergerpc — Convenience functions

      +

      Next topic

      +

      vergerpc.exceptions — Exception definitions

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/vergerpc.data.html b/doc/vergerpc.data.html new file mode 100644 index 0000000..8a222ec --- /dev/null +++ b/doc/vergerpc.data.html @@ -0,0 +1,249 @@ + + + + + + + + vergerpc.data — VERGE RPC service, data objects — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      vergerpc.data — VERGE RPC service, data objects

      +

      VERGE RPC service, data objects.

      +
      +
      +class vergerpc.data.AccountInfo(*args_t, **args_d)
      +

      Bases: vergerpc.util.DStruct

      +

      Information object returned by listreceivedbyaccount().

      +
        +
      • account – The account of the receiving address.
      • +
      • amount – Total amount received by the address.
      • +
      • confirmations – Number of confirmations of the most recent transaction included.
      • +
      +
      + +
      +
      +class vergerpc.data.AddressInfo(*args_t, **args_d)
      +

      Bases: vergerpc.util.DStruct

      +

      Information object returned by listreceivedbyaddress().

      +
        +
      • address – Receiving address.
      • +
      • account – The account of the receiving address.
      • +
      • amount – Total amount received by the address.
      • +
      • confirmations – Number of confirmations of the most recent transaction included.
      • +
      +
      + +
      +
      +class vergerpc.data.AddressValidation(*args_t, **args_d)
      +

      Bases: vergerpc.util.DStruct

      +

      Information object returned by validateaddress().

      +
        +
      • isvalid – Validatity of address (True or False).
      • +
      • ismineTrue if the address is in the server’s wallet.
      • +
      • address – VERGE address.
      • +
      +
      + +
      +
      +class vergerpc.data.MiningInfo(*args_t, **args_d)
      +

      Bases: vergerpc.util.DStruct

      +

      Information object returned by getmininginfo().

      +
        +
      • blocks – Number of blocks.
      • +
      • currentblocksize – Size of current block.
      • +
      • currentblocktx – Number of transactions in current block.
      • +
      • difficulty – Current generating difficulty.
      • +
      • errors – Number of errors.
      • +
      • generate – True if generation enabled, False if not.
      • +
      • genproclimit – Processor limit for generation.
      • +
      • hashespersec – Number of hashes per second (if generation enabled).
      • +
      • pooledtx – Number of pooled transactions.
      • +
      • testnet – True if connected to testnet, False if on real network.
      • +
      +
      + +
      +
      +class vergerpc.data.ServerInfo(*args_t, **args_d)
      +

      Bases: vergerpc.util.DStruct

      +

      Information object returned by getinfo().

      +
        +
      • errors – Number of errors.

        +
      • +
      • blocks – Number of blocks.

        +
      • +
      • paytxfee – Amount of transaction fee to pay.

        +
      • +
      • keypoololdest – Oldest key in keypool.

        +
      • +
      • genproclimit – Processor limit for generation.

        +
      • +
      • connections – Number of connections to other clients.

        +
      • +
      • difficulty – Current generating difficulty.

        +
      • +
      • testnet – True if connected to testnet, False if on real network.

        +
      • +
      • version – VERGE client version.

        +
      • +
      • proxy – Proxy configured in client.

        +
      • +
      • hashespersec – Number of hashes per second (if generation enabled).

        +
      • +
      • balance – Total current server balance.

        +
      • +
      • generate – True if generation enabled, False if not.

        +
      • +
      • +
        unlocked_until – Timestamp (seconds since epoch) after which the wallet
        +

        will be/was locked (if wallet encryption is enabled).

        +
        +
        +
      • +
      +
      + +
      +
      +class vergerpc.data.TransactionInfo(*args_t, **args_d)
      +

      Bases: vergerpc.util.DStruct

      +

      Information object returned by listtransactions().

      +
        +
      • account – account name.
      • +
      • address – the address verges were sent to, or received from.
      • +
      • category – will be generate, send, receive, or move.
      • +
      • amount – amount of transaction.
      • +
      • fee – Fee (if any) paid (only for send transactions).
      • +
      • confirmations – number of confirmations (only for generate/send/receive).
      • +
      • txid – transaction ID (only for generate/send/receive).
      • +
      • otheraccount – account funds were moved to or from (only for move).
      • +
      • message – message associated with transaction (only for send).
      • +
      • to – message-to associated with transaction (only for send).
      • +
      +
      + +
      +
      +class vergerpc.data.WorkItem(*args_t, **args_d)
      +

      Bases: vergerpc.util.DStruct

      +

      Information object returned by getwork().

      +
        +
      • midstate – Precomputed hash state after hashing the first half of the data.
      • +
      • data – Block data.
      • +
      • hash1 – Formatted hash buffer for second hash.
      • +
      • target – Little endian hash target.
      • +
      +
      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      vergerpc.exceptions — Exception definitions

      +

      Next topic

      +

      vergerpc.config — Utilities for reading verge configuration files

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/vergerpc.exceptions.html b/doc/vergerpc.exceptions.html new file mode 100644 index 0000000..48eed5f --- /dev/null +++ b/doc/vergerpc.exceptions.html @@ -0,0 +1,282 @@ + + + + + + + + vergerpc.exceptions — Exception definitions — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      vergerpc.exceptions — Exception definitions

      +

      Exception definitions.

      +
      +
      +exception vergerpc.exceptions.ClientException(error)
      +

      Bases: vergerpc.exceptions.VERGEException

      +

      P2P network error. +This exception is never raised but functions as a superclass +for other P2P client exceptions.

      +
      + +
      +
      +exception vergerpc.exceptions.VERGEException(error)
      +

      Bases: builtins.Exception

      +

      Base class for exceptions received from VERGE server.

      +
        +
      • code – Error code from verged.
      • +
      +
      + +
      +
      +exception vergerpc.exceptions.DownloadingBlocks(error)
      +

      Bases: vergerpc.exceptions.ClientException

      +

      Client is still downloading blocks.

      +
      + +
      +
      +exception vergerpc.exceptions.InsufficientFunds(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      Insufficient funds to complete transaction in wallet or account

      +
      + +
      +
      +exception vergerpc.exceptions.InvalidAccountName(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      Invalid account name

      +
      + +
      +
      +exception vergerpc.exceptions.InvalidAddressOrKey(error)
      +

      Bases: vergerpc.exceptions.VERGEException

      +

      Invalid address or key.

      +
      + +
      +
      +vergerpc.exceptions.InvalidAmount
      +

      alias of JSONTypeError

      +
      + +
      +
      +exception vergerpc.exceptions.InvalidParameter(error)
      +

      Bases: vergerpc.exceptions.VERGEException

      +

      Invalid parameter provided to RPC call.

      +
      + +
      +
      +vergerpc.exceptions.InvalidTransactionID
      +

      alias of InvalidAddressOrKey

      +
      + +
      +
      +exception vergerpc.exceptions.JSONTypeError(error)
      +

      Bases: vergerpc.exceptions.VERGEException

      +

      Unexpected type was passed as parameter

      +
      + +
      +
      +exception vergerpc.exceptions.KeypoolRanOut(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      Keypool ran out, call keypoolrefill first

      +
      + +
      +
      +exception vergerpc.exceptions.NotConnected(error)
      +

      Bases: vergerpc.exceptions.ClientException

      +

      Not connected to any peers.

      +
      + +
      +
      +exception vergerpc.exceptions.OutOfMemory(error)
      +

      Bases: vergerpc.exceptions.VERGEException

      +

      Out of memory during operation.

      +
      + +
      +
      +exception vergerpc.exceptions.SafeMode(error)
      +

      Bases: vergerpc.exceptions.VERGEException

      +

      Operation denied in safe mode (run verged with -disablesafemode).

      +
      + +
      +
      +vergerpc.exceptions.SendError
      +

      alias of WalletError

      +
      + +
      +
      +exception vergerpc.exceptions.TransportException(msg, code=None, protocol=None, raw_detail=None)
      +

      Bases: builtins.Exception

      +

      Class to define transport-level failures.

      +
      + +
      +
      +exception vergerpc.exceptions.WalletAlreadyUnlocked(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      Wallet is already unlocked

      +
      + +
      +
      +exception vergerpc.exceptions.WalletEncryptionFailed(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      Failed to encrypt the wallet

      +
      + +
      +
      +exception vergerpc.exceptions.WalletError(error)
      +

      Bases: vergerpc.exceptions.VERGEException

      +

      Unspecified problem with wallet (key not found etc.)

      +
      + +
      +
      +exception vergerpc.exceptions.WalletPassphraseIncorrect(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      The wallet passphrase entered was incorrect

      +
      + +
      +
      +exception vergerpc.exceptions.WalletUnlockNeeded(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      Enter the wallet passphrase with walletpassphrase first

      +
      + +
      +
      +exception vergerpc.exceptions.WalletWrongEncState(error)
      +

      Bases: vergerpc.exceptions.WalletError

      +

      Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)

      +
      + +
      +
      +vergerpc.exceptions.wrap_exception(error)
      +

      Convert a JSON error object to a more specific VERGE exception.

      +
      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      vergerpc.connection — Connect to VERGE server via JSON-RPC

      +

      Next topic

      +

      vergerpc.data — VERGE RPC service, data objects

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/vergerpc.html b/doc/vergerpc.html new file mode 100644 index 0000000..0a7f4d5 --- /dev/null +++ b/doc/vergerpc.html @@ -0,0 +1,140 @@ + + + + + + + + vergerpc — Convenience functions — verge-python 0.1.3 documentation + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      vergerpc — Convenience functions

      +

      verge-python - Easy-to-use VERGE API client

      +
      +
      +vergerpc.connect_to_local(filename=None)
      +

      Connect to default VERGE instance owned by this user, on this machine.

      +

      Returns a VERGEConnection object.

      +

      Arguments:

      +
      +
        +
      • filename: Path to a configuration file in a non-standard location (optional)
      • +
      +
      +
      + +
      +
      +vergerpc.connect_to_remote(user, password, host='localhost', port=22555, use_https=False)
      +

      Connect to remote or alternative local verge client instance.

      +

      Returns a VERGEConnection object.

      +
      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      API reference

      +

      Next topic

      +

      vergerpc.connection — Connect to VERGE server via JSON-RPC

      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/doc/vergerpc.util.html b/doc/vergerpc.util.html new file mode 100644 index 0000000..0972c5a --- /dev/null +++ b/doc/vergerpc.util.html @@ -0,0 +1,105 @@ + + + + + + + + vergerpc.util — Generic utilities used by verge client library — verge-python 0.1.3 documentation + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      vergerpc.util — Generic utilities used by verge client library

      +

      Generic utilities used by verge client library.

      +
      +
      +class vergerpc.util.DStruct(*args_t, **args_d)
      +

      Bases: builtins.object

      +

      Simple dynamic structure, like collections.namedtuple but more flexible +(and less memory-efficient)

      +
      + +
      + + +
      +
      +
      +
      +
      +

      This Page

      + + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/release_process.txt b/release_process.txt new file mode 100644 index 0000000..850eb10 --- /dev/null +++ b/release_process.txt @@ -0,0 +1,29 @@ +Release process + +- Update Changelog (using git history output from dist-tools/changelog.sh) + +- Change version numbers in setup.py and sphinx/source/conf.py + +- Commit + +- Make tag and upload to github + + - git tag -a vX.X + - git push origin vX.X + +- Run make in doc/ + +- Update documentation on github + + - git checkout gh_pages + - rm -r doc + - mkdir doc + - cp -r sphinx/build/html/* doc/ + - git add doc + - git commit -a + - git push origin gh-pages:gh-pages + +- Upload to pypi + + - python setup.py sdist upload + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..05c9b86 --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +from setuptools import setup, find_packages +setup( + name='verge-python', + version='0.1.3', + description='Friendly VERGE JSON-RPC API binding for Python', + long_description='This package allows performing commands such as listing the current balance' + ' and sending coins to the original client from Python. The communication with the' + ' client happens over JSON-RPC.', + url='https://github.com/vergecurrency/verge-python', + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + 'Environment :: Web Environment', + 'Intended Audience :: Developers', + 'Programming Language :: Python', + 'License :: OSI Approved :: MIT License', + 'Topic :: Office/Business :: Financial' + ], + packages=find_packages("src"), + package_dir={'': 'src'} +) diff --git a/sphinx/Makefile b/sphinx/Makefile new file mode 100644 index 0000000..60830db --- /dev/null +++ b/sphinx/Makefile @@ -0,0 +1,89 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/verge-python.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/verge-python.qhc" + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ + "run these through (pdf)latex." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/sphinx/make.bat b/sphinx/make.bat new file mode 100644 index 0000000..5a7fe90 --- /dev/null +++ b/sphinx/make.bat @@ -0,0 +1,113 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +set SPHINXBUILD=sphinx-build +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\verge-python.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\verge-python.ghc + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/sphinx/source/apireference.rst b/sphinx/source/apireference.rst new file mode 100644 index 0000000..795a567 --- /dev/null +++ b/sphinx/source/apireference.rst @@ -0,0 +1,13 @@ +================= + API reference +================= + +.. toctree:: + :maxdepth: 2 + + vergerpc.rst + vergerpc.connection.rst + vergerpc.exceptions.rst + vergerpc.data.rst + vergerpc.config.rst + diff --git a/sphinx/source/conf.py b/sphinx/source/conf.py new file mode 100644 index 0000000..b2a66b9 --- /dev/null +++ b/sphinx/source/conf.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +# +# verge-python documentation build configuration file, created by +# sphinx-quickstart on Fri Dec 10 21:45:49 2010. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.append(os.path.abspath('../../src')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'verge-python' +copyright = u'2016, verge-python developers' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1' +# The full version, including alpha/beta/rc tags. +release = '0.1.3' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ['_theme'] +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_use_modindex = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'verge-pythondoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'verge-python.tex', u'verge-python Documentation', + u'Witchspace', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True diff --git a/sphinx/source/examples.rst b/sphinx/source/examples.rst new file mode 100644 index 0000000..61cdaa0 --- /dev/null +++ b/sphinx/source/examples.rst @@ -0,0 +1,43 @@ +**************************** + Examples +**************************** + +A basic program that uses ``python-verge`` looks like this: + +First, import the library and exceptions. + +:: + + import vergerpc + from vergerpc.exceptions import InsufficientFunds + +Then, we connect to the currently running ``verge`` instance of the current user on the local machine +with one call to +:func:`~vergerpc.connect_to_local`. This returns a :class:`~vergerpc.connection.VERGEConnection` objects: + +:: + + conn = vergerpc.connect_to_local() + +Try to move one verge from account ``testaccount`` to account ``testaccount2`` using +:func:`~vergerpc.connection.VERGEConnection.move`. Catch the :class:`~vergerpc.exceptions.InsufficientFunds` +exception in the case the originating account is broke: + +:: + + try: + conn.move("testaccount", "testaccount2", 100.0) + except InsufficientFunds,e: + print "Account does not have enough funds available!" + + +Retrieve general server information with :func:`~vergerpc.connection.VERGEConnection.getinfo` and print some statistics: + +:: + + info = conn.getinfo() + print "Blocks: %i" % info.blocks + print "Connections: %i" % info.connections + print "Difficulty: %f" % info.difficulty + + diff --git a/sphinx/source/gettingstarted.rst b/sphinx/source/gettingstarted.rst new file mode 100644 index 0000000..4b34042 --- /dev/null +++ b/sphinx/source/gettingstarted.rst @@ -0,0 +1,11 @@ +================= + Getting Started +================= + +.. toctree:: + :maxdepth: 2 + + introduction.rst + usage.rst + examples.rst + diff --git a/sphinx/source/index.rst b/sphinx/source/index.rst new file mode 100644 index 0000000..92eeeb0 --- /dev/null +++ b/sphinx/source/index.rst @@ -0,0 +1,24 @@ +================================================== + verge-python - Easy-to-use VERGE API client. +================================================== + +``verge-python`` is a set of Python libraries that allows easy access to the +verge_ peer-to-peer cryptocurrency client API. + +Contents: + +.. toctree:: + :maxdepth: 2 + + gettingstarted.rst + apireference.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +.. _verge: http://vergecurrency.com/ + diff --git a/sphinx/source/introduction.rst b/sphinx/source/introduction.rst new file mode 100644 index 0000000..bc882b3 --- /dev/null +++ b/sphinx/source/introduction.rst @@ -0,0 +1,47 @@ +**************************** + Introduction +**************************** + +The goal of this library is to make it easier for: + +- Payment gateways to support verge +- Merchant sites to integrate verge payments directly +- Other services that require (micro-)payments to use verge + +In this initial release it implements a thin wrapper around the +VERGE JSON-RPC API. Using this API from Python directly is conceptually very simple, +here is the example from the API +documentation page: + +:: + + from jsonrpc import ServiceProxy + + access = ServiceProxy("http://user:password@127.0.0.1:20102") + access.getinfo() + access.listreceivedbyaddress(6) + access.sendtoaddress("11yEmxiMso2RsFVfBcCa616npBvGgxiBX", 1000) + +However, this approach has some disadvantages, one thing is that error handling is complex, as it +requires manually checking the contents of :const:`JSONException` objects. + +``verge-python`` attempts to create an even more friendly interface by wrapping the JSON-RPC API. The major advantages +compared to a raw ``jsonrpc`` based approach are: + +- Better exception handling. Exceptions are converted to subclasses of :class:`~vergerpc.exceptions.VERGEException`. + +- Automatic verge configuration loading. In case the ``verge -server`` or ``verged`` program runs on the same + machine as the client script, and as the same user, the configuration file can automatically be parsed. This + makes it unneccesary to explicitly specify a *username* and *password*. Of course, this is still possible. + +- Documentation in Pythonish format. You are reading this right now. + +- The functions + :func:`~vergerpc.connection.VERGEConnection.getinfo`, :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaccount`, + :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaddress`, + :func:`~vergerpc.connection.VERGEConnection.listtransactions` and more return actual Python objects, instead of simply + dictionaries. This makes for cleaner code, as the fields can simply be addressed with ``x.foo`` instead of + ``x['foo']``. + +The plan for future releases is to add a more high-level interface on top of this. + diff --git a/sphinx/source/usage.rst b/sphinx/source/usage.rst new file mode 100644 index 0000000..2835644 --- /dev/null +++ b/sphinx/source/usage.rst @@ -0,0 +1,120 @@ +================= + Usage +================= + +See also the `main verge documentation`_ for details and background on setting up and +using verged remotely. + +Setting up verge for remote control +------------------------------------- + +If you run VERGE with the ``-server`` argument, or if you run ``verged``, it can be controlled +either by sending it HTTP-JSON-RPC commands. + +However, beginning with VERGE 0.3.3 you must create a ``VERGE.conf`` file in the VERGE data directory +(default ``$HOME/.vergeconf``) and set an RPC password: + +:: + + rpcuser=anything + rpcpassword=anything + +Once that is done, the easiest way to check whether VERGE accepts remote commands is by running +VERGE again, with the command (and any parameters) as arguments. For example: + +:: + + $ verged getinfo + +Connecting to the wallet from Python +------------------------------------- + +There are two functions for this: + +*Connecting to local verge instance* + Use the function :func:`~vergerpc.connect_to_local`. This automagically + sorts out the connection to a verge process running on the current machine, + for the current user. + + :: + + conn = vergerpc.connect_to_local() + +*Connecting to a remote verge instance* + Use the function :func:`~vergerpc.connect_to_remote`. For this function + it is neccesary to explicitly specify a hostname and port to connect to, and + to provide user credentials for logging in. + + :: + + conn = vergerpc.connect_to_remote('foo', 'bar', host='payments.yoyodyne.com', port=20102) + + +How to use the API +------------------------------------- + +For basic sending and receiving of payments, the four most important methods are + +*Getting the current balance* + Use the method :func:`~vergerpc.connection.VERGEConnection.getbalance` to get the current server balance. + + :: + + print "Your balance is %f" % (conn.getbalance(),) + +*Check a customer address for validity and get information about it* + This can be done with the method :func:`~vergerpc.connection.VERGEConnection.validateaddress`. + + :: + + rv = conn.validateaddress(foo) + if rv.isvalid: + print "The address that you provided is valid" + else: + print "The address that you provided is invalid, please correct" + +*Sending payments* + The method :func:`~vergerpc.connection.VERGEConnection.sendtoaddress` sends a specified + amount of coins to a specified address. + + :: + + conn.sendtoaddress("msTGAm1ApjEJfsWfAaRVaZHRm26mv5GL73", 10000.0) + +*Get a new address for accepting payments* + To accept payments, use the method :func:`~vergerpc.connection.VERGEConnection.getnewaddress` + to generate a new address. Give this address to the customer and store it in a safe place, to be able to check + when the payment to this address has been made. + + :: + + pay_to = conn.getnewaddress() + print "We will ship the pirate sandwidth after payment of 200 coins to ", pay_to + +*Check how much has been received at a certain address* + The method :func:`~vergerpc.connection.VERGEConnection.getreceivedbyaddress` + returns how many verges have been received at a certain address. Together with the + previous function, this can be used to check whether a payment has been made + by the customer. + + :: + + amount = conn.getreceivedbyaddress(pay_to) + if amount > 20000.0: + print "Thanks, your order will be prepared and shipped." + + + + +The account API +------------------------------------- +More advanced usage of verge allows multiple accounts within one wallet. This +can be useful if you are writing software for a bank, or +simply want to have a clear separation between customers payments. + +For this, see the `Account API`_ documentation. + +.. _main bitcoin documentation: https://en.bitcoin.it/wiki/Main_Page +.. _account API: https://en.bitcoin.it/wiki/Accounts_explained + + diff --git a/sphinx/source/vergerpc.config.rst b/sphinx/source/vergerpc.config.rst new file mode 100644 index 0000000..50afc27 --- /dev/null +++ b/sphinx/source/vergerpc.config.rst @@ -0,0 +1,7 @@ +:mod:`vergerpc.config` --- Utilities for reading verge configuration files +==================================================================================== + +.. automodule:: vergerpc.config + :members: + :show-inheritance: + diff --git a/sphinx/source/vergerpc.connection.rst b/sphinx/source/vergerpc.connection.rst new file mode 100644 index 0000000..922fc9f --- /dev/null +++ b/sphinx/source/vergerpc.connection.rst @@ -0,0 +1,8 @@ +:mod:`vergerpc.connection` --- Connect to VERGE server via JSON-RPC +==================================================================================== + +.. automodule:: vergerpc.connection + :members: + :show-inheritance: + + diff --git a/sphinx/source/vergerpc.data.rst b/sphinx/source/vergerpc.data.rst new file mode 100644 index 0000000..fe3a16b --- /dev/null +++ b/sphinx/source/vergerpc.data.rst @@ -0,0 +1,7 @@ +:mod:`vergerpc.data` --- VERGE RPC service, data objects +==================================================================================== + +.. automodule:: vergerpc.data + :members: + :show-inheritance: + diff --git a/sphinx/source/vergerpc.exceptions.rst b/sphinx/source/vergerpc.exceptions.rst new file mode 100644 index 0000000..ae74eb7 --- /dev/null +++ b/sphinx/source/vergerpc.exceptions.rst @@ -0,0 +1,7 @@ +:mod:`vergerpc.exceptions` --- Exception definitions +==================================================================================== + +.. automodule:: vergerpc.exceptions + :members: + :show-inheritance: + diff --git a/sphinx/source/vergerpc.rst b/sphinx/source/vergerpc.rst new file mode 100644 index 0000000..e931a6b --- /dev/null +++ b/sphinx/source/vergerpc.rst @@ -0,0 +1,7 @@ +:mod:`vergerpc` --- Convenience functions +==================================================================================== + +.. automodule:: vergerpc + :members: + :show-inheritance: + diff --git a/sphinx/source/vergerpc.util.rst b/sphinx/source/vergerpc.util.rst new file mode 100644 index 0000000..81bb6db --- /dev/null +++ b/sphinx/source/vergerpc.util.rst @@ -0,0 +1,7 @@ +:mod:`vergerpc.util` --- Generic utilities used by verge client library +==================================================================================== + +.. automodule:: vergerpc.util + :members: + :show-inheritance: + diff --git a/src/vergerpc/__init__.py b/src/vergerpc/__init__.py new file mode 100644 index 0000000..96e3046 --- /dev/null +++ b/src/vergerpc/__init__.py @@ -0,0 +1,58 @@ +# Copyright (c) 2010 Witchspace +# +# 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. +""" +verge-python - Easy-to-use VERGE API client +""" + + +def connect_to_local(filename=None): + """ + Connect to default verge instance owned by this user, on this machine. + + Returns a :class:`~vergerpc.connection.VERGEConnection` object. + + Arguments: + + - `filename`: Path to a configuration file in a non-standard location (optional) + """ + from vergerpc.connection import VERGEConnection + from vergerpc.config import read_default_config + + cfg = read_default_config(filename) + if cfg is None: + cfg = {} + #port = int(cfg.get('rpcport', '18332' if cfg.get('testnet') else '20102')) + port = int(cfg.get('rpcport', '20102')) + rpcuser = cfg.get('rpcuser', '') + rpcpassword = cfg.get('rpcpassword', '') + + return VERGEConnection(rpcuser, rpcpassword, 'localhost', port) + + +def connect_to_remote(user, password, host='localhost', port=20102, + use_https=False): + """ + Connect to remote or alternative local verge client instance. + + Returns a :class:`~vergerpc.connection.VERGEConnection` object. + """ + from vergerpc.connection import VERGEConnection + + return VERGEConnection(user, password, host, port, use_https) diff --git a/src/vergerpc/config.py b/src/vergerpc/config.py new file mode 100644 index 0000000..55481df --- /dev/null +++ b/src/vergerpc/config.py @@ -0,0 +1,77 @@ +# Copyright (c) 2010 Witchspace +# +# 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. +""" +Utilities for reading verge configuration files. +""" + + +def read_config_file(filename): + """ + Read a simple ``'='``-delimited config file. + Raises :const:`IOError` if unable to open file, or :const:`ValueError` + if an parse error occurs. + """ + f = open(filename) + try: + cfg = {} + for line in f: + line = line.strip() + if line and not line.startswith("#"): + try: + (key, value) = line.split('=', 1) + cfg[key] = value + except ValueError: + pass # Happens when line has no '=', ignore + finally: + f.close() + return cfg + + +def read_default_config(filename=None): + """ + Read verge default configuration from the current user's home directory. + + Arguments: + + - `filename`: Path to a configuration file in a non-standard location (optional) + """ + if filename is None: + import os + import platform + home = os.getenv("HOME") + if not home: + raise IOError("Home directory not defined, don't know where to look for config file") + + if platform.system() == "Darwin": + location = 'Library/Application Support/VERGE/VERGE.conf' + elif platform.system() in ('Windows', 'Microsoft'): + location = 'AppData\\Roaming\\VERGE\\VERGE.conf' + else: + location = '.VERGE/VERGE.conf' + filename = os.path.join(home, location) + + elif filename.startswith("~"): + import os + filename = os.path.expanduser(filename) + + try: + return read_config_file(filename) + except (IOError, ValueError): + pass # Cannot read config file, ignore diff --git a/src/vergerpc/connection.py b/src/vergerpc/connection.py new file mode 100644 index 0000000..7ec5771 --- /dev/null +++ b/src/vergerpc/connection.py @@ -0,0 +1,659 @@ +# Copyright (c) 2010 Witchspace +# +# 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. +""" +Connect to VERGE server via JSON-RPC. +""" +from vergerpc.proxy import AuthServiceProxy +from vergerpc.exceptions import (wrap_exception, VERGEException, + WalletPassphraseIncorrect, + WalletAlreadyUnlocked) +from vergerpc.data import (ServerInfo, AccountInfo, AddressInfo, TransactionInfo, + AddressValidation, WorkItem, MiningInfo) + + +class VERGEConnection(object): + """ + A VERGEConnection object defines a connection to a verge server. + It is a thin wrapper around a JSON-RPC API connection. + + Arguments to constructor: + + - *user* -- Authenticate as user. + - *password* -- Authentication password. + - *host* -- VERGE JSON-RPC host. + - *port* -- VERGE JSON-RPC port. + """ + def __init__(self, user, password, host='localhost', port=22555, + use_https=False): + """ + Create a new verge server connection. + """ + url = 'http{s}://{user}:{password}@{host}:{port}/'.format( + s='s' if use_https else '', + user=user, password=password, host=host, port=port) + self.url = url + self.proxy = AuthServiceProxy(url, exception_wrapper=wrap_exception) + + def stop(self): + """ + Stop verge server. + """ + self.proxy.stop() + + def getblock(self, hash): + """ + Returns information about the given block hash. + """ + return self.proxy.getblock(hash) + + def getblockcount(self): + """ + Returns the number of blocks in the longest block chain. + """ + return self.proxy.getblockcount() + + def getblockhash(self, index): + """ + Returns hash of block in best-block-chain at index. + + :param index: index ob the block + + """ + return self.proxy.getblockhash(index) + + def getblocknumber(self): + """ + Returns the block number of the latest block in the longest block chain. + Deprecated. Use getblockcount instead. + """ + return self.getblockcount() + + def getconnectioncount(self): + """ + Returns the number of connections to other nodes. + """ + return self.proxy.getconnectioncount() + + def getdifficulty(self): + """ + Returns the proof-of-work difficulty as a multiple of the minimum difficulty. + """ + return self.proxy.getdifficulty() + + def getgenerate(self): + """ + Returns :const:`True` or :const:`False`, depending on whether generation is enabled. + """ + return self.proxy.getgenerate() + + def setgenerate(self, generate, genproclimit=None): + """ + Enable or disable generation (mining) of coins. + + Arguments: + + - *generate* -- is :const:`True` or :const:`False` to turn generation on or off. + - *genproclimit* -- Number of processors that are used for generation, -1 is unlimited. + + """ + if genproclimit is None: + return self.proxy.setgenerate(generate) + else: + return self.proxy.setgenerate(generate, genproclimit) + + def gethashespersec(self): + """ + Returns a recent hashes per second performance measurement while generating. + """ + return self.proxy.gethashespersec() + + def getinfo(self): + """ + Returns an :class:`~vergerpc.data.ServerInfo` object containing various state info. + """ + return ServerInfo(**self.proxy.getinfo()) + + def getmininginfo(self): + """ + Returns an :class:`~vergerpc.data.MiningInfo` object containing various + mining state info. + """ + return MiningInfo(**self.proxy.getmininginfo()) + + def getnewaddress(self, account=None): + """ + Returns a new verge address for receiving payments. + + Arguments: + + - *account* -- If account is specified (recommended), it is added to the address book + so that payments received with the address will be credited to it. + + """ + if account is None: + return self.proxy.getnewaddress() + else: + return self.proxy.getnewaddress(account) + + def getaccountaddress(self, account): + """ + Returns the current verge address for receiving payments to an account. + + Arguments: + + - *account* -- Account for which the address should be returned. + + """ + return self.proxy.getaccountaddress(account) + + def setaccount(self, vergeaddress, account): + """ + Sets the account associated with the given address. + + Arguments: + + - *vergeaddress* -- VERGE address to associate. + - *account* -- Account to associate the address to. + + """ + return self.proxy.setaccount(vergeaddress, account) + + def getaccount(self, vergeaddress): + """ + Returns the account associated with the given address. + + Arguments: + + - *vergeaddress* -- VERGE address to get account for. + """ + return self.proxy.getaccount(vergeaddress) + + def getaddressesbyaccount(self, account): + """ + Returns the list of addresses for the given account. + + Arguments: + + - *account* -- Account to get list of addresses for. + """ + return self.proxy.getaddressesbyaccount(account) + + def sendtoaddress(self, vergeaddress, amount, comment=None, comment_to=None): + """ + Sends *amount* from the server's available balance to *vergeaddress*. + + Arguments: + + - *vergeaddress* -- VERGE address to send to. + - *amount* -- Amount to send (float, rounded to the nearest 0.00000001). + - *minconf* -- Minimum number of confirmations required for transferred balance. + - *comment* -- Comment for transaction. + - *comment_to* -- Comment for to-address. + + """ + if comment is None: + return self.proxy.sendtoaddress(vergeaddress, amount) + elif comment_to is None: + return self.proxy.sendtoaddress(vergeaddress, amount, comment) + else: + return self.proxy.sendtoaddress(vergeaddress, amount, comment, comment_to) + + def getreceivedbyaddress(self, vergeaddress, minconf=1): + """ + Returns the total amount received by a verge address in transactions with at least a + certain number of confirmations. + + Arguments: + + - *vergeaddress* -- Address to query for total amount. + + - *minconf* -- Number of confirmations to require, defaults to 1. + """ + return self.proxy.getreceivedbyaddress(vergeaddress, minconf) + + def getreceivedbyaccount(self, account, minconf=1): + """ + Returns the total amount received by addresses with an account in transactions with + at least a certain number of confirmations. + + Arguments: + + - *account* -- Account to query for total amount. + - *minconf* -- Number of confirmations to require, defaults to 1. + + """ + return self.proxy.getreceivedbyaccount(account, minconf) + + def gettransaction(self, txid): + """ + Get detailed information about transaction + + Arguments: + + - *txid* -- Transactiond id for which the info should be returned + + """ + return TransactionInfo(**self.proxy.gettransaction(txid)) + + def getrawtransaction(self, txid, verbose=True): + """ + Get transaction raw info + + Arguments: + + - *txid* -- Transactiond id for which the info should be returned. + - *verbose* -- If False, return only the "hex" of the transaction. + + """ + if verbose: + return TransactionInfo(**self.proxy.getrawtransaction(txid, 1)) + return self.proxy.getrawtransaction(txid, 0) + + def gettxout(self, txid, index, mempool=True): + """ + Returns details about an unspent transaction output (UTXO) + + Arguments: + + - *txid* -- Transactiond id for which the info should be returned. + - *index* -- The output index. + - *mempool* -- Add memory pool transactions. + """ + tx = self.proxy.gettxout(txid, index, mempool) + if tx != None: + return TransactionInfo(**tx) + else: + return TransactionInfo() + + def createrawtransaction(self, inputs, outputs): + """ + Creates a raw transaction spending given inputs + (a list of dictionaries, each containing a transaction id and an output number), + sending to given address(es). + + Returns hex-encoded raw transaction. + + Example usage: + >>> conn.createrawtransaction( + [{"txid": "a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c", + "vout": 0}], + {"mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT":50}) + + + Arguments: + + - *inputs* -- A list of {"txid": txid, "vout": n} dictionaries. + - *outputs* -- A dictionary mapping (public) addresses to the amount + they are to be paid. + """ + return self.proxy.createrawtransaction(inputs, outputs) + + def signrawtransaction(self, hexstring, previous_transactions=None, private_keys=None): + """ + Sign inputs for raw transaction (serialized, hex-encoded). + + Returns a dictionary with the keys: + "hex": raw transaction with signature(s) (hex-encoded string) + "complete": 1 if transaction has a complete set of signature(s), 0 if not + + Arguments: + + - *hexstring* -- A hex string of the transaction to sign. + - *previous_transactions* -- A (possibly empty) list of dictionaries of the form: + {"txid": txid, "vout": n, "scriptPubKey": hex, "redeemScript": hex}, representing + previous transaction outputs that this transaction depends on but may not yet be + in the block chain. + - *private_keys* -- A (possibly empty) list of base58-encoded private + keys that, if given, will be the only keys used to sign the transaction. + """ + return dict(self.proxy.signrawtransaction(hexstring, previous_transactions, private_keys)) + + def decoderawtransaction(self, hexstring): + """ + Produces a human-readable JSON object for a raw transaction. + + Arguments: + + - *hexstring* -- A hex string of the transaction to be decoded. + """ + return dict(self.proxy.decoderawtransaction(hexstring)) + + def listsinceblock(self, block_hash): + res = self.proxy.listsinceblock(block_hash) + res['transactions'] = [TransactionInfo(**x) for x in res['transactions']] + return res + + def listreceivedbyaddress(self, minconf=1, includeempty=False): + """ + Returns a list of addresses. + + Each address is represented with a :class:`~vergerpc.data.AddressInfo` object. + + Arguments: + + - *minconf* -- Minimum number of confirmations before payments are included. + - *includeempty* -- Whether to include addresses that haven't received any payments. + + """ + return [AddressInfo(**x) for x in + self.proxy.listreceivedbyaddress(minconf, includeempty)] + + def listaccounts(self, minconf=1, as_dict=False): + """ + Returns a list of account names. + + Arguments: + + - *minconf* -- Minimum number of confirmations before payments are included. + - *as_dict* -- Returns a dictionary of account names, with their balance as values. + """ + if as_dict: + return dict(self.proxy.listaccounts(minconf)) + else: + return self.proxy.listaccounts(minconf).keys() + + def listreceivedbyaccount(self, minconf=1, includeempty=False): + """ + Returns a list of accounts. + + Each account is represented with a :class:`~vergerpc.data.AccountInfo` object. + + Arguments: + + - *minconf* -- Minimum number of confirmations before payments are included. + + - *includeempty* -- Whether to include addresses that haven't received any payments. + """ + return [AccountInfo(**x) for x in + self.proxy.listreceivedbyaccount(minconf, includeempty)] + + def listtransactions(self, account=None, count=10, from_=0, address=None): + """ + Returns a list of the last transactions for an account. + + Each transaction is represented with a :class:`~vergerpc.data.TransactionInfo` object. + + Arguments: + + - *account* -- Account to list transactions from. Return transactions from + all accounts if None. + - *count* -- Number of transactions to return. + - *from_* -- Skip the first transactions. + - *address* -- Receive address to consider + """ + accounts = [account] if account is not None else self.listaccounts(as_dict=True).keys() + return [TransactionInfo(**tx) for acc in accounts for + tx in self.proxy.listtransactions(acc, count, from_) if + address is None or tx["address"] == address] + + def backupwallet(self, destination): + """ + Safely copies ``wallet.dat`` to *destination*, which can be a directory or a path + with filename. + + Arguments: + - *destination* -- directory or path with filename to backup wallet to. + + """ + return self.proxy.backupwallet(destination) + + def validateaddress(self, validateaddress): + """ + Validate a verge address and return information for it. + + The information is represented by a :class:`~vergerpc.data.AddressValidation` object. + + Arguments: -- Address to validate. + + + - *validateaddress* + """ + return AddressValidation(**self.proxy.validateaddress(validateaddress)) + + def getbalance(self, account=None, minconf=None): + """ + Get the current balance, either for an account or the total server balance. + + Arguments: + - *account* -- If this parameter is specified, returns the balance in the account. + - *minconf* -- Minimum number of confirmations required for transferred balance. + + """ + args = [] + if account is not None: + args.append(account) + if minconf is not None: + args.append(minconf) + return self.proxy.getbalance(*args) + + def move(self, fromaccount, toaccount, amount, minconf=1, comment=None): + """ + Move from one account in your wallet to another. + + Arguments: + + - *fromaccount* -- Source account name. + - *toaccount* -- Destination account name. + - *amount* -- Amount to transfer. + - *minconf* -- Minimum number of confirmations required for transferred balance. + - *comment* -- Comment to add to transaction log. + + """ + if comment is None: + return self.proxy.move(fromaccount, toaccount, amount, minconf) + else: + return self.proxy.move(fromaccount, toaccount, amount, minconf, comment) + + def sendfrom(self, fromaccount, tovergeaddress, amount, minconf=1, comment=None, + comment_to=None): + """ + Sends amount from account's balance to vergeaddress. This method will fail + if there is less than amount verges with minconf confirmations in the account's + balance (unless account is the empty-string-named default account; it + behaves like the sendtoaddress method). Returns transaction ID on success. + + Arguments: + + - *fromaccount* -- Account to send from. + - *tovergeaddress* -- VERGE address to send to. + - *amount* -- Amount to send (float, rounded to the nearest 0.01). + - *minconf* -- Minimum number of confirmations required for transferred balance. + - *comment* -- Comment for transaction. + - *comment_to* -- Comment for to-address. + + """ + if comment is None: + return self.proxy.sendfrom(fromaccount, tovergeaddress, amount, minconf) + elif comment_to is None: + return self.proxy.sendfrom(fromaccount, tovergeaddress, amount, minconf, comment) + else: + return self.proxy.sendfrom(fromaccount, tovergeaddress, amount, minconf, + comment, comment_to) + + def sendmany(self, fromaccount, todict, minconf=1, comment=None): + """ + Sends specified amounts from account's balance to vergeaddresses. This method will fail + if there is less than total amount verges with minconf confirmations in the account's + balance (unless account is the empty-string-named default account; Returns transaction ID + on success. + + Arguments: + + - *fromaccount* -- Account to send from. + - *todict* -- Dictionary with VERGE addresses as keys and amounts as values. + - *minconf* -- Minimum number of confirmations required for transferred balance. + - *comment* -- Comment for transaction. + + """ + if comment is None: + return self.proxy.sendmany(fromaccount, todict, minconf) + else: + return self.proxy.sendmany(fromaccount, todict, minconf, comment) + + def verifymessage(self, vergeaddress, signature, message): + """ + Verifies a signature given the vergeaddress used to sign, + the signature itself, and the message that was signed. + Returns :const:`True` if the signature is valid, and :const:`False` if it is invalid. + + Arguments: + + - *vergeaddress* -- the vergeaddress used to sign the message + - *signature* -- the signature to be verified + - *message* -- the message that was originally signed + + """ + return self.proxy.verifymessage(vergeaddress, signature, message) + + def getwork(self, data=None): + """ + Get work for remote mining, or submit result. + If data is specified, the server tries to solve the block + using the provided data and returns :const:`True` if it was successful. + If not, the function returns formatted hash data (:class:`~vergerpc.data.WorkItem`) + to work on. + + Arguments: + + - *data* -- Result from remote mining. + + """ + if data is None: + # Only if no data provided, it returns a WorkItem + return WorkItem(**self.proxy.getwork()) + else: + return self.proxy.getwork(data) + + def listunspent(self, minconf=1, maxconf=999999): + """ + Returns a list of unspent transaction inputs in the wallet. + + Arguments: + + - *minconf* -- Minimum number of confirmations required to be listed. + + - *maxconf* -- Maximal number of confirmations allowed to be listed. + + + """ + return [TransactionInfo(**tx) for tx in + self.proxy.listunspent(minconf, maxconf)] + + def keypoolrefill(self): + "Fills the keypool, requires wallet passphrase to be set." + self.proxy.keypoolrefill() + + def walletpassphrase(self, passphrase, timeout, dont_raise=False): + """ + Stores the wallet decryption key in memory for seconds. + + - *passphrase* -- The wallet passphrase. + + - *timeout* -- Time in seconds to keep the wallet unlocked + (by keeping the passphrase in memory). + + - *dont_raise* -- instead of raising `~vergerpc.exceptions.WalletPassphraseIncorrect` + return False. + """ + try: + self.proxy.walletpassphrase(passphrase, timeout) + return True + except VERGEException as exception: + if dont_raise: + if isinstance(exception, WalletPassphraseIncorrect): + return False + elif isinstance(exception, WalletAlreadyUnlocked): + return True + raise exception + + def walletlock(self): + """ + Removes the wallet encryption key from memory, locking the wallet. + After calling this method, you will need to call walletpassphrase + again before being able to call any methods which require the wallet + to be unlocked. + """ + return self.proxy.walletlock() + + def walletpassphrasechange(self, oldpassphrase, newpassphrase, dont_raise=False): + """ + Changes the wallet passphrase from to . + + Arguments: + + - *dont_raise* -- instead of raising `~vergerpc.exceptions.WalletPassphraseIncorrect` + return False. + """ + try: + self.proxy.walletpassphrasechange(oldpassphrase, newpassphrase) + return True + except VERGEException as exception: + if dont_raise and isinstance(exception, WalletPassphraseIncorrect): + return False + raise exception + + def importprivkey(self, privkey, acct='', rescan=True): + """ + import private key to account [acct], optionally rescanning blockchain . + + Arguments: + + - *privkey* -- private key to import. + - [acct] -- name of account to associate with private key + - [rescan] -- rescan blockchain for transcations containing altcoin address associated with privkey + """ + return self.proxy.importprivkey(privkey, acct, rescan) + + + def dumpprivkey(self, address): + """ + Returns the private key belonging to
      . + + Arguments: + + - *address* -- VERGE address whose private key should be returned. + """ + return self.proxy.dumpprivkey(address) + + def signmessage(self, address, message): + """ + Sign messages, returns the signature + + :param address: VERGE address used to sign a message + :type address: str or unicode + :param message: The message to sign + :type message: str or unicode + :rtype: unicode + """ + return self.proxy.signmessage(address, message) + + def verifymessage(self, address, signature, message): + """ + Verify a signed message + + :param address: VERGE address used to sign a message + :type address: str or unicode + :param signature: The signature + :type signature: unicode + :param message: The message to sign + :type message: str or unicode + :rtype: bool + """ + return self.proxy.verifymessage(address, signature, message) diff --git a/src/vergerpc/data.py b/src/vergerpc/data.py new file mode 100644 index 0000000..899ebac --- /dev/null +++ b/src/vergerpc/data.py @@ -0,0 +1,168 @@ +# Copyright (c) 2010 Witchspace +# +# 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. +""" +VERGE RPC service, data objects. +""" +from vergerpc.util import DStruct + + +class ServerInfo(DStruct): + """ + Information object returned by :func:`~vergerpc.connection.VERGEConnection.getinfo`. + + - *errors* -- Number of errors. + + - *blocks* -- Number of blocks. + + - *paytxfee* -- Amount of transaction fee to pay. + + - *keypoololdest* -- Oldest key in keypool. + + - *genproclimit* -- Processor limit for generation. + + - *connections* -- Number of connections to other clients. + + - *difficulty* -- Current generating difficulty. + + - *testnet* -- True if connected to testnet, False if on real network. + + - *version* -- VERGE client version. + + - *proxy* -- Proxy configured in client. + + - *hashespersec* -- Number of hashes per second (if generation enabled). + + - *balance* -- Total current server balance. + + - *generate* -- True if generation enabled, False if not. + + - *unlocked_until* -- Timestamp (seconds since epoch) after which the wallet + will be/was locked (if wallet encryption is enabled). + + """ + + +class AccountInfo(DStruct): + """ + Information object returned by :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaccount`. + + - *account* -- The account of the receiving address. + + - *amount* -- Total amount received by the address. + + - *confirmations* -- Number of confirmations of the most recent transaction included. + + """ + + +class AddressInfo(DStruct): + """ + Information object returned by :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaddress`. + + - *address* -- Receiving address. + + - *account* -- The account of the receiving address. + + - *amount* -- Total amount received by the address. + + - *confirmations* -- Number of confirmations of the most recent transaction included. + + """ + + +class TransactionInfo(DStruct): + """ + Information object returned by :func:`~vergerpc.connection.VERGEConnection.listtransactions`. + + - *account* -- account name. + + - *address* -- the address verges were sent to, or received from. + + - *category* -- will be generate, send, receive, or move. + + - *amount* -- amount of transaction. + + - *fee* -- Fee (if any) paid (only for send transactions). + + - *confirmations* -- number of confirmations (only for generate/send/receive). + + - *txid* -- transaction ID (only for generate/send/receive). + + - *otheraccount* -- account funds were moved to or from (only for move). + + - *message* -- message associated with transaction (only for send). + + - *to* -- message-to associated with transaction (only for send). + """ + + +class AddressValidation(DStruct): + """ + Information object returned by :func:`~vergerpc.connection.VERGEConnection.validateaddress`. + + - *isvalid* -- Validatity of address (:const:`True` or :const:`False`). + + - *ismine* -- :const:`True` if the address is in the server's wallet. + + - *address* -- VERGE address. + + """ + + +class WorkItem(DStruct): + """ + Information object returned by :func:`~vergerpc.connection.VERGEConnection.getwork`. + + - *midstate* -- Precomputed hash state after hashing the first half of the data. + + - *data* -- Block data. + + - *hash1* -- Formatted hash buffer for second hash. + + - *target* -- Little endian hash target. + + """ + + +class MiningInfo(DStruct): + """ + Information object returned by :func:`~vergerpc.connection.VERGEConnection.getmininginfo`. + + - *blocks* -- Number of blocks. + + - *currentblocksize* -- Size of current block. + + - *currentblocktx* -- Number of transactions in current block. + + - *difficulty* -- Current generating difficulty. + + - *errors* -- Number of errors. + + - *generate* -- True if generation enabled, False if not. + + - *genproclimit* -- Processor limit for generation. + + - *hashespersec* -- Number of hashes per second (if generation enabled). + + - *pooledtx* -- Number of pooled transactions. + + - *testnet* -- True if connected to testnet, False if on real network. + + """ diff --git a/src/vergerpc/exceptions.py b/src/vergerpc/exceptions.py new file mode 100644 index 0000000..0051d35 --- /dev/null +++ b/src/vergerpc/exceptions.py @@ -0,0 +1,227 @@ +# Copyright (c) 2010 Witchspace +# +# 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. +""" +Exception definitions. +""" + + +class VERGEException(Exception): + """ + Base class for exceptions received from VERGE server. + + - *code* -- Error code from ``verged``. + """ + # Standard JSON-RPC 2.0 errors + INVALID_REQUEST = -32600, + METHOD_NOT_FOUND = -32601, + INVALID_PARAMS = -32602, + INTERNAL_ERROR = -32603, + PARSE_ERROR = -32700, + + # General application defined errors + MISC_ERROR = -1 # std::exception thrown in command handling + FORBIDDEN_BY_SAFE_MODE = -2 # Server is in safe mode, and command is not allowed in safe mode + TYPE_ERROR = -3 # Unexpected type was passed as parameter + INVALID_ADDRESS_OR_KEY = -5 # Invalid address or key + OUT_OF_MEMORY = -7 # Ran out of memory during operation + INVALID_PARAMETER = -8 # Invalid, missing or duplicate parameter + DATABASE_ERROR = -20 # Database error + DESERIALIZATION_ERROR = -22 # Error parsing or validating structure in raw format + + # P2P client errors + CLIENT_NOT_CONNECTED = -9 # VERGE is not connected + CLIENT_IN_INITIAL_DOWNLOAD = -10 # Still downloading initial blocks + + # Wallet errors + WALLET_ERROR = -4 # Unspecified problem with wallet (key not found etc.) + WALLET_INSUFFICIENT_FUNDS = -6 # Not enough funds in wallet or account + WALLET_INVALID_ACCOUNT_NAME = -11 # Invalid account name + WALLET_KEYPOOL_RAN_OUT = -12 # Keypool ran out, call keypoolrefill first + WALLET_UNLOCK_NEEDED = -13 # Enter the wallet passphrase with walletpassphrase first + WALLET_PASSPHRASE_INCORRECT = -14 # The wallet passphrase entered was incorrect + WALLET_WRONG_ENC_STATE = -15 # Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) + WALLET_ENCRYPTION_FAILED = -16 # Failed to encrypt the wallet + WALLET_ALREADY_UNLOCKED = -17 # Wallet is already unlocked + + def __init__(self, error): + Exception.__init__(self, error['message']) + self.code = error['code'] + + +class TransportException(Exception): + """ + Class to define transport-level failures. + """ + def __init__(self, msg, code=None, protocol=None, raw_detail=None): + self.msg = msg + self.code = code + self.protocol = protocol + self.raw_detail = raw_detail + self.s = """ + Transport-level failure: {msg} + Code: {code} + Protocol: {protocol} + """.format(msg=msg, code=code, protocol=protocol) + + def __str__(self): + return self.s + + +##### General application defined errors +class SafeMode(VERGEException): + """ + Operation denied in safe mode (run ``verged`` with ``-disablesafemode``). + """ + + +class JSONTypeError(VERGEException): + """ + Unexpected type was passed as parameter + """ +InvalidAmount = JSONTypeError # Backwards compatibility + + +class InvalidAddressOrKey(VERGEException): + """ + Invalid address or key. + """ +InvalidTransactionID = InvalidAddressOrKey # Backwards compatibility + + +class OutOfMemory(VERGEException): + """ + Out of memory during operation. + """ + + +class InvalidParameter(VERGEException): + """ + Invalid parameter provided to RPC call. + """ + + +##### Client errors +class ClientException(VERGEException): + """ + P2P network error. + This exception is never raised but functions as a superclass + for other P2P client exceptions. + """ + + +class NotConnected(ClientException): + """ + Not connected to any peers. + """ + + +class DownloadingBlocks(ClientException): + """ + Client is still downloading blocks. + """ + + +##### Wallet errors +class WalletError(VERGEException): + """ + Unspecified problem with wallet (key not found etc.) + """ +SendError = WalletError # Backwards compatibility + + +class InsufficientFunds(WalletError): + """ + Insufficient funds to complete transaction in wallet or account + """ + + +class InvalidAccountName(WalletError): + """ + Invalid account name + """ + + +class KeypoolRanOut(WalletError): + """ + Keypool ran out, call keypoolrefill first + """ + + +class WalletUnlockNeeded(WalletError): + """ + Enter the wallet passphrase with walletpassphrase first + """ + + +class WalletPassphraseIncorrect(WalletError): + """ + The wallet passphrase entered was incorrect + """ + + +class WalletWrongEncState(WalletError): + """ + Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) + """ + + +class WalletEncryptionFailed(WalletError): + """ + Failed to encrypt the wallet + """ + + +class WalletAlreadyUnlocked(WalletError): + """ + Wallet is already unlocked + """ + + +# For convenience, we define more specific exception classes +# for the more common errors. +_exception_map = { + VERGEException.FORBIDDEN_BY_SAFE_MODE: SafeMode, + VERGEException.TYPE_ERROR: JSONTypeError, + VERGEException.WALLET_ERROR: WalletError, + VERGEException.INVALID_ADDRESS_OR_KEY: InvalidAddressOrKey, + VERGEException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds, + VERGEException.OUT_OF_MEMORY: OutOfMemory, + VERGEException.INVALID_PARAMETER: InvalidParameter, + VERGEException.CLIENT_NOT_CONNECTED: NotConnected, + VERGEException.CLIENT_IN_INITIAL_DOWNLOAD: DownloadingBlocks, + VERGEException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds, + VERGEException.WALLET_INVALID_ACCOUNT_NAME: InvalidAccountName, + VERGEException.WALLET_KEYPOOL_RAN_OUT: KeypoolRanOut, + VERGEException.WALLET_UNLOCK_NEEDED: WalletUnlockNeeded, + VERGEException.WALLET_PASSPHRASE_INCORRECT: WalletPassphraseIncorrect, + VERGEException.WALLET_WRONG_ENC_STATE: WalletWrongEncState, + VERGEException.WALLET_ENCRYPTION_FAILED: WalletEncryptionFailed, + VERGEException.WALLET_ALREADY_UNLOCKED: WalletAlreadyUnlocked, +} + + +def wrap_exception(error): + """ + Convert a JSON error object to a more specific VERGE exception. + """ + # work around to temporarily fix https://github.com/bitcoin/bitcoin/issues/3007 + if error['code'] == VERGEException.WALLET_ERROR and error['message'] == u'Insufficient funds': + error['code'] = VERGEException.WALLET_INSUFFICIENT_FUNDS + return _exception_map.get(error['code'], VERGEException)(error) diff --git a/src/vergerpc/proxy.py b/src/vergerpc/proxy.py new file mode 100644 index 0000000..3599d10 --- /dev/null +++ b/src/vergerpc/proxy.py @@ -0,0 +1,165 @@ +""" + Copyright (c) 2007 Jan-Klaas Kollhof + Copyright (c) 2011-2013 Jeff Garzik + Copyright (c) 2013 Nikolay Belikov (nikolay@belikov.me) + + + jsonrpc is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This software is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this software; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +try: + import http.client as httplib +except ImportError: + import httplib +import base64 +import json +import decimal +try: + import urllib.parse as urlparse +except ImportError: + import urlparse +from collections import defaultdict, deque +from vergerpc.exceptions import TransportException + +USER_AGENT = "AuthServiceProxy/0.1" + +HTTP_TIMEOUT = 30 + + +class JSONRPCException(Exception): + def __init__(self, rpc_error): + Exception.__init__(self) + self.error = rpc_error + + +class HTTPTransport(object): + def __init__(self, service_url): + self.service_url = service_url + self.parsed_url = urlparse.urlparse(service_url) + if self.parsed_url.port is None: + port = 80 + else: + port = self.parsed_url.port + authpair = "%s:%s" % (self.parsed_url.username, + self.parsed_url.password) + authpair = authpair.encode('utf8') + self.auth_header = "Basic ".encode('utf8') + base64.b64encode(authpair) + if self.parsed_url.scheme == 'https': + self.connection = httplib.HTTPSConnection(self.parsed_url.hostname, + port, None, None, False, + HTTP_TIMEOUT) + else: + self.connection = httplib.HTTPConnection(self.parsed_url.hostname, + port, False, HTTP_TIMEOUT) + + def request(self, serialized_data): + self.connection.request('POST', self.parsed_url.path, serialized_data, + {'Host': self.parsed_url.hostname, + 'User-Agent': USER_AGENT, + 'Authorization': self.auth_header, + 'Content-type': 'application/json'}) + + httpresp = self.connection.getresponse() + if httpresp is None: + self._raise_exception({ + 'code': -342, 'message': 'missing HTTP response from server'}) + elif httpresp.status == httplib.FORBIDDEN: + msg = "verged returns 403 Forbidden. Is your IP allowed?" + raise TransportException(msg, code=403, + protocol=self.parsed_url.scheme, + raw_detail=httpresp) + + resp = httpresp.read() + return resp.decode('utf8') + + +class FakeTransport(object): + """A simple testing facility.""" + def __init__(self): + self._data = defaultdict(deque) + + def load_serialized(self, method_name, fixture): + self._data[method_name].append(fixture) + + def load_raw(self, method_name, fixture): + self._data[method_name].append(json.dumps(fixture)) + + def request(self, serialized_data): + data = json.loads(serialized_data, parse_float=decimal.Decimal) + method_name = data['method'] + return self._data[method_name].popleft() + + +class RPCMethod(object): + def __init__(self, name, service_proxy): + self._method_name = name + self._service_proxy = service_proxy + + def __getattr__(self, name): + new_name = '{}.{}'.format(self._method_name, name) + return RPCMethod(new_name, self._service_proxy) + + def __call__(self, *args): + self._service_proxy._id_counter += 1 + data = {'version': '1.1', + 'method': self._method_name, + 'params': args, + 'id': self._service_proxy._id_counter} + postdata = json.dumps(data) + resp = self._service_proxy._transport.request(postdata) + resp = json.loads(resp, parse_float=decimal.Decimal) + + if resp['error'] is not None: + self._service_proxy._raise_exception(resp['error']) + elif 'result' not in resp: + self._service_proxy._raise_exception({ + 'code': -343, 'message': 'missing JSON-RPC result'}) + else: + return resp['result'] + + def __repr__(self): + return ''.format(name=self._method_name) + + +class AuthServiceProxy(object): + """ + You can use custom transport to test your app's behavior without calling + the remote service. + + exception_wrapper is a callable accepting a dictionary containing error + code and message and returning a suitable exception object. + """ + def __init__(self, service_url, transport=None, exception_wrapper=None): + self._service_url = service_url + self._id_counter = 0 + self._transport = (HTTPTransport(service_url) if transport is None + else transport) + self._exception_wrapper = exception_wrapper + + def __getattr__(self, name): + return RPCMethod(name, self) + + def _get_method(self, name): + """ + Get method instance when the name contains forbidden characters or + already taken by internal attribute. + """ + return RPCMethod(name, self) + + def _raise_exception(self, error): + if self._exception_wrapper is None: + raise JSONRPCException(error) + else: + raise self._exception_wrapper(error) diff --git a/src/vergerpc/util.py b/src/vergerpc/util.py new file mode 100644 index 0000000..f4dc0d7 --- /dev/null +++ b/src/vergerpc/util.py @@ -0,0 +1,49 @@ +# Copyright (c) 2010 Witchspace +# +# 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. +"""Generic utilities used by verge client library.""" +from copy import copy + + +class DStruct(object): + """ + Simple dynamic structure, like :const:`collections.namedtuple` but more flexible + (and less memory-efficient) + """ + # Default arguments. Defaults are *shallow copied*, to allow defaults such as []. + _fields = [] + _defaults = {} + + def __init__(self, *args_t, **args_d): + # order + if len(args_t) > len(self._fields): + raise TypeError("Number of arguments is larger than of predefined fields") + # Copy default values + for (k, v) in self._defaults.items(): + self.__dict__[k] = copy(v) + # Set pass by value arguments + self.__dict__.update(zip(self._fields, args_t)) + # dict + self.__dict__.update(args_d) + + def __repr__(self): + return '{module}.{classname}({slots})'.format( + module=self.__class__.__module__, classname=self.__class__.__name__, + slots=", ".join('{k}={v!r}'.format(k=k, v=v) for k, v in + self.__dict__.items())) diff --git a/tests/test.py b/tests/test.py new file mode 100644 index 0000000..f85dd64 --- /dev/null +++ b/tests/test.py @@ -0,0 +1,106 @@ +# coding=utf-8 +''' +Test script +*WARNING* Don't run this on a production verge server! *WARNING* +Only on the test network. +''' +import argparse +import sys +sys.path.append('../src') + +import vergerpc +from vergerpc.exceptions import VERGEException, InsufficientFunds + + +from decimal import Decimal + +parser = argparse.ArgumentParser() +parser.add_argument('--config', help="Specify configuration file") +parser.add_argument('--nolocal', help="Don't use connect_to_local", + action='store_true') +parser.add_argument('--noremote', help="Don't use connect_to_remote", + action='store_true') +args = parser.parse_args() + +if __name__ == "__main__": + + if args.config: + from vergerpc.config import read_config_file + cfg = read_config_file(args.config) + else: + from vergerpc.config import read_default_config + cfg = read_default_config(None) + port = int(cfg.get('rpcport', '20102')) + rpcuser = cfg.get('rpcuser', '') + + connections = [] + if not args.nolocal: + local_conn = vergerpc.connect_to_local() # will use read_default_config + connections.append(local_conn) + if not args.noremote: + remote_conn = vergerpc.connect_to_remote( + user=rpcuser, password=cfg['rpcpassword'], host='localhost', + port=port, use_https=False) + connections.append(remote_conn) + + for conn in connections: + assert(conn.getinfo().testnet) # don't test on prodnet + + assert(type(conn.getblockcount()) is int) + assert(type(conn.getconnectioncount()) is int) + assert(type(conn.getdifficulty()) is Decimal) + assert(type(conn.getgenerate()) is bool) + conn.setgenerate(True) + conn.setgenerate(True, 2) + conn.setgenerate(False) + assert(type(conn.gethashespersec()) is int) + account = "testaccount" + account2 = "testaccount2" + vergeaddress = conn.getnewaddress(account) + conn.setaccount(vergeaddress, account) + address = conn.getaccountaddress(account) + address2 = conn.getaccountaddress(account2) + assert(conn.getaccount(address) == account) + addresses = conn.getaddressesbyaccount(account) + assert(address in addresses) + #conn.sendtoaddress(vergeaddress, amount, comment=None, comment_to=None) + conn.getreceivedbyaddress(vergeaddress) + conn.getreceivedbyaccount(account) + conn.listreceivedbyaddress() + conn.listreceivedbyaccount() + #conn.backupwallet(destination) + x = conn.validateaddress(address) + assert(x.isvalid == True) + x = conn.validateaddress("invalid") + assert(x.isvalid == False) + messages = ('Hello, world!', u'かたな') + for message in messages: + signature = conn.signmessage(vergeaddress, message) + assert(conn.verifymessage(vergeaddress, signature, message) is True) + + for accid in conn.listaccounts(as_dict=True).iterkeys(): + tx = conn.listtransactions(accid) + if len(tx) > 0: + txid = tx[0].txid + txdata = conn.gettransaction(txid) + assert(txdata.txid == tx[0].txid) + + assert(type(conn.listunspent()) is list) # needs better testing + + try: + conn.sendtoaddress(vergeaddress, 10000000) + assert(0) # Should raise InsufficientFunds + except InsufficientFunds: + pass + + info = conn.getinfo() + print "Blocks: %i" % info.blocks + print "Connections: %i" % info.connections + print "Difficulty: %f" % info.difficulty + + m_info = conn.getmininginfo() + print ("Pooled Transactions: {pooledtx}\n" + "Testnet: {testnet}\n" + "Hash Rate: {hashes} H/s".format(pooledtx=m_info.pooledtx, + testnet=m_info.testnet, + hashes=m_info.hashespersec))