"""
Tests for bitarray

Author: Ilan Schnell
"""
import os
import sys
import unittest
import tempfile
import shutil
from random import randint

is_py3k = bool(sys.version_info[0] == 3)

# imports needed inside tests
import copy
import pickle
import itertools

try:
    import shelve, hashlib
except ImportError:
    shelve = hashlib = None

if is_py3k:
    from io import StringIO
    unicode = str
else:
    from cStringIO import StringIO

from bitarray import (bitarray, frozenbitarray,
                      bitdiff, bits2bytes, _sysinfo, __version__)

tests = []

class Util(object):

    @staticmethod
    def randombitarrays(start=1):
        for n in list(range(start, 25)) + [randint(1000, 2000)]:
            a = bitarray(endian=['little', 'big'][randint(0, 1)])
            a.frombytes(os.urandom(bits2bytes(n)))
            del a[n:]
            yield a

    @staticmethod
    def randomlists():
        for n in list(range(25)) + [randint(1000, 2000)]:
            yield [bool(randint(0, 1)) for d in range(n)]

    @staticmethod
    def rndsliceidx(length):
        if randint(0, 1):
            return None
        else:
            return randint(-length-5, length+5)

    @staticmethod
    def slicelen(s, length):
        assert isinstance(s, slice)
        start, stop, step = s.indices(length)
        slicelength = (stop - start + (1 if step < 0 else -1)) // step + 1
        if slicelength < 0:
            slicelength = 0
        return slicelength

    def check_obj(self, a):
        self.assertEqual(repr(type(a)), "<class 'bitarray.bitarray'>")
        unused = 8 * a.buffer_info()[1] - len(a)
        self.assertTrue(0 <= unused < 8)
        self.assertEqual(unused, a.buffer_info()[3])

    def assertEQUAL(self, a, b):
        self.assertEqual(a, b)
        self.assertEqual(a.endian(), b.endian())
        self.check_obj(a)
        self.check_obj(b)

    def assertStopIteration(self, it):
        if is_py3k:
            return
        self.assertRaises(StopIteration, it.next)

    if sys.version_info[:2] == (2, 6):
        def assertIsInstance(self, o, t):
            self.assertTrue(isinstance(o, t))

# ---------------------------------------------------------------------------

class TestsModuleFunctions(unittest.TestCase, Util):

    def test_bitdiff(self):
        a = bitarray('0011')
        b = bitarray('0101')
        self.assertEqual(bitdiff(a, b), 2)
        self.assertRaises(TypeError, bitdiff, a, '')
        self.assertRaises(TypeError, bitdiff, '1', b)
        self.assertRaises(TypeError, bitdiff, a, 4)
        b.append(1)
        self.assertRaises(ValueError, bitdiff, a, b)

        for n in list(range(50)) + [randint(1000, 2000)]:
            a = bitarray()
            a.frombytes(os.urandom(bits2bytes(n)))
            del a[n:]
            b = bitarray()
            b.frombytes(os.urandom(bits2bytes(n)))
            del b[n:]
            diff = sum(a[i] ^ b[i] for i in range(n))
            self.assertEqual(bitdiff(a, b), diff)

    def test_bits2bytes(self):
        for arg in ['foo', [], None, {}]:
            self.assertRaises(TypeError, bits2bytes, arg)

        self.assertRaises(TypeError, bits2bytes, 187.0)
        self.assertRaises(TypeError, bits2bytes, -4.0)
        self.assertRaises(TypeError, bits2bytes)
        self.assertRaises(TypeError, bits2bytes, 1, 2)

        self.assertRaises(ValueError, bits2bytes, -1)
        self.assertRaises(ValueError, bits2bytes, -924)

        self.assertEqual(bits2bytes(0), 0)
        for n in range(1, 100):
            self.assertEqual(bits2bytes(n), (n - 1) // 8 + 1)

        for n, m in [(0, 0), (1, 1), (2, 1), (7, 1), (8, 1), (9, 2),
                     (10, 2), (15, 2), (16, 2), (64, 8), (65, 9),
                     (2**31, 2**28), (2**32, 2**29), (2**34, 2**31),
                     (2**34+793, 2**31+100), (2**35-8, 2**32-1),
                     (2**62, 2**59), (2**63-8, 2**60-1)]:
            self.assertEqual(bits2bytes(n), m)

tests.append(TestsModuleFunctions)

# ---------------------------------------------------------------------------

class CreateObjectTests(unittest.TestCase, Util):

    def test_noInitializer(self):
        a = bitarray()
        self.assertEqual(len(a), 0)
        self.assertEqual(a.tolist(), [])
        self.check_obj(a)

    def test_endian1(self):
        a = bitarray(endian='little')
        a.fromstring('A')
        self.assertEqual(a.endian(), 'little')
        self.assertIsInstance(a.endian(), str)
        self.check_obj(a)

        b = bitarray(endian='big')
        b.fromstring('A')
        self.assertEqual(b.endian(), 'big')
        self.assertIsInstance(a.endian(), str)
        self.check_obj(b)

        self.assertEqual(a.tostring(), b.tostring())

    def test_endian2(self):
        a = bitarray(endian='little')
        a.fromstring(' ')
        self.assertEqual(a.endian(), 'little')
        self.check_obj(a)

        b = bitarray(endian='big')
        b.fromstring(' ')
        self.assertEqual(b.endian(), 'big')
        self.check_obj(b)

        self.assertEqual(a.tostring(), b.tostring())

        self.assertRaises(TypeError, bitarray.__new__, bitarray, endian=0)
        self.assertRaises(ValueError, bitarray.__new__, bitarray, endian='')
        self.assertRaises(ValueError, bitarray.__new__,
                          bitarray, endian='foo')

    def test_integers(self):
        for n in range(50):
            a = bitarray(n)
            self.assertEqual(len(a), n)
            self.check_obj(a)

            a = bitarray(int(n))
            self.assertEqual(len(a), n)
            self.check_obj(a)

        self.assertRaises(ValueError, bitarray.__new__, bitarray, -1)
        self.assertRaises(ValueError, bitarray.__new__, bitarray, -924)

    def test_list(self):
        lst = ['foo', None, [1], {}]
        a = bitarray(lst)
        self.assertEqual(a.tolist(), [True, False, True, False])
        self.check_obj(a)

        for n in range(50):
            lst = [bool(randint(0, 1)) for d in range(n)]
            a = bitarray(lst)
            self.assertEqual(a.tolist(), lst)
            self.check_obj(a)

    def test_tuple(self):
        tup = ('', True, [], {1:2})
        a = bitarray(tup)
        self.assertEqual(a.tolist(), [False, True, False, True])
        self.check_obj(a)

        for n in range(50):
            lst = [bool(randint(0, 1)) for d in range(n)]
            a = bitarray(tuple(lst))
            self.assertEqual(a.tolist(), lst)
            self.check_obj(a)

    def test_iter1(self):
        for n in range(50):
            lst = [bool(randint(0, 1)) for d in range(n)]
            a = bitarray(iter(lst))
            self.assertEqual(a.tolist(), lst)
            self.check_obj(a)

    def test_iter2(self):
        for lst in self.randomlists():
            def foo():
                for x in lst:
                    yield x
            a = bitarray(foo())
            self.assertEqual(a, bitarray(lst))
            self.check_obj(a)

    def test_iter3(self):
        a = bitarray(itertools.repeat(False, 10))
        self.assertEqual(a, bitarray(10 * '0'))
        # Note that the through value of '0' is True: bool('0') -> True
        a = bitarray(itertools.repeat('0', 10))
        self.assertEqual(a, bitarray(10 * '1'))

    def test_01(self):
        a = bitarray('0010111')
        self.assertEqual(a.tolist(), [0, 0, 1, 0, 1, 1, 1])
        self.check_obj(a)

        for n in range(50):
            lst = [bool(randint(0, 1)) for d in range(n)]
            s = ''.join([['0', '1'][x] for x in lst])
            a = bitarray(s)
            self.assertEqual(a.tolist(), lst)
            self.check_obj(a)

        self.assertRaises(ValueError, bitarray.__new__, bitarray, '01012100')

    def test_rawbytes(self): # this representation is used for pickling
        for s, r in [(b'\x00', ''), (b'\x07\xff', '1'), (b'\x03\xff', '11111'),
                     (b'\x01\x87\xda', '10000111' '1101101')]:
            self.assertEqual(bitarray(s, endian='big'),
                             bitarray(r))

        for i in range(1, 8):
            self.assertRaises(ValueError, bitarray.__new__,
                              bitarray, bytes(bytearray([i])))

    def test_bitarray(self):
        for n in range(10):
            a = bitarray(n)
            b = bitarray(a)
            self.assertFalse(a is b)
            self.assertEQUAL(a, b)

        for end in ('little', 'big'):
            a = bitarray(endian=end)
            c = bitarray(a)
            self.assertEqual(c.endian(), end)
            c = bitarray(a, endian='little')
            self.assertEqual(c.endian(), 'little')
            c = bitarray(a, endian='big')
            self.assertEqual(c.endian(), 'big')

    def test_None(self):
        self.assertEQUAL(bitarray(), bitarray(0))
        self.assertEQUAL(bitarray(), bitarray(None))

    def test_WrongArgs(self):
        self.assertRaises(TypeError, bitarray.__new__, bitarray, 'A', 42, 69)

        self.assertRaises(TypeError, bitarray.__new__, bitarray, Ellipsis)
        self.assertRaises(TypeError, bitarray.__new__, bitarray, slice(0))

        self.assertRaises(TypeError, bitarray.__new__, bitarray, 2.345)
        self.assertRaises(TypeError, bitarray.__new__, bitarray, 4+3j)

        self.assertRaises(TypeError, bitarray.__new__, bitarray, '', 0, 42)
        self.assertRaises(ValueError, bitarray.__new__, bitarray, 0, 'foo')

tests.append(CreateObjectTests)

# ---------------------------------------------------------------------------

class ToObjectsTests(unittest.TestCase, Util):

    def test_numeric(self):
        a = bitarray()
        self.assertRaises(Exception, int, a)
        self.assertRaises(Exception, float, a)
        self.assertRaises(Exception, complex, a)

    def test_list(self):
        for a in self.randombitarrays():
            self.assertEqual(list(a), a.tolist())

    def test_tuple(self):
        for a in self.randombitarrays():
            self.assertEqual(tuple(a), tuple(a.tolist()))

tests.append(ToObjectsTests)

# ---------------------------------------------------------------------------

class MetaDataTests(unittest.TestCase, Util):

    def test_buffer_info1(self):
        a = bitarray('0000111100001', endian='little')
        self.assertEqual(a.buffer_info()[1:4], (2, 'little', 3))

        a = bitarray()
        self.assertRaises(TypeError, a.buffer_info, 42)

        bi = a.buffer_info()
        self.assertIsInstance(bi, tuple)
        self.assertEqual(len(bi), 5)

        self.assertIsInstance(bi[0], int)
        if is_py3k:
            self.assertIsInstance(bi[1], int)
        self.assertIsInstance(bi[2], str)
        self.assertIsInstance(bi[3], int)
        if is_py3k:
            self.assertIsInstance(bi[4], int)

    def test_buffer_info2(self):
        for n in range(50):
            bi = bitarray(n).buffer_info()
            self.assertEqual(bi[1], bits2bytes(n))
            self.assertEqual(bi[3] + n, 8 * bi[1])
            self.assertTrue(bi[4] >= bi[1])

    def test_buffer_info3(self):
        a = bitarray(endian='little')
        self.assertEqual(a.buffer_info()[2], 'little')

        a = bitarray(endian='big')
        self.assertEqual(a.buffer_info()[2], 'big')

    def test_endian(self):
        a = bitarray(endian='little')
        self.assertEqual(a.endian(), 'little')

        a = bitarray(endian='big')
        self.assertEqual(a.endian(), 'big')

    def test_length(self):
        for n in range(100):
            a = bitarray(n)
            self.assertEqual(len(a), n)
            self.assertEqual(a.length(), n)

tests.append(MetaDataTests)

# ---------------------------------------------------------------------------

class SliceTests(unittest.TestCase, Util):

    def test_getitem1(self):
        a = bitarray()
        self.assertRaises(IndexError, a.__getitem__,  0)
        a.append(True)
        self.assertEqual(a[0], True)
        self.assertRaises(IndexError, a.__getitem__,  1)
        self.assertRaises(IndexError, a.__getitem__, -2)
        a.append(False)
        self.assertEqual(a[1], False)
        self.assertRaises(IndexError, a.__getitem__,  2)
        self.assertRaises(IndexError, a.__getitem__, -3)

    def test_getitem2(self):
        a = bitarray('1100010')
        for i, b in enumerate([True, True, False, False, False, True, False]):
            self.assertEqual(a[i], b)
            self.assertEqual(a[i-7], b)
        self.assertRaises(IndexError, a.__getitem__,  7)
        self.assertRaises(IndexError, a.__getitem__, -8)

    def test_getitem3(self):
        a = bitarray('0100000100001')
        self.assertEQUAL(a[:], a)
        self.assertFalse(a[:] is a)
        aa = a.tolist()
        self.assertEQUAL(a[11:2:-3], bitarray(aa[11:2:-3]))
        self.check_obj(a[:])

        self.assertRaises(ValueError, a.__getitem__, slice(None, None, 0))
        self.assertRaises(TypeError, a.__getitem__, (1, 2))

    def test_getitem4(self):
        for a in self.randombitarrays(start=1):
            aa = a.tolist()
            la = len(a)
            for dum in range(10):
                step = self.rndsliceidx(la) or None
                s = slice(self.rndsliceidx(la), self.rndsliceidx(la), step)
                self.assertEQUAL(a[s], bitarray(aa[s], endian=a.endian()))

    def test_setitem1(self):
        a = bitarray([False])
        a[0] = 1
        self.assertEqual(a, bitarray('1'))

        a = bitarray(2)
        a[0] = 0
        a[1] = 1
        self.assertEqual(a, bitarray('01'))
        a[-1] = 0
        a[-2] = 1
        self.assertEqual(a, bitarray('10'))

        self.assertRaises(IndexError, a.__setitem__,  2, True)
        self.assertRaises(IndexError, a.__setitem__, -3, False)

    def test_setitem2(self):
        for a in self.randombitarrays(start=1):
            la = len(a)
            i = randint(0, la - 1)
            aa = a.tolist()
            ida = id(a)
            val = bool(randint(0, 1))
            a[i] = val
            aa[i] = val
            self.assertEqual(a.tolist(), aa)
            self.assertEqual(id(a), ida)
            self.check_obj(a)

            b = bitarray(la)
            b[0:la] = bitarray(a)
            self.assertEqual(a, b)
            self.assertNotEqual(id(a), id(b))

            b = bitarray(la)
            b[:] = bitarray(a)
            self.assertEqual(a, b)
            self.assertNotEqual(id(a), id(b))

            b = bitarray(la)
            b[::-1] = bitarray(a)
            self.assertEqual(a.tolist()[::-1], b.tolist())

    def test_setitem3(self):
        a = bitarray('00000')
        a[0] = 1
        a[-2] = 1
        self.assertEqual(a, bitarray('10010'))
        self.assertRaises(IndexError, a.__setitem__, 5, 'foo')
        self.assertRaises(IndexError, a.__setitem__, -6, 'bar')

    def test_setitem4(self):
        for a in self.randombitarrays(start=1):
            la = len(a)
            for dum in range(10):
                step = self.rndsliceidx(la) or None
                s = slice(self.rndsliceidx(la), self.rndsliceidx(la), step)
                lb = randint(0, 10) if step is None else self.slicelen(s, la)
                b = bitarray(lb)
                c = bitarray(a)
                c[s] = b
                self.check_obj(c)
                cc = a.tolist()
                cc[s] = b.tolist()
                self.assertEqual(c, bitarray(cc))

    def test_setslice_to_bitarray(self):
        a = bitarray('11111111' '1111')
        a[2:6] = bitarray('0010')
        self.assertEqual(a, bitarray('11001011' '1111'))
        a.setall(0)
        a[::2] = bitarray('111001')
        self.assertEqual(a, bitarray('10101000' '0010'))
        a.setall(0)
        a[3:] = bitarray('111')
        self.assertEqual(a, bitarray('000111'))
        a = bitarray(12)
        a.setall(0)
        a[1:11:2] = bitarray('11101')
        self.assertEqual(a, bitarray('01010100' '0100'))
        a = bitarray(12)
        a.setall(0)
        a[:-6:-1] = bitarray('10111')
        self.assertEqual(a, bitarray('00000001' '1101'))
        a = bitarray('1111')
        a[3:3] = bitarray('000')  # insert
        self.assertEqual(a, bitarray('1110001'))
        a[2:5] = bitarray()  # remove
        self.assertEqual(a, bitarray('1101'))
        a = bitarray('1111')
        a[1:3] = bitarray('0000')
        self.assertEqual(a, bitarray('100001'))
        a[:] = bitarray('010') # replace all values
        self.assertEqual(a, bitarray('010'))

    def test_setslice_to_bool(self):
        a = bitarray('11111111')
        a[::2] = False
        self.assertEqual(a, bitarray('01010101'))
        a[4::] = True #                   ^^^^
        self.assertEqual(a, bitarray('01011111'))
        a[-2:] = False #                    ^^
        self.assertEqual(a, bitarray('01011100'))
        a[:2:] = True #               ^^
        self.assertEqual(a, bitarray('11011100'))
        a[:] = True #                 ^^^^^^^^
        self.assertEqual(a, bitarray('11111111'))
        a[2:5] = False #                ^^^
        self.assertEqual(a, bitarray('11000111'))
        a[1::3] = False #              ^  ^  ^
        self.assertEqual(a, bitarray('10000110'))
        a[1:6:2] = True #              ^ ^ ^
        self.assertEqual(a, bitarray('11010110'))

    def test_setslice_to_int(self):
        a = bitarray('11111111')
        a[::2] = 0 #  ^ ^ ^ ^
        self.assertEqual(a, bitarray('01010101'))
        a[4::] = 1 #                      ^^^^
        self.assertEqual(a, bitarray('01011111'))
        a.__setitem__(slice(-2, None, None), 0)
        self.assertEqual(a, bitarray('01011100'))
        self.assertRaises(ValueError, a.__setitem__, slice(None, None, 2), 3)
        self.assertRaises(ValueError, a.__setitem__, slice(None, 2, None), -1)

    def test_sieve(self): # Sieve of Eratosthenes
        a = bitarray(50)
        a.setall(1)
        for i in range(2, 8):
            if a[i]:
                a[i*i::i] = 0
        primes = [i for i in range(2, 50) if a[i]]
        self.assertEqual(primes, [2, 3, 5, 7, 11, 13, 17, 19,
                                  23, 29, 31, 37, 41, 43, 47])

    def test_delitem1(self):
        a = bitarray('100110')
        del a[1]
        self.assertEqual(len(a), 5)
        del a[3]
        del a[-2]
        self.assertEqual(a, bitarray('100'))
        self.assertRaises(IndexError, a.__delitem__,  3)
        self.assertRaises(IndexError, a.__delitem__, -4)
        a = bitarray('10101100' '10110')
        del a[3:9] #     ^^^^^   ^
        self.assertEqual(a, bitarray('1010110'))
        del a[::3] #                  ^  ^  ^
        self.assertEqual(a, bitarray('0111'))
        a = bitarray('10101100' '1011011')
        del a[:-9:-2] #          ^ ^ ^ ^
        self.assertEqual(a, bitarray('10101100' '011'))

    def test_delitem2(self):
        for a in self.randombitarrays(start=1):
            la = len(a)
            for dum in range(10):
                step = self.rndsliceidx(la) or None
                s = slice(self.rndsliceidx(la), self.rndsliceidx(la), step)
                c = bitarray(a)
                d = c
                del c[s]
                self.assertTrue(c is d)
                self.check_obj(c)
                cc = a.tolist()
                del cc[s]
                self.assertEQUAL(c, bitarray(cc, endian=c.endian()))

tests.append(SliceTests)

# ---------------------------------------------------------------------------

class MiscTests(unittest.TestCase, Util):

    def test_instancecheck(self):
        a = bitarray('011')
        self.assertIsInstance(a, bitarray)
        self.assertFalse(isinstance(a, str))

    def test_booleanness(self):
        self.assertEqual(bool(bitarray('')), False)
        self.assertEqual(bool(bitarray('0')), True)
        self.assertEqual(bool(bitarray('1')), True)

    def test_to01(self):
        a = bitarray()
        self.assertEqual(a.to01(), '')
        self.assertIsInstance(a.to01(), str)

        a = bitarray('101')
        self.assertEqual(a.to01(), '101')
        self.assertIsInstance(a.to01(), str)

    def test_iterate(self):
        for lst in self.randomlists():
            acc = []
            for b in bitarray(lst):
                acc.append(b)
            self.assertEqual(acc, lst)

    def test_iter1(self):
        it = iter(bitarray('011'))
        self.assertEqual(next(it), False)
        self.assertEqual(next(it), True)
        self.assertEqual(next(it), True)
        self.assertStopIteration(it)

    def test_iter2(self):
        for a in self.randombitarrays():
            aa = a.tolist()
            self.assertEqual(list(a), aa)
            self.assertEqual(list(iter(a)), aa)

    def test_assignment(self):
        a = bitarray('00110111001')
        a[1:3] = a[7:9]
        a[-1:] = a[:1]
        b = bitarray('01010111000')
        self.assertEqual(a, b)

    def test_compare(self):
        for a in self.randombitarrays():
            aa = a.tolist()
            for b in self.randombitarrays():
                bb = b.tolist()
                self.assertEqual(a == b, aa == bb)
                self.assertEqual(a != b, aa != bb)
                self.assertEqual(a <= b, aa <= bb)
                self.assertEqual(a <  b, aa <  bb)
                self.assertEqual(a >= b, aa >= bb)
                self.assertEqual(a >  b, aa >  bb)

    def test_subclassing(self):
        class ExaggeratingBitarray(bitarray):

            def __new__(cls, data, offset):
                return bitarray.__new__(cls, data)

            def __init__(self, data, offset):
                self.offset = offset

            def __getitem__(self, i):
                return bitarray.__getitem__(self, i - self.offset)

        for a in self.randombitarrays(start=1):
            b = ExaggeratingBitarray(a, 1234)
            for i in range(len(a)):
                self.assertEqual(a[i], b[i+1234])

    def test_endianness1(self):
        a = bitarray(endian='little')
        a.frombytes(b'\x01')
        self.assertEqual(a.to01(), '10000000')

        b = bitarray(endian='little')
        b.frombytes(b'\x80')
        self.assertEqual(b.to01(), '00000001')

        c = bitarray(endian='big')
        c.frombytes(b'\x80')
        self.assertEqual(c.to01(), '10000000')

        d = bitarray(endian='big')
        d.frombytes(b'\x01')
        self.assertEqual(d.to01(), '00000001')

        self.assertEqual(a, c)
        self.assertEqual(b, d)

    def test_endianness2(self):
        a = bitarray(8, endian='little')
        a.setall(False)
        a[0] = True
        self.assertEqual(a.tobytes(), b'\x01')
        a[1] = True
        self.assertEqual(a.tobytes(), b'\x03')
        a.frombytes(b' ')
        self.assertEqual(a.tobytes(), b'\x03 ')
        self.assertEqual(a.to01(), '1100000000000100')

    def test_endianness3(self):
        a = bitarray(8, endian='big')
        a.setall(False)
        a[7] = True
        self.assertEqual(a.tobytes(), b'\x01')
        a[6] = True
        self.assertEqual(a.tobytes(), b'\x03')
        a.frombytes(b' ')
        self.assertEqual(a.tobytes(), b'\x03 ')
        self.assertEqual(a.to01(), '0000001100100000')

    def test_endianness4(self):
        a = bitarray('00100000', endian='big')
        self.assertEqual(a.tobytes(), b' ')
        b = bitarray('00000100', endian='little')
        self.assertEqual(b.tobytes(), b' ')
        self.assertNotEqual(a, b)

    def test_endianness5(self):
        a = bitarray('11100000', endian='little')
        b = bitarray(a, endian='big')
        self.assertNotEqual(a, b)
        self.assertEqual(a.tobytes(), b.tobytes())

    def test_pickle(self):
        for v in range(3):
            for a in self.randombitarrays():
                b = pickle.loads(pickle.dumps(a, v))
                self.assertFalse(b is a)
                self.assertEQUAL(a, b)

    def test_overflow(self):
        if _sysinfo()[0] == 8:
            return

        self.assertRaises(OverflowError, bitarray.__new__,
                          bitarray, 2**34 + 1)

        a = bitarray(10 ** 6)
        self.assertRaises(OverflowError, a.__imul__, 17180)

    def test_unicode1(self):
        a = bitarray(unicode())
        self.assertEqual(a, bitarray())

        a = bitarray(unicode('111001'))
        self.assertEqual(a, bitarray('111001'))

        for a in self.randombitarrays():
            b = bitarray(unicode(a.to01()))
            self.assertEqual(a, b)

    def test_unicode2(self):
        a = bitarray()
        a.extend(unicode())
        self.assertEqual(a, bitarray())

        a = bitarray()
        a.extend(unicode('001011'))
        self.assertEqual(a, bitarray('001011'))

        for a in self.randombitarrays():
            b = bitarray()
            b.extend(unicode(a.to01()))
            self.assertEqual(a, b)

    def test_unhashable(self):
        a = bitarray()
        self.assertRaises(TypeError, hash, a)
        self.assertRaises(TypeError, dict, [(a, 'foo')])

tests.append(MiscTests)

# ---------------------------------------------------------------------------

class SpecialMethodTests(unittest.TestCase, Util):

    def test_all(self):
        a = bitarray()
        self.assertTrue(a.all())
        for s, r in ('0', False), ('1', True), ('01', False):
            self.assertEqual(bitarray(s).all(), r)

        for a in self.randombitarrays():
            self.assertEqual(all(a), a.all())
            self.assertEqual(all(a.tolist()), a.all())

    def test_any(self):
        a = bitarray()
        self.assertFalse(a.any())
        for s, r in ('0', False), ('1', True), ('01', True):
            self.assertEqual(bitarray(s).any(), r)

        for a in self.randombitarrays():
            self.assertEqual(any(a), a.any())
            self.assertEqual(any(a.tolist()), a.any())

    def test_repr(self):
        r = repr(bitarray())
        self.assertEqual(r, "bitarray()")
        self.assertIsInstance(r, str)

        r = repr(bitarray('10111'))
        self.assertEqual(r, "bitarray('10111')")
        self.assertIsInstance(r, str)

        for a in self.randombitarrays():
            b = eval(repr(a))
            self.assertFalse(b is a)
            self.assertEqual(a, b)
            self.check_obj(b)

    def test_copy(self):
        for a in self.randombitarrays():
            b = a.copy()
            self.assertFalse(b is a)
            self.assertEQUAL(a, b)

            b = copy.copy(a)
            self.assertFalse(b is a)
            self.assertEQUAL(a, b)

            b = copy.deepcopy(a)
            self.assertFalse(b is a)
            self.assertEQUAL(a, b)

    def assertReallyEqual(self, a, b):
        # assertEqual first, because it will have a good message if the
        # assertion fails.
        self.assertEqual(a, b)
        self.assertEqual(b, a)
        self.assertTrue(a == b)
        self.assertTrue(b == a)
        self.assertFalse(a != b)
        self.assertFalse(b != a)
        if not is_py3k:
            self.assertEqual(0, cmp(a, b))
            self.assertEqual(0, cmp(b, a))

    def assertReallyNotEqual(self, a, b):
        # assertNotEqual first, because it will have a good message if the
        # assertion fails.
        self.assertNotEqual(a, b)
        self.assertNotEqual(b, a)
        self.assertFalse(a == b)
        self.assertFalse(b == a)
        self.assertTrue(a != b)
        self.assertTrue(b != a)
        if not is_py3k:
            self.assertNotEqual(0, cmp(a, b))
            self.assertNotEqual(0, cmp(b, a))

    def test_equality(self):
        self.assertReallyEqual(bitarray(''), bitarray(''))
        self.assertReallyEqual(bitarray('0'), bitarray('0'))
        self.assertReallyEqual(bitarray('1'), bitarray('1'))

    def test_not_equality(self):
        self.assertReallyNotEqual(bitarray(''), bitarray('1'))
        self.assertReallyNotEqual(bitarray(''), bitarray('0'))
        self.assertReallyNotEqual(bitarray('0'), bitarray('1'))

tests.append(SpecialMethodTests)

# ---------------------------------------------------------------------------

class NumberTests(unittest.TestCase, Util):

    def test_add(self):
        c = bitarray('001') + bitarray('110')
        self.assertEQUAL(c, bitarray('001110'))

        for a in self.randombitarrays():
            aa = a.copy()
            for b in self.randombitarrays():
                bb = b.copy()
                c = a + b
                self.assertEqual(c, bitarray(a.tolist() + b.tolist()))
                self.assertEqual(c.endian(), a.endian())
                self.check_obj(c)

                self.assertEQUAL(a, aa)
                self.assertEQUAL(b, bb)

        a = bitarray()
        self.assertRaises(TypeError, a.__add__, 42)

    def test_iadd(self):
        c = bitarray('001')
        c += bitarray('110')
        self.assertEQUAL(c, bitarray('001110'))

        for a in self.randombitarrays():
            for b in self.randombitarrays():
                c = bitarray(a)
                d = c
                d += b
                self.assertEqual(d, a + b)
                self.assertTrue(c is d)
                self.assertEQUAL(c, d)
                self.assertEqual(d.endian(), a.endian())
                self.check_obj(d)

        a = bitarray()
        self.assertRaises(TypeError, a.__iadd__, 42)

    def test_mul(self):
        c = 0 * bitarray('1001111')
        self.assertEQUAL(c, bitarray())

        c = 3 * bitarray('001')
        self.assertEQUAL(c, bitarray('001001001'))

        c = bitarray('110') * 3
        self.assertEQUAL(c, bitarray('110110110'))

        for a in self.randombitarrays():
            b = a.copy()
            for n in range(-10, 20):
                c = a * n
                self.assertEQUAL(c, bitarray(n * a.tolist(),
                                             endian=a.endian()))
                c = n * a
                self.assertEqual(c, bitarray(n * a.tolist(),
                                             endian=a.endian()))
                self.assertEQUAL(a, b)

        a = bitarray()
        self.assertRaises(TypeError, a.__mul__, None)

    def test_imul(self):
        c = bitarray('1101110011')
        idc = id(c)
        c *= 0
        self.assertEQUAL(c, bitarray())
        self.assertEqual(idc, id(c))

        c = bitarray('110')
        c *= 3
        self.assertEQUAL(c, bitarray('110110110'))

        for a in self.randombitarrays():
            for n in range(-10, 10):
                b = a.copy()
                idb = id(b)
                b *= n
                self.assertEQUAL(b, bitarray(n * a.tolist(),
                                             endian=a.endian()))
                self.assertEqual(idb, id(b))

        a = bitarray()
        self.assertRaises(TypeError, a.__imul__, None)

tests.append(NumberTests)

# ---------------------------------------------------------------------------

class BitwiseTests(unittest.TestCase, Util):

    def test_misc(self):
        for a in self.randombitarrays():
            b = ~a
            c = a & b
            self.assertEqual(c.any(), False)
            self.assertEqual(a, a ^ c)
            d = a ^ b
            self.assertEqual(d.all(), True)
            b &= d
            self.assertEqual(~b, a)

    def test_and(self):
        a = bitarray('11001')
        b = bitarray('10011')
        self.assertEQUAL(a & b, bitarray('10001'))

        b = bitarray('1001')
        self.assertRaises(ValueError, a.__and__, b) # not same length

        self.assertRaises(TypeError, a.__and__, 42)

    def test_iand(self):
        a =  bitarray('110010110')
        ida = id(a)
        a &= bitarray('100110011')
        self.assertEQUAL(a, bitarray('100010010'))
        self.assertEqual(ida, id(a))

    def test_or(self):
        a = bitarray('11001')
        b = bitarray('10011')
        aa = a.copy()
        bb = b.copy()
        self.assertEQUAL(a | b, bitarray('11011'))
        self.assertEQUAL(a, aa)
        self.assertEQUAL(b, bb)

    def test_ior(self):
        a = bitarray('110010110')
        b = bitarray('100110011')
        bb = b.copy()
        a |= b
        self.assertEQUAL(a, bitarray('110110111'))
        self.assertEQUAL(b, bb)

    def test_xor(self):
        a = bitarray('11001')
        b = bitarray('10011')
        self.assertEQUAL(a ^ b, bitarray('01010'))

    def test_ixor(self):
        a =  bitarray('110010110')
        a ^= bitarray('100110011')
        self.assertEQUAL(a, bitarray('010100101'))

    def test_invert(self):
        a = bitarray()
        a.invert()
        self.assertEQUAL(a, bitarray())

        a = bitarray('11011')
        a.invert()
        self.assertEQUAL(a, bitarray('00100'))

        a = bitarray('11011')
        b = ~a
        self.assertEQUAL(b, bitarray('00100'))
        self.assertEQUAL(a, bitarray('11011'))
        self.assertFalse(a is b)

        for a in self.randombitarrays():
            b = bitarray(a)
            b.invert()
            for i in range(len(a)):
                self.assertEqual(b[i], not a[i])
            self.check_obj(b)
            c = ~a
            self.assertEQUAL(c, b)
            self.check_obj(c)

tests.append(BitwiseTests)

# ---------------------------------------------------------------------------

class SequenceTests(unittest.TestCase, Util):

    def test_contains1(self):
        a = bitarray()
        self.assertFalse(False in a)
        self.assertFalse(True in a)
        self.assertTrue(bitarray() in a)
        a.append(True)
        self.assertTrue(True in a)
        self.assertFalse(False in a)
        a = bitarray([False])
        self.assertTrue(False in a)
        self.assertFalse(True in a)
        a.append(True)
        self.assertTrue(0 in a)
        self.assertTrue(1 in a)
        if not is_py3k:
            self.assertTrue(long(0) in a)
            self.assertTrue(long(1) in a)

    def test_contains2(self):
        a = bitarray()
        self.assertEqual(a.__contains__(1), False)
        a.append(1)
        self.assertEqual(a.__contains__(1), True)
        a = bitarray('0011')
        self.assertEqual(a.__contains__(bitarray('01')), True)
        self.assertEqual(a.__contains__(bitarray('10')), False)
        self.assertRaises(TypeError, a.__contains__, 'asdf')
        self.assertRaises(ValueError, a.__contains__, 2)
        self.assertRaises(ValueError, a.__contains__, -1)
        if not is_py3k:
            self.assertRaises(ValueError, a.__contains__, long(2))

    def test_contains3(self):
        for n in range(2, 50):
            a = bitarray(n)
            a.setall(0)
            self.assertTrue(False in a)
            self.assertFalse(True in a)
            a[randint(0, n - 1)] = 1
            self.assertTrue(True in a)
            self.assertTrue(False in a)
            a.setall(1)
            self.assertTrue(True in a)
            self.assertFalse(False in a)
            a[randint(0, n - 1)] = 0
            self.assertTrue(True in a)
            self.assertTrue(False in a)

    def test_contains4(self):
        a = bitarray('011010000001')
        for s, r in [('', True), ('1', True), ('11', True), ('111', False),
                     ('011', True), ('0001', True), ('00011', False)]:
            self.assertEqual(bitarray(s) in a, r)

tests.append(SequenceTests)

# ---------------------------------------------------------------------------

class ExtendTests(unittest.TestCase, Util):

    def test_wrongArgs(self):
        a = bitarray()
        self.assertRaises(TypeError, a.extend)
        self.assertRaises(TypeError, a.extend, None)
        self.assertRaises(TypeError, a.extend, True)
        self.assertRaises(TypeError, a.extend, 24)
        self.assertRaises(ValueError, a.extend, '0011201')

    def test_bitarray(self):
        a = bitarray()
        a.extend(bitarray())
        self.assertEqual(a, bitarray())
        a.extend(bitarray('110'))
        self.assertEqual(a, bitarray('110'))
        a.extend(bitarray('1110'))
        self.assertEqual(a, bitarray('1101110'))

        a = bitarray('00001111', endian='little')
        a.extend(bitarray('00111100', endian='big'))
        self.assertEqual(a, bitarray('0000111100111100'))

        for a in self.randombitarrays():
            for b in self.randombitarrays():
                c = bitarray(a)
                idc = id(c)
                c.extend(b)
                self.assertEqual(id(c), idc)
                self.assertEqual(c, a + b)

    def test_list(self):
        a = bitarray()
        a.extend([0, 1, 3, None, {}])
        self.assertEqual(a, bitarray('01100'))
        a.extend([True, False])
        self.assertEqual(a, bitarray('0110010'))

        for a in self.randomlists():
            for b in self.randomlists():
                c = bitarray(a)
                idc = id(c)
                c.extend(b)
                self.assertEqual(id(c), idc)
                self.assertEqual(c.tolist(), a + b)
                self.check_obj(c)

    def test_tuple(self):
        a = bitarray()
        a.extend((0, 1, 2, 0, 3))
        self.assertEqual(a, bitarray('01101'))

        for a in self.randomlists():
            for b in self.randomlists():
                c = bitarray(a)
                idc = id(c)
                c.extend(tuple(b))
                self.assertEqual(id(c), idc)
                self.assertEqual(c.tolist(), a + b)
                self.check_obj(c)

    def test_generator(self):
        def bar():
            for x in ('', '1', None, True, []):
                yield x
        a = bitarray()
        a.extend(bar())
        self.assertEqual(a, bitarray('01010'))

        for a in self.randomlists():
            for b in self.randomlists():
                def foo():
                    for e in b:
                        yield e
                c = bitarray(a)
                idc = id(c)
                c.extend(foo())
                self.assertEqual(id(c), idc)
                self.assertEqual(c.tolist(), a + b)
                self.check_obj(c)

    def test_iterator1(self):
        a = bitarray()
        a.extend(iter([3, 9, 0, 1, -2]))
        self.assertEqual(a, bitarray('11011'))

        for a in self.randomlists():
            for b in self.randomlists():
                c = bitarray(a)
                idc = id(c)
                c.extend(iter(b))
                self.assertEqual(id(c), idc)
                self.assertEqual(c.tolist(), a + b)
                self.check_obj(c)

    def test_iterator2(self):
        a = bitarray()
        a.extend(itertools.repeat(True, 23))
        self.assertEqual(a, bitarray(23 * '1'))

    def test_string01(self):
        a = bitarray()
        a.extend('0110111')
        self.assertEqual(a, bitarray('0110111'))

        for a in self.randomlists():
            for b in self.randomlists():
                c = bitarray(a)
                idc = id(c)
                c.extend(''.join(['0', '1'][x] for x in b))
                self.assertEqual(id(c), idc)
                self.assertEqual(c.tolist(), a + b)
                self.check_obj(c)

    def test_extend_self(self):
        a = bitarray()
        a.extend(a)
        self.assertEqual(a, bitarray())

        a = bitarray('1')
        a.extend(a)
        self.assertEqual(a, bitarray('11'))

        a = bitarray('110')
        a.extend(a)
        self.assertEqual(a, bitarray('110110'))

        for a in self.randombitarrays():
            b = bitarray(a)
            a.extend(a)
            self.assertEqual(a, b + b)

tests.append(ExtendTests)

# ---------------------------------------------------------------------------

class MethodTests(unittest.TestCase, Util):

    def test_append(self):
        a = bitarray()
        a.append(True)
        a.append(False)
        a.append(False)
        self.assertEQUAL(a, bitarray('100'))
        a.append(0)
        a.append(1)
        a.append(2)
        a.append(None)
        a.append('')
        a.append('a')
        self.assertEQUAL(a, bitarray('100011001'))

        for a in self.randombitarrays():
            aa = a.tolist()
            b = a
            b.append(1)
            self.assertTrue(a is b)
            self.check_obj(b)
            self.assertEQUAL(b, bitarray(aa+[1], endian=a.endian()))
            b.append('')
            self.assertEQUAL(b, bitarray(aa+[1, 0], endian=a.endian()))

    def test_insert(self):
        a = bitarray()
        b = a
        a.insert(0, True)
        self.assertTrue(a is b)
        self.assertEqual(a, bitarray('1'))
        self.assertRaises(TypeError, a.insert)
        self.assertRaises(TypeError, a.insert, None)

        for a in self.randombitarrays():
            aa = a.tolist()
            for _ in range(50):
                item = bool(randint(0, 1))
                pos = randint(-len(a) - 2, len(a) + 2)
                a.insert(pos, item)
                aa.insert(pos, item)
                self.assertEqual(a.tolist(), aa)
                self.check_obj(a)

    def test_index1(self):
        a = bitarray()
        for i in (True, False, 1, 0):
            self.assertRaises(ValueError, a.index, i)

        a = bitarray(100 * [False])
        self.assertRaises(ValueError, a.index, True)
        self.assertRaises(TypeError, a.index)
        self.assertRaises(TypeError, a.index, 1, 'a')
        self.assertRaises(TypeError, a.index, 1, 0, 'a')
        self.assertRaises(TypeError, a.index, 1, 0, 100, 1)
        a[20] = a[27] = 1
        self.assertEqual(a.index(42), 20)
        self.assertEqual(a.index(1, 21), 27)
        self.assertEqual(a.index(1, 27), 27)
        self.assertEqual(a.index(1, -73), 27)
        self.assertRaises(ValueError, a.index, 1, 5, 17)
        self.assertRaises(ValueError, a.index, 1, 5, -83)
        self.assertRaises(ValueError, a.index, 1, 21, 27)
        self.assertRaises(ValueError, a.index, 1, 28)
        self.assertEqual(a.index(0), 0)

        a = bitarray(200 * [True])
        self.assertRaises(ValueError, a.index, False)
        a[173] = a[187] = 0
        self.assertEqual(a.index(False), 173)
        self.assertEqual(a.index(True), 0)

    def test_index2(self):
        for n in range(50):
            for m in range(n):
                a = bitarray(n)
                a.setall(0)
                self.assertRaises(ValueError, a.index, 1)
                a[m] = 1
                self.assertEqual(a.index(1), m)

                a.setall(1)
                self.assertRaises(ValueError, a.index, 0)
                a[m] = 0
                self.assertEqual(a.index(0), m)

    def test_index3(self):
        a = bitarray('00001000' '00000000' '0010000')
        self.assertEqual(a.index(1), 4)
        self.assertEqual(a.index(1, 1), 4)
        self.assertEqual(a.index(0, 4), 5)
        self.assertEqual(a.index(1, 5), 18)
        self.assertRaises(ValueError, a.index, 1, 5, 18)
        self.assertRaises(ValueError, a.index, 1, 19)

    def test_index4(self):
        a = bitarray('11110111' '11111111' '1101111')
        self.assertEqual(a.index(0), 4)
        self.assertEqual(a.index(0, 1), 4)
        self.assertEqual(a.index(1, 4), 5)
        self.assertEqual(a.index(0, 5), 18)
        self.assertRaises(ValueError, a.index, 0, 5, 18)
        self.assertRaises(ValueError, a.index, 0, 19)

    def test_index5(self):
        a = bitarray(2000)
        a.setall(0)
        for _ in range(3):
            a[randint(0, 1999)] = 1
        aa = a.tolist()
        for _ in range(100):
            start = randint(0, 2000)
            stop = randint(0, 2000)
            try:
                res1 = a.index(1, start, stop)
            except ValueError:
                res1 = None
            try:
                res2 = aa.index(1, start, stop)
            except ValueError:
                res2 = None
            self.assertEqual(res1, res2)

    def test_index6(self):
        for n in range(1, 50):
            a = bitarray(n)
            i = randint(0, 1)
            a.setall(i)
            for unused in range(randint(1, 4)):
                a[randint(0, n-1)] = 1-i
            aa = a.tolist()
            for unused in range(100):
                start = randint(-50, n+50)
                stop = randint(-50, n+50)
                try:
                    res1 = a.index(1-i, start, stop)
                except ValueError:
                    res1 = None
                try:
                    res2 = aa.index(1-i, start, stop)
                except ValueError:
                    res2 = None
                self.assertEqual(res1, res2)

    def test_count1(self):
        a = bitarray('10011')
        self.assertEqual(a.count(), 3)
        self.assertEqual(a.count(True), 3)
        self.assertEqual(a.count(False), 2)
        self.assertEqual(a.count(1), 3)
        self.assertEqual(a.count(0), 2)
        self.assertEqual(a.count(None), 2)
        self.assertEqual(a.count(''), 2)
        self.assertEqual(a.count('A'), 3)
        self.assertRaises(TypeError, a.count, 0, 'A')
        self.assertRaises(TypeError, a.count, 0, 0, 'A')

    def test_count2(self):
        for i in range(0, 256):
            a = bitarray()
            a.frombytes(bytes(bytearray([i])))
            self.assertEqual(a.count(), a.to01().count('1'))

    def test_count3(self):
        for a in self.randombitarrays():
            s = a.to01()
            self.assertEqual(a.count(1), s.count('1'))
            self.assertEqual(a.count(0), s.count('0'))

    def test_count4(self):
        N = 37
        a = bitarray(N)
        a.setall(1)
        for i in range(N):
            for j in range(i, N):
                self.assertEqual(a.count(1, i, j), j - i)

    def test_count5(self):
        for endian in 'big', 'little':
            a = bitarray('01001100' '01110011' '01', endian)
            self.assertEqual(a.count(), 9)
            self.assertEqual(a.count(0, 12), 3)
            self.assertEqual(a.count(1, -5), 3)
            self.assertEqual(a.count(1, 2, 17), 7)
            self.assertEqual(a.count(1, 6, 11), 2)
            self.assertEqual(a.count(0, 7, -3), 4)
            self.assertEqual(a.count(1, 1, -1), 8)
            self.assertEqual(a.count(1, 17, 14), 0)

    def test_count6(self):
        for a in self.randombitarrays():
            s = a.to01()
            i = randint(-3, len(a)+1)
            j = randint(-3, len(a)+1)
            self.assertEqual(a.count(1, i, j), s[i:j].count('1'))
            self.assertEqual(a.count(0, i, j), s[i:j].count('0'))

    def test_search(self):
        a = bitarray('')
        self.assertEqual(a.search(bitarray('0')), [])
        self.assertEqual(a.search(bitarray('1')), [])

        a = bitarray('1')
        self.assertEqual(a.search(bitarray('0')), [])
        self.assertEqual(a.search(bitarray('1')), [0])
        self.assertEqual(a.search(bitarray('11')), [])

        a = bitarray(100*'1')
        self.assertEqual(a.search(bitarray('0')), [])
        self.assertEqual(a.search(bitarray('1')), list(range(100)))

        a = bitarray('10010101110011111001011')
        for limit in range(10):
            self.assertEqual(a.search(bitarray('011'), limit),
                             [6, 11, 20][:limit])
        self.assertRaises(ValueError, a.search, bitarray())
        self.assertRaises(TypeError, a.search, '010')

    def test_itersearch(self):
        a = bitarray('10011')
        self.assertRaises(ValueError, a.itersearch, bitarray())
        self.assertRaises(TypeError, a.itersearch, '')
        it = a.itersearch(bitarray('1'))
        self.assertEqual(next(it), 0)
        self.assertEqual(next(it), 3)
        self.assertEqual(next(it), 4)
        self.assertStopIteration(it)

    def test_search2(self):
        a = bitarray('10011')
        for s, res in [('0',     [1, 2]),  ('1', [0, 3, 4]),
                       ('01',    [2]),     ('11', [3]),
                       ('000',   []),      ('1001', [0]),
                       ('011',   [2]),     ('0011', [1]),
                       ('10011', [0]),     ('100111', [])]:
            b = bitarray(s)
            self.assertEqual(a.search(b), res)
            self.assertEqual([p for p in a.itersearch(b)], res)

    def test_search3(self):
        a = bitarray('10010101110011111001011')
        for s, res in [('011', [6, 11, 20]),
                       ('111', [7, 12, 13, 14]), # note the overlap
                       ('1011', [5, 19]),
                       ('100', [0, 9, 16])]:
            b = bitarray(s)
            self.assertEqual(a.search(b), res)
            self.assertEqual(list(a.itersearch(b)), res)
            self.assertEqual([p for p in a.itersearch(b)], res)

    def test_search4(self):
        for a in self.randombitarrays():
            aa = a.to01()
            for sub in '0', '1', '01', '01', '11', '101', '1111111':
                sr = a.search(bitarray(sub), 1)
                try:
                    p = sr[0]
                except IndexError:
                    p = -1
                self.assertEqual(p, aa.find(sub))

    def test_search_type(self):
        a = bitarray('10011')
        it = a.itersearch(bitarray('1'))
        self.assertIsInstance(type(it), type)

    def test_fill(self):
        a = bitarray('')
        self.assertEqual(a.fill(), 0)
        self.assertEqual(len(a), 0)

        a = bitarray('101')
        self.assertEqual(a.fill(), 5)
        self.assertEQUAL(a, bitarray('10100000'))
        self.assertEqual(a.fill(), 0)
        self.assertEQUAL(a, bitarray('10100000'))

        for a in self.randombitarrays():
            aa = a.tolist()
            la = len(a)
            b = a
            self.assertTrue(0 <= b.fill() < 8)
            self.assertEqual(b.endian(), a.endian())
            bb = b.tolist()
            lb = len(b)
            self.assertTrue(a is b)
            self.check_obj(b)
            if la % 8 == 0:
                self.assertEqual(bb, aa)
                self.assertEqual(lb, la)
            else:
                self.assertTrue(lb % 8 == 0)
                self.assertNotEqual(bb, aa)
                self.assertEqual(bb[:la], aa)
                self.assertEqual(b[la:], (lb-la)*bitarray('0'))
                self.assertTrue(0 < lb-la < 8)

    def test_sort(self):
        a = bitarray('1101000')
        a.sort()
        self.assertEqual(a, bitarray('0000111'))

        a = bitarray('1101000')
        a.sort(reverse=True)
        self.assertEqual(a, bitarray('1110000'))
        a.sort(reverse=False)
        self.assertEqual(a, bitarray('0000111'))
        a.sort(True)
        self.assertEqual(a, bitarray('1110000'))
        a.sort(False)
        self.assertEqual(a, bitarray('0000111'))

        self.assertRaises(TypeError, a.sort, 'A')

        N = 100000
        a = bitarray(randint(N, N + 100))
        for dum in range(100):
            a[randint(0, N - 1)] = randint(0, 1)
        b = a.tolist()
        a.sort()
        self.assertEqual(a, bitarray(sorted(b)))

        for a in self.randombitarrays():
            b = a.tolist()
            ida = id(a)
            rev = randint(0, 1)
            a.sort(rev)
            self.assertEqual(a, bitarray(sorted(b, reverse=rev)))
            self.assertEqual(id(a), ida)

    def test_reverse(self):
        self.assertRaises(TypeError, bitarray().reverse, 42)

        for x, y in [('', ''), ('1', '1'), ('10', '01'), ('001', '100'),
                     ('1110', '0111'), ('11100', '00111'),
                     ('011000', '000110'), ('1101100', '0011011'),
                     ('11110000', '00001111'),
                     ('11111000011', '11000011111'),
                     ('11011111' '00100000' '000111',
                      '111000' '00000100' '11111011')]:
            a = bitarray(x)
            a.reverse()
            self.assertEQUAL(a, bitarray(y))

        for a in self.randombitarrays():
            aa = a.tolist()
            b = bitarray(a)
            ida = id(a)
            a.reverse()
            self.assertEqual(ida, id(a))
            self.assertEQUAL(a, bitarray(aa[::-1], endian=a.endian()))
            self.assertEqual(a, b[::-1])

    def test_tolist(self):
        a = bitarray()
        self.assertEqual(a.tolist(), [])

        a = bitarray('110')
        self.assertEqual(a.tolist(), [True, True, False])

        for lst in self.randomlists():
            a = bitarray(lst)
            self.assertEqual(a.tolist(), lst)

    def test_remove(self):
        a = bitarray()
        for i in (True, False, 1, 0):
            self.assertRaises(ValueError, a.remove, i)

        a = bitarray(21)
        a.setall(0)
        self.assertRaises(ValueError, a.remove, 1)
        a.setall(1)
        self.assertRaises(ValueError, a.remove, 0)

        a = bitarray('1010110')
        for val, res in [(False, '110110'), (True, '10110'),
                         (1, '0110'), (1, '010'), (0, '10'),
                         (0, '1'), (1, '')]:
            a.remove(val)
            self.assertEQUAL(a, bitarray(res))

        a = bitarray('0010011')
        b = a
        b.remove('1')
        self.assertTrue(b is a)
        self.assertEQUAL(b, bitarray('000011'))

    def test_pop(self):
        for x, n, r, y in [('1', 0, True, ''),
                           ('0', -1, False, ''),
                           ('0011100', 3, True, '001100')]:
            a = bitarray(x)
            self.assertEqual(a.pop(n), r)
            self.assertEqual(a, bitarray(y))

        a = bitarray('01')
        self.assertEqual(a.pop(), True)
        self.assertEqual(a.pop(), False)
        self.assertRaises(IndexError, a.pop)

        for a in self.randombitarrays():
            self.assertRaises(IndexError, a.pop, len(a))
            self.assertRaises(IndexError, a.pop, -len(a)-1)
            if len(a) == 0:
                continue
            aa = a.tolist()
            enda = a.endian()
            self.assertEqual(a.pop(), aa[-1])
            self.check_obj(a)
            self.assertEqual(a.endian(), enda)

        for a in self.randombitarrays(start=1):
            n = randint(-len(a), len(a)-1)
            aa = a.tolist()
            self.assertEqual(a.pop(n), aa[n])
            aa.pop(n)
            self.assertEqual(a, bitarray(aa))
            self.check_obj(a)

    def test_setall(self):
        a = bitarray(5)
        a.setall(True)
        self.assertEQUAL(a, bitarray('11111'))

        for a in self.randombitarrays():
            val = randint(0, 1)
            b = a
            b.setall(val)
            self.assertEqual(b, bitarray(len(b) * [val]))
            self.assertTrue(a is b)
            self.check_obj(b)

    def test_bytereverse(self):
        for x, y in [('', ''),
                     ('1', '0'),
                     ('1011', '0000'),
                     ('111011', '001101'),
                     ('11101101', '10110111'),
                     ('000000011', '100000000'),
                     ('11011111' '00100000' '000111',
                      '11111011' '00000100' '001110')]:
            a = bitarray(x)
            a.bytereverse()
            self.assertEqual(a, bitarray(y))

        for i in range(256):
            a = bitarray()
            a.frombytes(bytes(bytearray([i])))
            aa = a.tolist()
            b = a
            b.bytereverse()
            self.assertEqual(b, bitarray(aa[::-1]))
            self.assertTrue(a is b)
            self.check_obj(b)

tests.append(MethodTests)

# ---------------------------------------------------------------------------

class StringTests(unittest.TestCase, Util):

    def randombytes(self):
        for n in range(1, 20):
            yield os.urandom(n)

    def test_frombytes(self):
        a = bitarray(endian='big')
        a.frombytes(b'A')
        self.assertEqual(a, bitarray('01000001'))

        b = a
        b.frombytes(b'BC')
        self.assertEQUAL(b, bitarray('01000001' '01000010' '01000011',
                                     endian='big'))
        self.assertTrue(b is a)

        for b in self.randombitarrays():
            c = b.copy()
            b.frombytes(b'')
            self.assertEQUAL(b, c)

        for b in self.randombitarrays():
            for s in self.randombytes():
                a = bitarray(endian=b.endian())
                a.frombytes(s)
                c = b.copy()
                b.frombytes(s)
                self.assertEQUAL(b[-len(a):], a)
                self.assertEQUAL(b[:-len(a)], c)
                self.assertEQUAL(b, c + a)

    def test_tobytes(self):
        a = bitarray()
        self.assertEqual(a.tobytes(), b'')

        for end in ('big', 'little'):
            a = bitarray(endian=end)
            a.frombytes(b'foo')
            self.assertEqual(a.tobytes(), b'foo')

            for s in self.randombytes():
                a = bitarray(endian=end)
                a.frombytes(s)
                self.assertEqual(a.tobytes(), s)

        for n, s in [(1, b'\x01'), (2, b'\x03'), (3, b'\x07'), (4, b'\x0f'),
                     (5, b'\x1f'), (6, b'\x3f'), (7, b'\x7f'), (8, b'\xff'),
                     (12, b'\xff\x0f'), (15, b'\xff\x7f'), (16, b'\xff\xff'),
                     (17, b'\xff\xff\x01'), (24, b'\xff\xff\xff')]:
            a = bitarray(n, endian='little')
            a.setall(1)
            self.assertEqual(a.tobytes(), s)

    def test_unpack(self):
        a = bitarray('01')
        if is_py3k:
            self.assertIsInstance(a.unpack(), bytes)
        else:
            self.assertIsInstance(a.unpack(), str)
        self.assertEqual(a.unpack(), b'\x00\xff')
        self.assertEqual(a.unpack(b'A'), b'A\xff')
        self.assertEqual(a.unpack(b'0', b'1'), b'01')
        self.assertEqual(a.unpack(one=b'\x01'), b'\x00\x01')
        self.assertEqual(a.unpack(zero=b'A'), b'A\xff')
        self.assertEqual(a.unpack(one=b't', zero=b'f'), b'ft')

        self.assertRaises(TypeError, a.unpack, b'a', zero=b'b')
        self.assertRaises(TypeError, a.unpack, foo=b'b')

        for a in self.randombitarrays():
            self.assertEqual(a.unpack(b'0', b'1'), a.to01().encode())

            b = bitarray()
            b.pack(a.unpack())
            self.assertEqual(b, a)

            b = bitarray()
            b.pack(a.unpack(b'\x01', b'\x00'))
            b.invert()
            self.assertEqual(b, a)

    def test_pack(self):
        a = bitarray()
        a.pack(b'\x00')
        self.assertEqual(a, bitarray('0'))
        a.pack(b'\xff')
        self.assertEqual(a, bitarray('01'))
        a.pack(b'\x01\x00\x7a')
        self.assertEqual(a, bitarray('01101'))

        a = bitarray()
        for n in range(256):
            a.pack(bytes(bytearray([n])))
        self.assertEqual(a, bitarray('0' + 255 * '1'))

        self.assertRaises(TypeError, a.pack, 0)
        if is_py3k:
            self.assertRaises(TypeError, a.pack, '1')
        self.assertRaises(TypeError, a.pack, [1, 3])
        self.assertRaises(TypeError, a.pack, bitarray())

tests.append(StringTests)

# ---------------------------------------------------------------------------

class FileTests(unittest.TestCase, Util):

    def setUp(self):
        self.tmpdir = tempfile.mkdtemp()
        self.tmpfname = os.path.join(self.tmpdir, 'testfile')

    def tearDown(self):
        shutil.rmtree(self.tmpdir)

    def test_pickle(self):
        for v in range(3):
            for a in self.randombitarrays():
                with open(self.tmpfname, 'wb') as fo:
                    pickle.dump(a, fo, v)
                b = pickle.load(open(self.tmpfname, 'rb'))
                self.assertFalse(b is a)
                self.assertEQUAL(a, b)

    def test_shelve(self):
        if not shelve or hasattr(sys, 'gettotalrefcount'):
            return

        d = shelve.open(self.tmpfname)
        stored = []
        for a in self.randombitarrays():
            key = hashlib.md5(repr(a).encode() +
                              a.endian().encode()).hexdigest()
            d[key] = a
            stored.append((key, a))
        d.close()
        del d

        d = shelve.open(self.tmpfname)
        for k, v in stored:
            self.assertEQUAL(d[k], v)
        d.close()

    def test_fromfile_wrong_args(self):
        b = bitarray()
        self.assertRaises(TypeError, b.fromfile)
        self.assertRaises(TypeError, b.fromfile, StringIO()) # file not open
        self.assertRaises(TypeError, b.fromfile, 42)
        self.assertRaises(TypeError, b.fromfile, 'bar')

    def test_from_empty_file(self):
        with open(self.tmpfname, 'wb') as fo:
            pass

        a = bitarray()
        a.fromfile(open(self.tmpfname, 'rb'))
        self.assertEqual(a, bitarray())

    def test_from_large_file(self):
        N = 100000

        with open(self.tmpfname, 'wb') as fo:
            fo.write(N * b'X')

        a = bitarray()
        a.fromfile(open(self.tmpfname, 'rb'))
        self.assertEqual(len(a), 8 * N)
        self.assertEqual(a.buffer_info()[1], N)
        # make sure there is no over-allocation
        self.assertEqual(a.buffer_info()[4], N)

    def test_fromfile_Foo(self):
        with open(self.tmpfname, 'wb') as fo:
            fo.write(b'Foo\n')

        a = bitarray(endian='big')
        a.fromfile(open(self.tmpfname, 'rb'))
        self.assertEqual(a, bitarray('01000110011011110110111100001010'))

        a = bitarray(endian='little')
        a.fromfile(open(self.tmpfname, 'rb'))
        self.assertEqual(a, bitarray('01100010111101101111011001010000'))

        a = bitarray('1', endian='little')
        a.fromfile(open(self.tmpfname, 'rb'))
        self.assertEqual(a, bitarray('101100010111101101111011001010000'))

        for n in range(20):
            a = bitarray(n, endian='little')
            a.setall(1)
            a.fromfile(open(self.tmpfname, 'rb'))
            self.assertEqual(a,
                             n*bitarray('1') +
                             bitarray('01100010111101101111011001010000'))

    def test_fromfile_n(self):
        a = bitarray()
        a.fromstring('ABCDEFGHIJ')
        with open(self.tmpfname, 'wb') as fo:
            a.tofile(fo)

        b = bitarray()
        with open(self.tmpfname, 'rb') as f:
            b.fromfile(f, 0);     self.assertEqual(b.tostring(), '')
            b.fromfile(f, 1);     self.assertEqual(b.tostring(), 'A')
            f.read(1)
            b = bitarray()
            b.fromfile(f, 2);     self.assertEqual(b.tostring(), 'CD')
            b.fromfile(f, 1);     self.assertEqual(b.tostring(), 'CDE')
            b.fromfile(f, 0);     self.assertEqual(b.tostring(), 'CDE')
            b.fromfile(f);        self.assertEqual(b.tostring(), 'CDEFGHIJ')
            b.fromfile(f);        self.assertEqual(b.tostring(), 'CDEFGHIJ')

        b = bitarray()
        with open(self.tmpfname, 'rb') as f:
            f.read(1);
            self.assertRaises(EOFError, b.fromfile, f, 10)

        self.assertEqual(b.tostring(), 'BCDEFGHIJ')

        b = bitarray()
        with open(self.tmpfname, 'rb') as f:
            b.fromfile(f);
            self.assertEqual(b.tostring(), 'ABCDEFGHIJ')
            self.assertRaises(EOFError, b.fromfile, f, 1)

    def test_tofile(self):
        a = bitarray()
        with open(self.tmpfname, 'wb') as f:
            a.tofile(f)

        with open(self.tmpfname, 'rb') as fi:
            self.assertEqual(fi.read(), b'')

        a = bitarray('01000110011011110110111100001010', endian='big')
        with open(self.tmpfname, 'wb') as f:
            a.tofile(f)

        with open(self.tmpfname, 'rb') as fi:
            self.assertEqual(fi.read(), b'Foo\n')

        for a in self.randombitarrays():
            b = bitarray(a, endian='big')
            with open(self.tmpfname, 'wb') as fo:
                b.tofile(fo)

            s = open(self.tmpfname, 'rb').read()
            self.assertEqual(len(s), a.buffer_info()[1])

        for n in range(3):
            a.fromstring(n * 'A')
            self.assertRaises(TypeError, a.tofile)
            self.assertRaises(TypeError, a.tofile, StringIO())

            with open(self.tmpfname, 'wb') as f:
                a.tofile(f)
            self.assertRaises(TypeError, a.tofile, f)

        for n in range(20):
            a = n * bitarray('1', endian='little')
            with open(self.tmpfname, 'wb') as fo:
                a.tofile(fo)

            s = open(self.tmpfname, 'rb').read()
            self.assertEqual(len(s), a.buffer_info()[1])

            b = a.copy()
            b.fill()

            c = bitarray(endian='little')
            c.frombytes(s)
            self.assertEqual(c, b)

tests.append(FileTests)

# ---------------------------------------------------------------------------

class PrefixCodeTests(unittest.TestCase, Util):

    def test_encode_string(self):
        a = bitarray()
        d = {'a': bitarray('0')}
        a.encode(d, '')
        self.assertEqual(a, bitarray())
        a.encode(d, 'a')
        self.assertEqual(a, bitarray('0'))
        self.assertEqual(d, {'a': bitarray('0')})

    def test_encode_list(self):
        a = bitarray()
        d = {'a': bitarray('0')}
        a.encode(d, [])
        self.assertEqual(a, bitarray())
        a.encode(d, ['a'])
        self.assertEqual(a, bitarray('0'))
        self.assertEqual(d, {'a': bitarray('0')})

    def test_encode_iter(self):
        a = bitarray()
        d = {'a': bitarray('0'), 'b': bitarray('1')}
        a.encode(d, iter('abba'))
        self.assertEqual(a, bitarray('0110'))

        def foo():
            for c in 'bbaabb':
                yield c

        a.encode(d, foo())
        self.assertEqual(a, bitarray('0110110011'))
        self.assertEqual(d, {'a': bitarray('0'), 'b': bitarray('1')})

    def test_encode(self):
        d = {'I': bitarray('1'),
             'l': bitarray('01'),
             'a': bitarray('001'),
             'n': bitarray('000')}
        a = bitarray()
        a.encode(d, 'Ilan')
        self.assertEqual(a, bitarray('101001000'))
        a.encode(d, 'a')
        self.assertEqual(a, bitarray('101001000001'))
        self.assertEqual(d, {'I': bitarray('1'), 'l': bitarray('01'),
                             'a': bitarray('001'), 'n': bitarray('000')})
        self.assertRaises(ValueError, a.encode, d, 'arvin')

    def test_encode_symbol_not_in_code(self):
        d = {None : bitarray('0'),
             0    : bitarray('10'),
             'A'  : bitarray('11')}
        a = bitarray()
        a.encode(d, ['A', None, 0])
        self.assertEqual(a, bitarray('11010'))
        self.assertRaises(ValueError, a.encode, d, [1, 2])
        self.assertRaises(ValueError, a.encode, d, 'ABCD')

    def test_encode_not_iterable(self):
        d = {'a': bitarray('0'), 'b': bitarray('1')}
        a = bitarray()
        a.encode(d, 'abba')
        self.assertRaises(TypeError, a.encode, d, 42)
        self.assertRaises(TypeError, a.encode, d, 1.3)
        self.assertRaises(TypeError, a.encode, d, None)
        self.assertEqual(a, bitarray('0110'))

    def test_check_codedict_encode(self):
        a = bitarray()
        self.assertRaises(TypeError, a.encode, None, '')
        self.assertRaises(ValueError, a.encode, {}, '')
        self.assertRaises(TypeError, a.encode, {'a': 'b'}, '')
        self.assertRaises(ValueError, a.encode, {'a': bitarray()}, '')
        self.assertEqual(len(a), 0)

    def test_check_codedict_decode(self):
        a = bitarray('101')
        self.assertRaises(TypeError, a.decode, 0)
        self.assertRaises(ValueError, a.decode, {})
        self.assertRaises(TypeError, a.decode, {'a': 42})
        self.assertRaises(ValueError, a.decode, {'a': bitarray()})
        self.assertEqual(a, bitarray('101'))

    def test_check_codedict_iterdecode(self):
        a = bitarray('1100101')
        self.assertRaises(TypeError, a.iterdecode, 0)
        self.assertRaises(ValueError, a.iterdecode, {})
        self.assertRaises(TypeError, a.iterdecode, {'a': []})
        self.assertRaises(ValueError, a.iterdecode, {'a': bitarray()})
        self.assertEqual(a, bitarray('1100101'))

    def test_decode_simple(self):
        d = {'I': bitarray('1'),
             'l': bitarray('01'),
             'a': bitarray('001'),
             'n': bitarray('000')}
        dcopy = dict(d)
        a = bitarray('101001000')
        self.assertEqual(a.decode(d), ['I', 'l', 'a', 'n'])
        self.assertEqual(d, dcopy)
        self.assertEqual(a, bitarray('101001000'))

    def test_iterdecode_simple(self):
        d = {'I': bitarray('1'),
             'l': bitarray('01'),
             'a': bitarray('001'),
             'n': bitarray('000')}
        dcopy = dict(d)
        a = bitarray('101001000')
        self.assertEqual(list(a.iterdecode(d)), ['I', 'l', 'a', 'n'])
        self.assertEqual(d, dcopy)
        self.assertEqual(a, bitarray('101001000'))

    def test_decode_empty(self):
        d = {'a': bitarray('1')}
        a = bitarray()
        self.assertEqual(a.decode(d), [])
        self.assertEqual(d, {'a': bitarray('1')})
        # test decode iterator
        self.assertEqual(list(a.iterdecode(d)), [])
        self.assertEqual(d, {'a': bitarray('1')})
        self.assertEqual(len(a), 0)

    def test_decode_no_term(self):
        d = {'a': bitarray('0'), 'b': bitarray('111')}
        a = bitarray('011')
        self.assertRaises(ValueError, a.decode, d)
        self.assertEqual(a, bitarray('011'))
        self.assertEqual(d, {'a': bitarray('0'), 'b': bitarray('111')})

    def test_decode_buggybitarray(self):
        d = {'a': bitarray('0')}
        a = bitarray('1')
        self.assertRaises(ValueError, a.decode, d)
        self.assertEqual(a, bitarray('1'))
        self.assertEqual(d, {'a': bitarray('0')})

    def test_iterdecode_no_term(self):
        d = {'a': bitarray('0'), 'b': bitarray('111')}
        a = bitarray('011')
        it = a.iterdecode(d)
        if not is_py3k:
            self.assertEqual(it.next(), 'a')
            self.assertRaises(ValueError, it.next)
        self.assertEqual(a, bitarray('011'))
        self.assertEqual(d, {'a': bitarray('0'), 'b': bitarray('111')})

    def test_iterdecode_buggybitarray(self):
        d = {'a': bitarray('0')}
        a = bitarray('1')
        it = a.iterdecode(d)
        if not is_py3k:
            self.assertRaises(ValueError, it.next)
        self.assertEqual(a, bitarray('1'))
        self.assertEqual(d, {'a': bitarray('0')})

    def test_decode_buggybitarray2(self):
        d = {'a': bitarray('00'), 'b': bitarray('01')}
        a = bitarray('1')
        self.assertRaises(ValueError, a.decode, d)
        self.assertEqual(a, bitarray('1'))

    def test_iterdecode_buggybitarray2(self):
        d = {'a': bitarray('00'), 'b': bitarray('01')}
        a = bitarray('1')
        it = a.iterdecode(d)
        if not is_py3k:
            self.assertRaises(ValueError, it.next)
        self.assertEqual(a, bitarray('1'))

    def test_decode_ambiguous_code(self):
        for d in [
            {'a': bitarray('0'), 'b': bitarray('0'), 'c': bitarray('1')},
            {'a': bitarray('01'), 'b': bitarray('01'), 'c': bitarray('1')},
            {'a': bitarray('0'), 'b': bitarray('01')},
            {'a': bitarray('0'), 'b': bitarray('11'), 'c': bitarray('111')},
        ]:
            a = bitarray()
            self.assertRaises(ValueError, a.decode, d)
            self.assertRaises(ValueError, a.iterdecode, d)

    def test_miscitems(self):
        d = {None : bitarray('00'),
             0    : bitarray('110'),
             1    : bitarray('111'),
             ''   : bitarray('010'),
             2    : bitarray('011')}
        a = bitarray()
        a.encode(d, [None, 0, 1, '', 2])
        self.assertEqual(a, bitarray('00110111010011'))
        self.assertEqual(a.decode(d), [None, 0, 1, '', 2])
        # iterator
        it = a.iterdecode(d)
        self.assertEqual(next(it), None)
        self.assertEqual(next(it), 0)
        self.assertEqual(next(it), 1)
        self.assertEqual(next(it), '')
        self.assertEqual(next(it), 2)
        self.assertStopIteration(it)

    def test_real_example(self):
        code = {' ': bitarray('001'),
                '.': bitarray('0101010'),
                'a': bitarray('0110'),
                'b': bitarray('0001100'),
                'c': bitarray('000011'),
                'd': bitarray('01011'),
                'e': bitarray('111'),
                'f': bitarray('010100'),
                'g': bitarray('101000'),
                'h': bitarray('00000'),
                'i': bitarray('1011'),
                'j': bitarray('0111101111'),
                'k': bitarray('00011010'),
                'l': bitarray('01110'),
                'm': bitarray('000111'),
                'n': bitarray('1001'),
                'o': bitarray('1000'),
                'p': bitarray('101001'),
                'q': bitarray('00001001101'),
                'r': bitarray('1101'),
                's': bitarray('1100'),
                't': bitarray('0100'),
                'u': bitarray('000100'),
                'v': bitarray('0111100'),
                'w': bitarray('011111'),
                'x': bitarray('0000100011'),
                'y': bitarray('101010'),
                'z': bitarray('00011011110')}
        a = bitarray()
        message = 'the quick brown fox jumps over the lazy dog.'
        a.encode(code, message)
        self.assertEqual(a, bitarray('01000000011100100001001101000100101100'
          '00110001101000100011001101100001111110010010101001000000010001100'
          '10111101111000100000111101001110000110000111100111110100101000000'
          '0111001011100110000110111101010100010101110001010000101010'))
        self.assertEqual(''.join(a.decode(code)), message)
        self.assertEqual(''.join(a.iterdecode(code)), message)

tests.append(PrefixCodeTests)

# -------------- Buffer Interface (Python 2.7 and above) --------------------

class BufferInterfaceTests(unittest.TestCase):

    def test_read1(self):
        a = bitarray('01000001' '01000010' '01000011', endian='big')
        v = memoryview(a)
        self.assertEqual(len(v), 3)
        self.assertEqual(v[0], 65 if is_py3k else 'A')
        self.assertEqual(v.tobytes(), b'ABC')
        a[13] = 1
        self.assertEqual(v.tobytes(), b'AFC')

    def test_read2(self):
        a = bitarray()
        a.frombytes(os.urandom(100))
        v = memoryview(a)
        self.assertEqual(len(v), 100)
        b = a[34 * 8 : 67 * 8]
        self.assertEqual(v[34:67].tobytes(), b.tobytes())
        self.assertEqual(v.tobytes(), a.tobytes())

    def test_write(self):
        a = bitarray(8000)
        a.setall(0)
        v = memoryview(a)
        self.assertFalse(v.readonly)
        v[500] = 255 if is_py3k else '\xff'
        self.assertEqual(a[3999:4009], bitarray('0111111110'))
        a[4003] = 0
        self.assertEqual(a[3999:4009], bitarray('0111011110'))
        v[301:304] = b'ABC'
        self.assertEqual(a[300 *8 : 305 * 8].tobytes(), b'\x00ABC\x00')

if sys.version_info[:2] >= (2, 7):
    tests.append(BufferInterfaceTests)

# ---------------------------------------------------------------------------

class TestsFrozenbitarray(unittest.TestCase, Util):

    def test_init(self):
        a = frozenbitarray('110')
        self.assertEqual(a, bitarray('110'))
        self.assertEqual(a.to01(), '110')
        for endian in 'big', 'little':
            a = frozenbitarray(0, endian)
            self.assertEqual(a.endian(), endian)

    def test_methods(self):
        # test a few methods which do not raise the TypeError
        a = frozenbitarray('1101100')
        self.assertEqual(a[2], 0)
        self.assertEqual(a[:4].to01(), '1101')
        self.assertEqual(a.count(), 4)
        self.assertEqual(a.index(0), 2)
        b = a.copy()
        self.assertEqual(b, a)
        self.assertEqual(repr(type(b)), "<class 'bitarray.frozenbitarray'>")
        self.assertEqual(len(b), 7)
        self.assertEqual(b.length(), 7)
        self.assertEqual(b.all(), False)
        self.assertEqual(b.any(), True)

    def test_init_bitarray(self):
        for a in self.randombitarrays():
            b = frozenbitarray(a)
            self.assertFalse(b is a)
            self.assertEqual(b, a)
            self.assertEqual(b.endian(), a.endian())
            c = frozenbitarray(b)
            self.assertEqual(c, b)
            self.assertFalse(c is b)
            self.assertEqual(c.endian(), a.endian())
            self.assertEqual(hash(c), hash(b))

    def test_repr(self):
        a = frozenbitarray()
        self.assertEqual(repr(a), "frozenbitarray()")
        self.assertEqual(str(a), "frozenbitarray()")
        a = frozenbitarray('10111')
        self.assertEqual(repr(a), "frozenbitarray('10111')")
        self.assertEqual(str(a), "frozenbitarray('10111')")

    def test_immutable(self):
        a = frozenbitarray('111')
        self.assertRaises(TypeError, a.append, True)
        self.assertRaises(TypeError, a.__setitem__, 0, 0)
        self.assertRaises(TypeError, a.__delitem__, 0)

    def test_dictkey(self):
        a = frozenbitarray('01')
        b = frozenbitarray('1001')
        d = {a: 123, b: 345}
        self.assertEqual(d[frozenbitarray('01')], 123)
        self.assertEqual(d[frozenbitarray(b)], 345)

    def test_dictkey2(self): # taken sllightly modified from issue #74
        a1 = frozenbitarray([True, False])
        a2 = frozenbitarray([False, False])
        dct = {a1: "one", a2: "two"}
        a3 = frozenbitarray([True, False])
        self.assertEqual(a3, a1)
        self.assertEqual(dct[a3], 'one')

    def test_mix(self):
        a = bitarray('110')
        b = frozenbitarray('0011')
        self.assertEqual(a + b, bitarray('1100011'))
        a.extend(b)
        self.assertEqual(a, bitarray('1100011'))

tests.append(TestsFrozenbitarray)

# ---------------------------------------------------------------------------

def run(verbosity=1, repeat=1):
    import bitarray.test_util as btu
    tests.extend(btu.tests)

    print('bitarray is installed in: %s' % os.path.dirname(__file__))
    print('bitarray version: %s' % __version__)
    print('Python version: %s' % sys.version)

    suite = unittest.TestSuite()
    for cls in tests:
        for _ in range(repeat):
            suite.addTest(unittest.makeSuite(cls))

    runner = unittest.TextTestRunner(verbosity=verbosity)
    return runner.run(suite)

if __name__ == '__main__':
    run()


#Importing required libraries
import numpy as np
from matplotlib import pyplot as plt
import firfilter
import hpbsfilter

#Function that plots the time domain waveform of the signal of interest
def PlotWaveform(title, ycords):
    fs=1000
    plt.figure(figsize=(13.33,7.5))
    plt.title(title)
    plt.xlabel('Time [s]')
    plt.ylabel('Amplitude [mV]')
    time=np.linspace(0,len(ycords)/fs,len(ycords))
    plt.plot(time,ycords)
    plt.show()

#Function that plots the step graph for of the Momentary Heart Rate changes along time
def PlotWaveformStep(title, ycords):
    fs=1000
    plt.figure(figsize=(13.33,7.5))
    plt.title(title)
    plt.xlabel('Time [s]')
    plt.ylabel('Amplitude [mV]')
    time=np.linspace(0,len(ycords)/fs,len(ycords))
    plt.step(time,ycords)
    plt.show()

#Function that creates the ecg template for the matched FIR filter
def GenerateECGTemplate(samples, samplingFrequency):
    filteredSamples = []
    finalSamples = []
    # Create the filter coefficients to remove the 50Hz noise and baseband wander
    bandstopfir = hpbsfilter.fir_coeff()
    firCoefficients = bandstopfir.bandstopDesign(1000, 45, 55)

    # Initialize FIR
    fir = firfilter.FIR_filter(firCoefficients)

    # Generating the tempelate from only the first 4000 samples to prevent long wait time
    for x in range(4000):
        filteredSamples.append(fir.dofilter(samples[x]))

    highpassfir = hpbsfilter.fir_coeff()
    firCoefficients = highpassfir.highpassDesign(1000, 0.5)

    # Initialize FIR
    fir = firfilter.FIR_filter(firCoefficients)

    for x in range(4000):
        finalSamples.append(fir.dofilter(filteredSamples[x]))

    # Plot Filtered ECG waveform
    PlotWaveform("Filtered ECG", finalSamples)

    # Get one Period of ECG to form the template
    ecgSlice = finalSamples[2800:3600] # [760:870]
    # Flip to create the time reversed tempelate for the filter coefficients
    template = np.flip(ecgSlice)

    # Plotting both the ECG slices
    hpbsfilter.ecgNormPlot('ECG Slice', ecgSlice)
    hpbsfilter.ecgNormPlot('ECG Template', template)

    # Reset FIR filters ringbuffer and offset
    fir.ResetFilter()

    # Return the filter object and template coefficients
    return fir, template

#Main body of the program
if __name__ == "__main__":
    #Load the ecg data
    ecg_data = np.loadtxt("ECG_1000Hz_13.dat")
    fs = 1000
    nofsamples = len(ecg_data)
    fir, template = GenerateECGTemplate(ecg_data, 1000)
    filteredSmaples = np.zeros(nofsamples)
    squaredSamples = np.zeros(nofsamples)

    # Peak Detector with Heart rate tracking
    #Define the peak detector variables
    peakIndex = []
    # Momentary heart rate array
    m = []
    lastPeak = 0
    nPeaks = 0

    #Heuristics variable to prevent bogus detection
    pulseSettlingSamplecCnt = 37
    peakFlag = False

    #Set the threshold to detect peaks based on the amplitude of the delta plulses
    amplitudeThreshold = 20

    # Initialize matched filter object
    Templatefir = firfilter.FIR_filter(template)

    # Simulate causal system by filtering signal sample by sample
    # Filter the baseband wander and 50hH
    filteredSmaples = hpbsfilter.finalfilteredECGData()
    for x in range(nofsamples):

        # Apply the matched filter to generate the peaks
        squaredSamples[x] = Templatefir.dofilter(filteredSmaples[x])
        # Square the output samples to pronounce the amplitude and suppress the noise to get the delta pulses
        squaredSamples[x] = squaredSamples[x] * squaredSamples[x]

        # Wait for the filter to settle
        if(x > 2000):

            # Detect the peaks
            # If sample amplitude is above threshold, the peak hasn't been detected yet with some heuristics to prevent bogus detections
            if( squaredSamples[x] > amplitudeThreshold and peakFlag == False and (x - lastPeak ) >= pulseSettlingSamplecCnt ):

                peakFlag = True

            # If the amplitude exceeded the threshold and previous sample was higher that must've been a peak
            if( squaredSamples[x - 1] > squaredSamples[x] and peakFlag == True ):

                peakFlag = False

                # Holding the index as last peak index
                lastPeak = (x - 1)
                #Append the index of that sample to list
                peakIndex.append( lastPeak )
                # Increment peak counter
                nPeaks += 1

                # Calculating the momentary heart rate in BPM
                #Minimum of 2 peaks are required to generate the number of samples between them
                if ( nPeaks >= 2):
                    # Calculating the number of samples between peaks
                    t = lastPeak - peakIndex[ nPeaks - 2]
                    # Calculating the momentary rate in BPM
                    m.append( (fs/t)*60 )

    # Plotting the original time domain response of the ECG
    hpbsfilter.ecgNormPlot('Time domain signal of the original ECG', ecg_data)
    # Plotting the filtered time domain response of the ECG
    hpbsfilter.ecgNormPlot('Time domain signal of the filtered ECG', filteredSmaples)
    # Plotting the filtered frequency response of the ECG
    hpbsfilter.ecgFreqPlot('Frequency responce of the filtered ECG',filteredSmaples,fs)
    #Plotting the delta pulses returned by the matched filter
    PlotWaveform("Delta Pulses obtained after matched filtering", squaredSamples)
    #Plotting the momentary heart rate as a step graph
    PlotWaveformStep("Momenrary Heart Rate", m)
    #Print the number of heart beats detected
    print("Number of beats detected: " + str(nPeaks) )
    #Print the average BMP detected from the delta pulses
    print("Average Momentary Heart Rate (in BPM): %.1f" % (sum(m)/len(m)))


import os
from flask import Flask, render_template, session, redirect, url_for # tools that will make it easier to build on things
from flask_sqlalchemy import SQLAlchemy # handles database stuff for us - need to pip install flask_sqlalchemy in your virtual env, environment, etc to use this and run this
import requests, json
from bs4 import BeautifulSoup
from advanced_expiry_caching import Cache
# import numpy as np
import pandas as pd

######
# Constants
START_URL = "https://www.nps.gov/index.htm"
FILENAME = "nps_cache.json"
PROGRAM_CACHE = Cache(FILENAME)

# assuming constants exist as such
# use a tool to build functionality here
def access_page_data(url):
    data = PROGRAM_CACHE.get(url)
    if not data:
        data = requests.get(url).text
        PROGRAM_CACHE.set(url, data) # default here with the Cache.set tool is that it will expire in 7 days, which is probs fine, but something to explore
    return data

###### Scraping the data from the website

main_page = access_page_data(START_URL)
main_soup = BeautifulSoup(main_page, features="html.parser")
# print(main_soup.prettify())

list_of_topics = main_soup.find('ul', class_='dropdown-menu SearchBar-keywordSearch')
# all_links = list_of_topics.find_all('a')
# print(all_links)

states_urls = []
for link in list_of_topics.find_all('a'):
    # print(link.get('href'))
    states_urls.append("{}{}".format("https://www.nps.gov",link.get('href')))
# print(states_urls)

nps_dic = {} #dictionary of lists

nps_dic['Type'] = []
nps_dic['Name'] = []
nps_dic['Location'] = []
nps_dic['State'] = []
nps_dic['Description'] = []

for url in states_urls:
    state_page = access_page_data(url)
    state_soup = BeautifulSoup(state_page, features="html.parser")
    # print(state_soup.prettify())

    for each_item in state_soup.find("h1", class_="page-title"):
        sitestate = each_item
        # print(sitestate) <--- Check whether it prints out the list of states

    for each_item in state_soup.find("ul", id="list_parks").find_all('li', class_="clearfix"):
        # print('===============')
        # print(each_item)
        # print('===============')

        sitetype = each_item.find('h2')
        sitename = each_item.find('h3').find('a')
        sitelocation = each_item.find('h4')
        sitedescription = each_item.find('p')

        nps_dic['State'].append(sitestate)

        if (sitetype) and (sitetype.text != ""):
            nps_dic['Type'].append(sitetype.text)
        else:
            nps_dic['Type'].append("None")

        if (sitename) and (sitename.text != ""):
            nps_dic['Name'].append(sitename.text)
        else:
            nps_dic['Name'].append("None")

        if (sitelocation) and (sitelocation.text != ""):
            nps_dic['Location'].append(sitelocation.text)
        else:
            nps_dic['Location'].append("None")

        if (sitedescription) and (sitedescription.text != ""):
            nps_dic['Description'].append(sitedescription.text.strip())
        else:
            nps_dic['Description'].append("None")

        # print(nps_dic)

##### Save the scraped data into CSV file.
nps_data = pd.DataFrame.from_dict(nps_dic)
nps_data.to_csv('nps.csv')
# for each in nps_dic.keys():
#     print(len(nps_dic[each]))

###### Now with 'nps.csv' file, I am going to make db file using sqlalchemy.
import sqlite3
import csv
from sqlalchemy import Column, ForeignKey, Integer, String, Text, Float, REAL

sqlite_file = 'nps.db'

# Connecting to the database file
conn = sqlite3.connect(sqlite_file)
c = conn.cursor() # Object that allows us to use Python to act on the database

# Often easier to start with the "simplest" table and go on from there
c.execute('''DROP TABLE IF EXISTS 'State';''')
c.execute('''CREATE TABLE State (StateId INTEGER PRIMARY KEY AUTOINCREMENT, State TEXT)''')
state_lst = []

with open('nps.csv') as csvfile:
    readCSV = csv.reader(csvfile, delimiter=',')
    for row in readCSV:
        if not row[4] in state_lst:
            state_lst.append(row[4])
        state_lst_itself = state_lst[1:]

# print(state_lst_itself)
c.executemany('INSERT INTO State (State) VALUES(?)', zip(state_lst_itself))

c.execute('''DROP TABLE IF EXISTS 'Park';''')
c.execute('''CREATE TABLE Park (ParkId INTEGER PRIMARY KEY AUTOINCREMENT, ParkName TEXT, ParkType TEXT, ParkLocation TEXT, StateId INTEGER, Description TEXT, CONSTRAINT fk_States FOREIGN KEY (StateId) REFERENCES State(StateId))''')
# Three quotations make it possible for this to become a multi-line string, which can make it easier to organize and read
each_lst = []
with open('nps.csv') as csvfile:
    readCSV = csv.reader(csvfile, delimiter=',')
    readCSV.__next__()

    for row in readCSV:
        state_name = (row[4],)
        # print(type(state_name))
        c.execute("SELECT StateId FROM State WHERE State.State = ?" , state_name)
        fetch_state_name = c.fetchone()

        state_id = int(fetch_state_name[0])
        # print(fetch_state_name)
        each_lst.append((row[2], row[1], row[3], state_id, row[5]))

# print(each_lst)
c.executemany('INSERT INTO Park(ParkName, ParkType, ParkLocation, StateId, Description) VALUES (?,?,?,?,?)', each_lst)

conn.commit()
conn.close()

######
# Application configurations
from flask import Flask, render_template, session, redirect, url_for, g
app = Flask(__name__)

DATABASE = 'nps.db'

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
    return db

##### Set up Controllers (route functions) #####

## Main route
@app.route('/')
def index():

    cur = get_db().cursor()
    cur.execute("select * from Park")
    rows = cur.fetchall()

    park_num = len(rows)

    return render_template('index.html', park_num = park_num)

@app.route('/all_states')
def all_states():

    cur = get_db().cursor()
    cur.execute("select * from State")
    rows = cur.fetchall()

    state_list = []
    for each in rows:
        state_name = each[1]
        state_list.append(state_name)

    return render_template('all_states.html', state_name = state_name, state_list = state_list)

@app.route('/state/<state>')
def each_state(state):

    cur = get_db().cursor()
    cur.execute("select State, ParkName, ParkType, ParkLocation, Description from Park natural inner join State")
    parks = cur.fetchall() # It will be rows of pakrs in the certain state. It could be one or multiple locations.

    # print(parks)
    park_dic = {}
    park_dic["park_lst"]=[]

    for each_park in parks:
        if each_park[0] == state:
            park_dic["park_lst"].append(each_park[1:])

    return render_template('each_state.html', state_name=state, park_lst=park_dic["park_lst"])

if __name__ == '__main__':
   app.run()


import numpy as np
import csv
import os
import cv2
import matplotlib.pyplot as plt
from xml.etree import ElementTree as ET
import argparse

parser = argparse.ArgumentParser(description='compare mediapipe and kinect skeleton data', epilog = 'Enjoy the program! :)')

parser.add_argument('--inputfile', default =r'/datasets_nas/elma1294/example_tape/dominikw_front_0/e4sm_tape-2021-08-18_14-07-44.211275_skeletons.shuttleFront.csv',
                     help = 'The address of the input csv file')
parser.add_argument('--sample_image', default = r'/datasets_nas/elma1294/example_tape/dominikw_front_0/e4sm_tape-2021-08-18_14-07-44.211275_png.shuttleFront/shuttleFront_Kinect_ColorImage1629288474191866000.jpg',
                   help = 'sample image to get the width and height of the image')
parser.add_argument('--output_directory', default=r'/datasets_nas/elma1294/results' , help = 'The address of the results')
arguments = parser.parse_args()

path = arguments.inputfile
file_path = arguments.sample_image
output_directory = arguments.output_directory

output_kineckt = os.path.join(output_directory, 'results3Dto2Dnew.csv')

def _parse_camera_parameter(camera_name: str):

    assert camera_name in ['shuttleFront', 'shuttleSide', 'spike']

    # parse serialized kinect azure calibration
    root = ET.parse(f'intrinsics/{camera_name}.xml').getroot()
    root = root.find('KinectAzureCalibration')

    # get color intrinsics as cx, cy, fx, fy
    color_params = root.find('color_camera_calibration')

    # intrsinics
    intrinsics = color_params.find('intrinsics').find('parameters').findall('item')

    cx = float(intrinsics[0].text)
    cy = float(intrinsics[1].text)
    fx = float(intrinsics[2].text)
    fy = float(intrinsics[3].text)

    # get transformation from depth frame to color frame
    # the kinect sdk defines the local transformation tree as
    # mount frame -> depth_frame -> color_frame
    # so we can just parse the extrinsics from color camera which represents
    # the transformation depth_frame -> color_frame
    extrinsics = color_params.find('extrinsics')

    # NOTE: rotation matrix is serialized as simple vector
    rotation = extrinsics.find('rotation').findall('item')
    translation = extrinsics.find('translation').findall('item')

    rotation_vec = np.zeros(9)
    for i, el in enumerate(rotation):
        rotation_vec[i] = el.text

    translation_vec = np.zeros(3)
    for i, el in enumerate(translation):
        translation_vec[i] = el.text

    # translation is given in mm
    # as we work in m we convert
    translation_vec *= 0.001

    transform = np.eye(4)
    transform[:3, :3] = rotation_vec.reshape(3, 3)
    transform[:3, 3] = translation_vec

    return [cx, cy, fx, fy], transform

def convert_3d_to_2d_position(x,y,z, transform, camera_parameter, width, height):
    ''' with Intrinsic Parameter i defined Camera Matrix to get the 2D Position'''

    xc = float(x)
    yc = float(y)
    zc = float(z)
    xc, yc, zc = np.dot(transform, np.array([xc, yc, zc, 1]))[:3]

    #shutlefront
    cx, cy, fx, fy = camera_parameter

    if len(x) < 1 or len(y) < 1 or len(z) <1:
        return 0,0
    k = np.array([[fx,0,cx],[0,fy,cy],[0,0,1]])
    one = np.array([[1,0,0,0],[0,1,0,0],[0,0,1,0]])
    camera_matrix = np.array([[xc],[yc],[zc],[1]])
    m1 = np.dot(k,one)
    output_matrix = np.dot(m1,camera_matrix)
    u_array = (output_matrix[0]/output_matrix[2])/width
    v_array= (output_matrix[1]/output_matrix[2])/height
    u = u_array[0].astype(float)
    v = v_array[0].astype(float)
    return u,v

def _plot_sample(joint_dict, img):
    joints = np.zeros(((len(joint_dict) -1) // 2, 2))
    for ei, joint in enumerate(list(joint_dict.values())[1:]):
        joints[ei // 2, ei % 2] = joint
    plt.imshow(img)
    joints *= img.shape[:2][::-1]
    plt.scatter(joints[:, 0], joints[:, 1], s=10, c='r')
    plt.show()
    # plt.savefig('test.png')

list_of_results = []
camera_params, transform = _parse_camera_parameter('shuttleFront')
img = cv2.imread(file_path, cv2.IMREAD_COLOR)
width = img.shape[1]
height = img.shape[0]

with open(path) as f:
    ''' read the csv file and convert the 3D Position to 2D Position and save it in a new csv file'''
    rows = [{k: v for k, v in row.items()} for row in csv.DictReader(f, skipinitialspace=True)]
    for row in rows:
        mDict = {}
        mDict['timestamp'] = row['timestamp']
        for x_header in row.keys():
            if '.x' in x_header:
                y_header = x_header.replace('.x','.y')
                z_header = x_header.replace('.x','.z')
                x_value = row[x_header]
                y_value = row[y_header]
                z_value = row[z_header]
                u,v= convert_3d_to_2d_position(x_value,y_value,z_value, transform, camera_params, width, height)
                mDict[x_header] = u
                mDict[y_header] = v
        list_of_results.append(mDict)

_plot_sample(mDict, img)

with open(output_kineckt, 'w', encoding='UTF8', newline='') as f2:
    writer = csv.DictWriter(f2, mDict.keys())
    writer.writeheader()
    writer.writerows(list_of_results)


from aip import AipOcr
import configparser

class BaiDuAPI:
    '''调用百度云的API来实现数字的识别
    filePath:
    --------
    是工单信息的ini配置文件全路径
    '''

    def __init__(self, filePath):
        target = configparser.ConfigParser()  # 初始化ConfigParser类
        # r'D:\我的坚果云\Python\Python课件\24点\password.ini'
        target.read(filePath)  # 读取ini文件
        # 读取工单信息
        # target.get第一个参数是section，第二个是键名，返回对应值
        app_id = target.get('工单密码', 'APP_ID')
        api_key = target.get('工单密码', 'API_KEY')
        secret_key = target.get('工单密码', 'SECRET_KEY')

        """ 你的 APPID AK SK """
        APP_ID = app_id
        API_KEY = api_key
        SECRET_KEY = secret_key

        self.client = AipOcr(APP_ID, API_KEY, SECRET_KEY)

    def picture2Text(self, filePath):
        image = self.get_file_content(filePath)
        """ 调用通用文字识别, 图片参数为本地图片 """
        texts = self.client.basicGeneral(image)
        allTexts = ''
        for words in texts['words_result']:
            allTexts = allTexts + ''.join(words.get('words',''))

        return allTexts

    # """ 读取图片 """

    # @staticmethod
    # def get_file_content(filePath):
    #     with open(filePath, 'rb') as fp:
    #         return fp.read()

    @classmethod
    def get_file_content(cls, filePath):
        with open(filePath, 'rb') as fp:
            return fp.read()

if __name__ == '__main__':

    baiduapi = BaiDuAPI(
        r'D:\Windows 7 Documents\Documents\PythonCode\24\password.ini')
    allTexts = baiduapi.picture2Text(
        r'D:\Windows 7 Documents\Documents\PythonCode\24\Snipaste_2018-05-19_22-42-33.png')
    print(allTexts)


from wordcloud import WordCloud
from PIL import Image

def make_ngram_wordcloud(count, target, filename):
    wordcloud = WordCloud(
    font_path = '../d2coding.ttf',
        width = 800,
        height = 800,
        background_color = "white"
    )
    gen = wordcloud.generate_from_frequencies(count)
    array = gen.to_array()
    save_as_image(array, target, filename)

def save_as_image(data, target, filename):
    im = Image.fromarray(data)
    im.save("./" + target + "/" + filename + ".jpg")


import sys, math
from collections import defaultdict

def countPerms(nxt):
    prev = nxt.pop(0)
    i = 0
    print("r")
    ans = 1
    while True:
        if i >= len(nxt):
            return 1

        if nxt[i] <= prev + 3:
            ans += 1
        i += 1
    return ans * countPerms(nxt)

with open(sys.argv[1]) as fil:
    adapters = sorted([0]+[int(i.strip()) for i in fil.readlines()])

adapters.append(max(adapters) + 3)
voltages = defaultdict(int)

print(adapters)
for i in range(len(adapters) - 1):
    voltages[adapters[i+1]-adapters[i]] += 1

print(voltages)
print("Part 1:", voltages[3] * voltages[1])
print(countPerms(adapters.copy()))