LOGGER = logging.getLogger(__name__)
def maybe_raise_exception(future):
def split_connection_host_port(value):
def parse_info_value(value):
def format_info_response(value): _CRC16_LOOKUP = [
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108,
    0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
    0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b,
    0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
    0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee,
    0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
    0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d,
    0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5,
    0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
    0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4,
    0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
    0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13,
    0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
    0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e,
    0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1,
    0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
    0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0,
    0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
    0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657,
    0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
    0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882,
    0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e,
    0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
    0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d,
    0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
    0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
]
def _py2_crc16(value):
def _py3_crc16(value): class TRedisException(Exception):
class ConnectError(TRedisException):
class ConnectionError(TRedisException):
class AuthError(TRedisException):
class RedisError(TRedisException):
class SubscribedError(TRedisException):
class InvalidClusterCommand(TRedisException): class ClusterMixin(object):
    def cluster_add_slots(self, *slots):
    def cluster_count_failure_report(self, node):
    def cluster_count_keys_in_slot(self, slot):
    def cluster_del_slots(self, slot):
    def cluster_failover(self, method):
    def cluster_forget(self, node_id):
    def cluster_get_keys_in_slot(self, slot, count):
    def cluster_info(self):
    def cluster_key_slot(self, key):
    def cluster_meet(self, ip, port):
    def cluster_nodes(self):
        def format_response(result):
    def cluster_replicate(self, node_id):
    def cluster_reset(self, method):
    def cluster_save_config(self):
    def cluster_set_config_epoch(self, config_epoch):
    def cluster_set_slot(self, subcommand, node_id):
    def cluster_slaves(self, node_id):
    def cluster_slots(self):
    def cluster_readonly(self):
    def cluster_readwrite(self): class ConnectionMixin(object): class GeoMixin(object): class HashesMixin(object):
    def hset(self, key, field, value):
    def hget(self, key, field):
    def hgetall(self, key):
        def format_response(value):
    def hmset(self, key, value_dict):
    def hmget(self, key, *fields):
        def format_response(val_array):
    def hdel(self, key, *fields):
    def hexists(self, key, field):
    def hincrby(self, key, field, increment):
    def hincrbyfloat(self, key, field, increment):
    def hkeys(self, key):
    def hlen(self, key):
    def hsetnx(self, key, field, value):
    def hvals(self, key): class HyperLogLogMixin(object):
    def pfadd(self, key, *elements):
    def pfcount(self, *keys):
    def pfmerge(self, dest_key, *keys): def keys(self, pattern):
    """Returns all keys matching pattern.

    While the time complexity for this operation is ``O(N)``, the constant
    times are fairly low. For example, Redis running on an entry level
    laptop can scan a 1 million key database in 40 milliseconds.

    .. warning:: Consider :meth:`~tredis.RedisClient.keys` as a
       command that should only be used in production environments with
       extreme care. It may ruin performance when it is executed against
       large databases. This command is intended for debugging and special
       operations, such as changing your keyspace layout. Don't use
       :meth:`~tredis.RedisClient.keys` in your regular application code.
       If you're looking for a way to find keys in a subset of your
       keyspace, consider using :meth:`~tredis.RedisClient.scan` or sets.

    Supported glob-style patterns:

     - ``h?llo`` matches ``hello``, ``hallo`` and ``hxllo``
     - ``h*llo`` matches ``hllo`` and ``heeeello``
     - ``h[ae]llo`` matches ``hello`` and ``hallo``, but not ``hillo``
     - ``h[^e]llo`` matches ``hallo``, ``hbllo``, but not ``hello``
     - ``h[a-b]llo`` matches ``hallo`` and ``hbllo``

    Use a backslash (``\``) to escape special characters if you want to
    match them verbatim.

    .. note::

       **Time complexity**: ``O(N)``

    :param pattern: The pattern to use when looking for keys
    :type pattern: :class:`str`, :class:`bytes`
    :rtype: list
    :raises: :exc:`~tredis.exceptions.RedisError`

    """
    return self._execute([b'KEYS', pattern]) class ListsMixin(object):
    def llen(self, key):
    def lrange(self, key, start, end):
    def ltrim(self, key, start, stop):
    def lpush(self, key, *values):
    def lpushx(self, key, *values):
    def lpop(self, key):
    def rpush(self, key, *values):
    def rpushx(self, key, *values):
    def rpop(self, key): class PubSubMixin(object): class ScriptingMixin(object):
    def eval(self, script, keys=None, args=None):
    def evalsha(self, sha1, keys=None, args=None):
    def script_exists(self, *hashes):
    def script_flush(self):
    def script_kill(self):
    def script_load(self, script): class ServerMixin(object):
    def auth(self, password):
        def on_response(response):
    def echo(self, message):
    def info(self, section=None):
    def ping(self):
    def quit(self):
    def select(self, index=0):
        def on_selected(f):
    def time(self):
        def format_response(value): class SetsMixin(object):
    def sadd(self, key, *members):
    def scard(self, key):
    def sdiff(self, *keys):
    def sdiffstore(self, destination, *keys):
    def sinter(self, *keys):
    def sinterstore(self, destination, *keys):
    def sismember(self, key, member):
    def smembers(self, key):
    def smove(self, source, destination, member):
    def spop(self, key, count=None):
    def srandmember(self, key, count=None):
    def srem(self, key, *members):
    def sscan(self, key, cursor=0, pattern=None, count=None):
        def format_response(value):
    def sunion(self, *keys):
    def sunionstore(self, destination, *keys): class SortedSetsMixin(object):
    def zadd(self, key, *members, **kwargs):
    def zcard(self, key):
    def zrange(self, key, start=0, stop=-1, with_scores=False):
    def zrangebyscore(self,
                      key,
                      min_score,
                      max_score,
                      with_scores=False,
                      offset=0,
                      count=0):
    def zrem(self, key, *members):
    def zremrangebyscore(self, key, min_score, max_score):
    def zrevrange(self, key, start=0, stop=-1, with_scores=False):
    def zscore(self, key, member): BITOP_AND = b'&'
BITOP_OR = b'|'
BITOP_XOR = b'^'
BITOP_NOT = b'~'
_BITOPTS = {
    BITOP_AND: b'AND',
    BITOP_OR: b'OR',
    BITOP_XOR: b'XOR',
    BITOP_NOT: b'NOT',
}
class StringsMixin(object):
    def append(self, key, value):
    def bitcount(self, key, start=None, end=None):
    def bitop(self, operation, dest_key, *keys):
    def bitpos(self, key, bit, start=None, end=None):
    def decr(self, key):
    def decrby(self, key, decrement):
    def get(self, key):
    def getbit(self, key, offset):
    def getrange(self, key, start, end):
    def getset(self, key, value):
    def incr(self, key):
    def incrby(self, key, increment):
    def incrbyfloat(self, key, increment):
    def mget(self, *keys):
    def mset(self, mapping):
    def msetnx(self, mapping):
    def psetex(self, key, milliseconds, value):
    def set(self, key, value, ex=None, px=None, nx=False, xx=False):
    def setbit(self, key, offset, bit):
    def setex(self, key, seconds, value):
    def setnx(self, key, value):
    def setrange(self, key, offset, value):
    def strlen(self, key): class TransactionsMixin(object):
import collections
import logging
import hiredis
from tornado import concurrent
from tornado import ioloop
from tornado import locks
from tornado import iostream
from tornado import tcpclient
from tredis import common
from tredis import crc16
from tredis import exceptions
from tredis import cluster
from tredis import connection
from tredis import geo
from tredis import hashes
from tredis import hyperloglog
from tredis import keys
from tredis import lists
from tredis import pubsub
from tredis import scripting
from tredis import server
from tredis import sets
from tredis import sortedsets
from tredis import strings
from tredis import transactions
    from tredis.compat import ascii
            raise exceptions.ConnectError('already connected')

        LOGGER.debug('%s connecting', self.name)
        self.io_loop.add_future(
            self._client.connect(self.host, self.port),
            lambda f: self._on_connected(f, future))
        return future

    def execute(self, command, future):
        """Execute a command after connecting if necessary.

        :param bytes command: command to execute after the connection
            is established
        :param tornado.concurrent.Future future:  future to resolve
            when the command's response is received.

        """
        LOGGER.debug('execute(%r, %r)', command, future)
        if self.connected:
            self._write(command, future)
        else:

            def on_connected(cfuture):
                if cfuture.exception():
                    return future.set_exception(cfuture.exception())
                self._write(command, future)

            self.io_loop.add_future(self.connect(), on_connected)

    @property
    def name(self):
        """Return the connection name as it is returned in the cluster nodes
        command.

        :rtype: str

        """
        return '{}:{}'.format(self.host, self.port)

    def read(self, callback):
        """Issue a read on the stream, invoke callback when completed.

        :raises: :class:`tredis.exceptions.ConnectionError` if the
            stream is not currently connected

        """
        self._stream.read_bytes(65536, callback, None, True)

    def set_read_only(self, read_only):
        """Change the connection's read-only flag in the client.

        :param bool read_only: Value to set
        """
        self._read_only = read_only

    def set_slots(self, slots):
        """Change the connection's slot list in the client.

        :param list slots: The updated slot values

        """
        self._slots = slots

    @property
    def slots(self):
        """Return the connection's slot values for clustering.

        :rtype: list

        """
        return self._slots

    def _on_closed(self):
        """Invoked when the connection is closed"""
        LOGGER.error('Redis connection closed')
        self.connected = False
        self._on_close()
        self._stream = None

    def _on_connected(self, stream_future, connect_future):
        """Invoked when the socket stream has connected, setting up the
        stream callbacks and invoking the on connect callback if set.

        :param stream_future: The connection socket future
        :type stream_future: :class:`~tornado.concurrent.Future`
        :param stream_future: The connection response future
        :type stream_future: :class:`~tornado.concurrent.Future`
        :raises: :exc:`tredis.exceptions.ConnectError`

        """
        if stream_future.exception():
            connect_future.set_exception(
                exceptions.ConnectError(stream_future.exception()))
        else:
            self._stream = stream_future.result()
            self._stream.set_close_callback(self._on_closed)
            self.connected = True
            connect_future.set_result(self)

    def _write(self, command, future):
        """Write a command to the socket

        :param Command command: the Command data structure

        """

        def on_written():
            self._on_written(command, future)

        try:
            self._stream.write(command.command, callback=on_written)
        except iostream.StreamClosedError as error:
            future.set_exception(exceptions.ConnectionError(error))
        except Exception as error:
            LOGGER.exception('unhandled write failure - %r', error)
            future.set_exception(exceptions.ConnectionError(error))


class Client(server.ServerMixin, keys.KeysMixin, strings.StringsMixin,
             geo.GeoMixin, hashes.HashesMixin, hyperloglog.HyperLogLogMixin,

             lists.ListsMixin, sets.SetsMixin, sortedsets.SortedSetsMixin,