# Path: aredis/exceptions.py
# class RedisError(Exception):
#     pass
# 
# Path: aredis/utils.py
# class NodeFlag:
#     BLOCKED = 'blocked'
#     ALL_NODES = 'all-nodes'
#     ALL_MASTERS = 'all-masters'
#     RANDOM = 'random'
#     SLOT_ID = 'slot-id'
# 
# def nativestr(x):
#     return x if isinstance(x, str) else x.decode('utf-8', 'replace')
# 
# def iteritems(x):
#     return iter(x.items())
# 
# def list_or_args(keys, args):
#     # returns a single list combining keys and args
#     try:
#         iter(keys)
#         # a string or bytes instance can be iterated, but indicates
#         # keys wasn't passed as a list
#         if isinstance(keys, (str, bytes)):
#             keys = [keys]
#     except TypeError:
#         keys = [keys]
#     if args:
#         keys.extend(args)
#     return keys
# 
# def dict_merge(*dicts):
#     merged = {}
#     for d in dicts:
#         merged.update(d)
#     return merged
# 
# def bool_ok(response):
#     return nativestr(response) == 'OK'
# 
# def string_keys_to_dict(key_string, callback):
#     return dict.fromkeys(key_string.split(), callback)


import datetime
from aredis.exceptions import RedisError
from aredis.utils import (NodeFlag, nativestr,
                          iteritems,
                          list_or_args,
                          dict_merge,
                          bool_ok,
                          string_keys_to_dict)
        return await self.execute_command('SETNX', name, value)

    async def setrange(self, name, offset, value):
        """
        Overwrite bytes in the value of ``name`` starting at ``offset`` with
        ``value``. If ``offset`` plus the length of ``value`` exceeds the
        length of the original value, the new value will be larger than before.
        If ``offset`` exceeds the length of the original value, null bytes
        will be used to pad between the end of the previous value and the start
        of what's being injected.

        Returns the length of the new string.
        """
        return await self.execute_command('SETRANGE', name, offset, value)

    async def strlen(self, name):
        """Returns the number of bytes stored in the value of ``name``"""
        return await self.execute_command('STRLEN', name)

    async def substr(self, name, start, end=-1):
        """
        Returns a substring of the string at key ``name``. ``start`` and ``end``
        are 0-based integers specifying the portion of the string to return.
        """
        return await self.execute_command('SUBSTR', name, start, end)


class ClusterStringsCommandMixin(StringsCommandMixin):

    NODES_FLAGS = {

# Path: aredis/exceptions.py
# class RedisError(Exception):
#     pass
# 
# Path: aredis/utils.py
# class NodeFlag:
#     BLOCKED = 'blocked'
#     ALL_NODES = 'all-nodes'
#     ALL_MASTERS = 'all-masters'
#     RANDOM = 'random'
#     SLOT_ID = 'slot-id'
# 
# def nativestr(x):
#     return x if isinstance(x, str) else x.decode('utf-8', 'replace')
# 
# def iteritems(x):
#     return iter(x.items())
# 
# def list_or_args(keys, args):
#     # returns a single list combining keys and args
#     try:
#         iter(keys)
#         # a string or bytes instance can be iterated, but indicates
#         # keys wasn't passed as a list
#         if isinstance(keys, (str, bytes)):
#             keys = [keys]
#     except TypeError:
#         keys = [keys]
#     if args:
#         keys.extend(args)
#     return keys
# 
# def dict_merge(*dicts):
#     merged = {}
#     for d in dicts:
#         merged.update(d)
#     return merged
# 
# def bool_ok(response):
#     return nativestr(response) == 'OK'
# 
# def string_keys_to_dict(key_string, callback):
#     return dict.fromkeys(key_string.split(), callback)


# Path: aredis/commands/strings.py
import datetime
from aredis.exceptions import RedisError
from aredis.utils import (NodeFlag, nativestr,
                          iteritems,
                          list_or_args,
                          dict_merge,
                          bool_ok,
                          string_keys_to_dict)

        return await self.execute_command('SETNX', name, value)

    async def setrange(self, name, offset, value):
        """
        Overwrite bytes in the value of ``name`` starting at ``offset`` with
        ``value``. If ``offset`` plus the length of ``value`` exceeds the
        length of the original value, the new value will be larger than before.
        If ``offset`` exceeds the length of the original value, null bytes
        will be used to pad between the end of the previous value and the start
        of what's being injected.

        Returns the length of the new string.
        """
        return await self.execute_command('SETRANGE', name, offset, value)

    async def strlen(self, name):
        """Returns the number of bytes stored in the value of ``name``"""
        return await self.execute_command('STRLEN', name)

    async def substr(self, name, start, end=-1):
        """
        Returns a substring of the string at key ``name``. ``start`` and ``end``
        are 0-based integers specifying the portion of the string to return.
        """
        return await self.execute_command('SUBSTR', name, start, end)


class ClusterStringsCommandMixin(StringsCommandMixin):

    NODES_FLAGS = {

        'BITOP': NodeFlag.BLOCKED