r"""QR Code Generator for Python
Copyright (c) 2012 Kazuhiko Arase
URL: http://www.d-project.com/
Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
The word 'QR Code' is registered trademark of
DENSO WAVE INCORPORATED
http://www.denso-wave.com/qrcode/faqpatent-e.html
Modified by Airshare Developers:
  - added `printQr()` to `QRCode`
"""


import colorama
from termcolor import colored, cprint


colorama.init()


class QRCode:

    PAD0 = 0xEC
    PAD1 = 0x11

    def __init__(self):
        self.typeNumber = 1
        self.errorCorrectLevel = ErrorCorrectLevel.H
        self.qrDataList = []
        self.modules = []
        self.moduleCount = 0

    def getTypeNumber(self):
        return self.typeNumber

    def setTypeNumber(self, typeNumber):
        self.typeNumber = typeNumber

    def getErrorCorrectLevel(self):
        return self.errorCorrectLevel

    def setErrorCorrectLevel(self, errorCorrectLevel):
        self.errorCorrectLevel = errorCorrectLevel

    def clearData(self):
        self.qrDataList = []

    def addData(self, data):
        self.qrDataList.append(QR8BitByte(data))

    def getDataCount(self):
        return len(self.qrDataList)

    def getData(self, index):
        return self.qrDataList[index]

    def isDark(self, row, col):
        return (self.modules[row][col] if self.modules[row][col] is not None
                else False)

    def getModuleCount(self):
        return self.moduleCount

    def printQr(self):
        WHITE = colored("  ", "white", "on_white")
        BLACK = "  "
        size = self.getModuleCount() + 2
        print()
        for row in range(size):
            for col in range(size):
                if row == 0 or col == 0 or col == size - 1 or row == size - 1:
                    cprint(WHITE, end="")
                else:
                    color = BLACK if self.isDark(row - 1, col - 1) else WHITE
                    cprint(color, end="")
            print()
        print()

    def make(self):
        self._make(False, self._getBestMaskPattern())

    def _getBestMaskPattern(self):
        minLostPoint = 0
        pattern = 0
        for i in range(8):
            self._make(True, i)
            lostPoint = QRUtil.getLostPoint(self)
            if i == 0 or minLostPoint > lostPoint:
                minLostPoint = lostPoint
                pattern = i
        return pattern

    def _make(self, test, maskPattern):
        self.moduleCount = self.typeNumber * 4 + 17
        self.modules = [[None] * self.moduleCount
                        for i in range(self.moduleCount)]

        self._setupPositionProbePattern(0, 0)
        self._setupPositionProbePattern(self.moduleCount - 7, 0)
        self._setupPositionProbePattern(0, self.moduleCount - 7)

        self._setupPositionAdjustPattern()
        self._setupTimingPattern()

        self._setupTypeInfo(test, maskPattern)

        if self.typeNumber >= 7:
            self._setupTypeNumber(test)

        data = QRCode._createData(
            self.typeNumber,
            self.errorCorrectLevel,
            self.qrDataList)

        self._mapData(data, maskPattern)

    def _mapData(self, data, maskPattern):
        rows = list(range(self.moduleCount))
        cols = [col - 1 if col <= 6 else col
                for col in range(self.moduleCount - 1, 0, -2)]
        maskFunc = QRUtil.getMaskFunction(maskPattern)

        byteIndex = 0
        bitIndex = 7

        for col in cols:
            rows.reverse()
            for row in rows:
                for c in range(2):
                    if self.modules[row][col - c] is None:

                        dark = False
                        if byteIndex < len(data):
                            dark = ((data[byteIndex] >> bitIndex) & 1) == 1
                        if maskFunc(row, col - c):
                            dark = not dark
                        self.modules[row][col - c] = dark

                        bitIndex -= 1
                        if bitIndex == -1:
                            byteIndex += 1
                            bitIndex = 7

    def _setupPositionAdjustPattern(self):
        pos = QRUtil.getPatternPosition(self.typeNumber)
        for row in pos:
            for col in pos:
                if self.modules[row][col] is not None:
                    continue
                for r in range(-2, 3):
                    for c in range(-2, 3):
                        self.modules[row + r][col + c] = (
                            r == -2 or r == 2 or c == -2 or c == 2
                            or (r == 0 and c == 0))

    def _setupPositionProbePattern(self, row, col):
        for r in range(-1, 8):
            for c in range(-1, 8):
                if (row + r <= -1 or self.moduleCount <= row + r
                        or col + c <= -1 or self.moduleCount <= col + c):
                    continue
                self.modules[row + r][col + c] = (
                    (0 <= r and r <= 6 and (c == 0 or c == 6))
                    or (0 <= c and c <= 6 and (r == 0 or r == 6))
                    or (2 <= r and r <= 4 and 2 <= c and c <= 4))

    def _setupTimingPattern(self):
        for r in range(8, self.moduleCount - 8):
            if self.modules[r][6] is not None:
                continue
            self.modules[r][6] = r % 2 == 0
        for c in range(8, self.moduleCount - 8):
            if self.modules[6][c] is not None:
                continue
            self.modules[6][c] = c % 2 == 0

    def _setupTypeNumber(self, test):
        bits = QRUtil.getBCHTypeNumber(self.typeNumber)
        for i in range(18):
            self.modules[i // 3][i % 3 + self.moduleCount - 8 - 3] = (
                not test and ((bits >> i) & 1) == 1)
        for i in range(18):
            self.modules[i % 3 + self.moduleCount - 8 - 3][i // 3] = (
                not test and ((bits >> i) & 1) == 1)

    def _setupTypeInfo(self, test, maskPattern):
        data = (self.errorCorrectLevel << 3) | maskPattern
        bits = QRUtil.getBCHTypeInfo(data)

        # vertical
        for i in range(15):
            mod = not test and ((bits >> i) & 1) == 1
            if i < 6:
                self.modules[i][8] = mod
            elif i < 8:
                self.modules[i + 1][8] = mod
            else:
                self.modules[self.moduleCount - 15 + i][8] = mod

        # horizontal
        for i in range(15):
            mod = not test and ((bits >> i) & 1) == 1
            if i < 8:
                self.modules[8][self.moduleCount - i - 1] = mod
            elif i < 9:
                self.modules[8][15 - i - 1 + 1] = mod
            else:
                self.modules[8][15 - i - 1] = mod

        # fixed
        self.modules[self.moduleCount - 8][8] = not test

    @staticmethod
    def _createData(typeNumber, errorCorrectLevel, dataArray):
        rsBlocks = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel)

        buffer = BitBuffer()

        for data in dataArray:
            buffer.put(data.getMode(), 4)
            buffer.put(data.getLength(), data.getLengthInBits(typeNumber))
            data.write(buffer)

        totalDataCount = sum(rsBlock.getDataCount()
                             for rsBlock in rsBlocks)

        if buffer.getLengthInBits() > totalDataCount * 8:
            raise Exception('code length overflow. (%s>%s)' %
                            (buffer.getLengthInBits(), totalDataCount * 8))

        # end code
        if buffer.getLengthInBits() + 4 <= totalDataCount * 8:
            buffer.put(0, 4)

        # padding
        while buffer.getLengthInBits() % 8 != 0:
            buffer.put(False)

        # padding
        while True:
            if buffer.getLengthInBits() >= totalDataCount * 8:
                break
            buffer.put(QRCode.PAD0, 8)
            if buffer.getLengthInBits() >= totalDataCount * 8:
                break
            buffer.put(QRCode.PAD1, 8)

        return QRCode._createBytes(buffer, rsBlocks)

    @staticmethod
    def _createBytes(buffer, rsBlocks):
        offset = 0

        maxDcCount = 0
        maxEcCount = 0

        dcdata = [None] * len(rsBlocks)
        ecdata = [None] * len(rsBlocks)

        for r in range(len(rsBlocks)):

            dcCount = rsBlocks[r].getDataCount()
            ecCount = rsBlocks[r].getTotalCount() - dcCount

            maxDcCount = max(maxDcCount, dcCount)
            maxEcCount = max(maxEcCount, ecCount)

            dcdata[r] = [0] * dcCount
            for i in range(len(dcdata[r])):
                dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]
            offset += dcCount

            rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount)
            rawPoly = Polynomial(dcdata[r], rsPoly.getLength() - 1)

            modPoly = rawPoly.mod(rsPoly)
            ecdata[r] = [0] * (rsPoly.getLength() - 1)
            for i in range(len(ecdata[r])):
                modIndex = i + modPoly.getLength() - len(ecdata[r])
                ecdata[r][i] = modPoly.get(modIndex) if modIndex >= 0 else 0

        totalCodeCount = sum(rsBlock.getTotalCount()
                             for rsBlock in rsBlocks)

        data = [0] * totalCodeCount

        index = 0

        for i in range(maxDcCount):
            for r in range(len(rsBlocks)):
                if i < len(dcdata[r]):
                    data[index] = dcdata[r][i]
                    index += 1

        for i in range(maxEcCount):
            for r in range(len(rsBlocks)):
                if i < len(ecdata[r]):
                    data[index] = ecdata[r][i]
                    index += 1

        return data

    @staticmethod
    def getMinimumQRCode(data, errorCorrectLevel):
        mode = Mode.MODE_8BIT_BYTE  # fixed to 8bit byte
        qr = QRCode()
        qr.setErrorCorrectLevel(errorCorrectLevel)
        qr.addData(data)
        length = qr.getData(0).getLength()
        for typeNumber in range(1, 11):
            if length <= QRUtil.getMaxLength(
                    typeNumber, mode, errorCorrectLevel):
                qr.setTypeNumber(typeNumber)
                break
        qr.make()
        return qr


class Mode:
    MODE_NUMBER = 1 << 0
    MODE_ALPHA_NUM = 1 << 1
    MODE_8BIT_BYTE = 1 << 2
    MODE_KANJI = 1 << 3


class ErrorCorrectLevel:
    L = 1  # 7%
    M = 0  # 15%
    Q = 3  # 25%
    H = 2  # 30%


class MaskPattern:
    PATTERN000 = 0
    PATTERN001 = 1
    PATTERN010 = 2
    PATTERN011 = 3
    PATTERN100 = 4
    PATTERN101 = 5
    PATTERN110 = 6
    PATTERN111 = 7


class QRUtil:

    @staticmethod
    def getPatternPosition(typeNumber):
        return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]

    PATTERN_POSITION_TABLE = [
        [],
        [6, 18],
        [6, 22],
        [6, 26],
        [6, 30],
        [6, 34],
        [6, 22, 38],
        [6, 24, 42],
        [6, 26, 46],
        [6, 28, 50],
        [6, 30, 54],
        [6, 32, 58],
        [6, 34, 62],
        [6, 26, 46, 66],
        [6, 26, 48, 70],
        [6, 26, 50, 74],
        [6, 30, 54, 78],
        [6, 30, 56, 82],
        [6, 30, 58, 86],
        [6, 34, 62, 90],
        [6, 28, 50, 72, 94],
        [6, 26, 50, 74, 98],
        [6, 30, 54, 78, 102],
        [6, 28, 54, 80, 106],
        [6, 32, 58, 84, 110],
        [6, 30, 58, 86, 114],
        [6, 34, 62, 90, 118],
        [6, 26, 50, 74, 98, 122],
        [6, 30, 54, 78, 102, 126],
        [6, 26, 52, 78, 104, 130],
        [6, 30, 56, 82, 108, 134],
        [6, 34, 60, 86, 112, 138],
        [6, 30, 58, 86, 114, 142],
        [6, 34, 62, 90, 118, 146],
        [6, 30, 54, 78, 102, 126, 150],
        [6, 24, 50, 76, 102, 128, 154],
        [6, 28, 54, 80, 106, 132, 158],
        [6, 32, 58, 84, 110, 136, 162],
        [6, 26, 54, 82, 110, 138, 166],
        [6, 30, 58, 86, 114, 142, 170]
    ]

    MAX_LENGTH = [
        [[41,  25,  17,  10],  [34,  20,  14,  8],   [
            27,  16,  11,  7],  [17,  10,  7,   4]],
        [[77,  47,  32,  20],  [63,  38,  26,  16],
            [48,  29,  20,  12], [34,  20,  14,  8]],
        [[127, 77,  53,  32],  [101, 61,  42,  26],  [
            77,  47,  32,  20], [58,  35,  24,  15]],
        [[187, 114, 78,  48],  [149, 90,  62,  38],  [
            111, 67,  46,  28], [82,  50,  34,  21]],
        [[255, 154, 106, 65],  [202, 122, 84,  52],  [
            144, 87,  60,  37], [106, 64,  44,  27]],
        [[322, 195, 134, 82],  [255, 154, 106, 65],  [
            178, 108, 74,  45], [139, 84,  58,  36]],
        [[370, 224, 154, 95],  [293, 178, 122, 75],  [
            207, 125, 86,  53], [154, 93,  64,  39]],
        [[461, 279, 192, 118], [365, 221, 152, 93],  [
            259, 157, 108, 66], [202, 122, 84,  52]],
        [[552, 335, 230, 141], [432, 262, 180, 111], [
            312, 189, 130, 80], [235, 143, 98,  60]],
        [[652, 395, 271, 167], [513, 311, 213, 131],
            [364, 221, 151, 93], [288, 174, 119, 74]]
    ]

    @staticmethod
    def getMaxLength(typeNumber, mode, errorCorrectLevel):
        t = typeNumber - 1
        e = {
            ErrorCorrectLevel.L: 0,
            ErrorCorrectLevel.M: 1,
            ErrorCorrectLevel.Q: 2,
            ErrorCorrectLevel.H: 3
        }[errorCorrectLevel]
        m = {
            Mode.MODE_NUMBER: 0,
            Mode.MODE_ALPHA_NUM: 1,
            Mode.MODE_8BIT_BYTE: 2,
            Mode.MODE_KANJI: 3
        }[mode]
        return QRUtil.MAX_LENGTH[t][e][m]

    @staticmethod
    def getErrorCorrectPolynomial(errorCorrectLength):
        a = Polynomial([1])
        for i in range(errorCorrectLength):
            a = a.multiply(Polynomial([1, QRMath.gexp(i)]))
        return a

    @staticmethod
    def getMaskFunction(maskPattern):
        return {
            MaskPattern.PATTERN000:
                lambda i, j: (i + j) % 2 == 0,
            MaskPattern.PATTERN001:
                lambda i, j: i % 2 == 0,
            MaskPattern.PATTERN010:
                lambda i, j: j % 3 == 0,
            MaskPattern.PATTERN011:
                lambda i, j: (i + j) % 3 == 0,
            MaskPattern.PATTERN100:
                lambda i, j: (i // 2 + j // 3) % 2 == 0,
            MaskPattern.PATTERN101:
                lambda i, j: (i * j) % 2 + (i * j) % 3 == 0,
            MaskPattern.PATTERN110:
                lambda i, j: ((i * j) % 2 + (i * j) % 3) % 2 == 0,
            MaskPattern.PATTERN111:
                lambda i, j: ((i * j) % 3 + (i + j) % 2) % 2 == 0
        }[maskPattern]

    @staticmethod
    def getLostPoint(qrcode):
        moduleCount = qrcode.getModuleCount()
        lostPoint = 0

        # LEVEL1
        for row in range(moduleCount):
            for col in range(moduleCount):
                sameCount = 0
                dark = qrcode.isDark(row, col)
                for r in range(-1, 2):
                    if row + r < 0 or moduleCount <= row + r:
                        continue
                    for c in range(-1, 2):
                        if col + c < 0 or moduleCount <= col + c:
                            continue
                        if r == 0 and c == 0:
                            continue
                        if dark == qrcode.isDark(row + r, col + c):
                            sameCount += 1
                if sameCount > 5:
                    lostPoint += (3 + sameCount - 5)

        # LEVEL2
        for row in range(moduleCount - 1):
            for col in range(moduleCount - 1):
                count = 0
                if qrcode.isDark(row, col):
                    count += 1
                if qrcode.isDark(row + 1, col):
                    count += 1
                if qrcode.isDark(row, col + 1):
                    count += 1
                if qrcode.isDark(row + 1, col + 1):
                    count += 1
                if count == 0 or count == 4:
                    lostPoint += 3

        # LEVEL3
        for row in range(moduleCount):
            for col in range(moduleCount - 6):
                if (qrcode.isDark(row, col)
                        and not qrcode.isDark(row, col + 1)
                        and qrcode.isDark(row, col + 2)
                        and qrcode.isDark(row, col + 3)
                        and qrcode.isDark(row, col + 4)
                        and not qrcode.isDark(row, col + 5)
                        and qrcode.isDark(row, col + 6)):
                    lostPoint += 40

        for col in range(moduleCount):
            for row in range(moduleCount - 6):
                if (qrcode.isDark(row, col)
                        and not qrcode.isDark(row + 1, col)
                        and qrcode.isDark(row + 2, col)
                        and qrcode.isDark(row + 3, col)
                        and qrcode.isDark(row + 4, col)
                        and not qrcode.isDark(row + 5, col)
                        and qrcode.isDark(row + 6, col)):
                    lostPoint += 40

        # LEVEL4
        darkCount = 0
        for col in range(moduleCount):
            for row in range(moduleCount):
                if qrcode.isDark(row, col):
                    darkCount += 1

        ratio = abs(100 * darkCount // moduleCount // moduleCount - 50) // 5
        lostPoint += ratio * 10

        return lostPoint

    G15 = ((1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) |
           (1 << 2) | (1 << 1) | (1 << 0))
    G18 = ((1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) |
           (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0))
    G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1)

    @staticmethod
    def getBCHTypeInfo(data):
        d = data << 10
        while QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0:
            d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) -
                                 QRUtil.getBCHDigit(QRUtil.G15)))
        return ((data << 10) | d) ^ QRUtil.G15_MASK

    @staticmethod
    def getBCHTypeNumber(data):
        d = data << 12
        while QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0:
            d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) -
                                 QRUtil.getBCHDigit(QRUtil.G18)))
        return (data << 12) | d

    @staticmethod
    def getBCHDigit(data):
        digit = 0
        while data != 0:
            digit += 1
            data >>= 1
        return digit

    @staticmethod
    def stringToBytes(s):
        return [ord(c) & 0xff for c in s]


class QR8BitByte:

    def __init__(self, data):
        self.mode = Mode.MODE_8BIT_BYTE
        self.data = data

    def getMode(self):
        return self.mode

    def getData(self):
        return self.data

    '''
    def write(self, buffer): raise Exception('not implemented.')
    def getLength(self): raise Exception('not implemented.')
    '''

    def write(self, buffer):
        data = QRUtil.stringToBytes(self.getData())
        for d in data:
            buffer.put(d, 8)

    def getLength(self):
        return len(QRUtil.stringToBytes(self.getData()))

    def getLengthInBits(self, type):
        if 1 <= type and type < 10:  # 1 - 9
            return {
                Mode.MODE_NUMBER:    10,
                Mode.MODE_ALPHA_NUM: 9,
                Mode.MODE_8BIT_BYTE: 8,
                Mode.MODE_KANJI:     8
            }[self.mode]

        elif type < 27:  # 10 - 26
            return {
                Mode.MODE_NUMBER:    12,
                Mode.MODE_ALPHA_NUM: 11,
                Mode.MODE_8BIT_BYTE: 16,
                Mode.MODE_KANJI:     10
            }[self.mode]

        elif type < 41:  # 27 - 40
            return {
                Mode.MODE_NUMBER:    14,
                Mode.MODE_ALPHA_NUM: 13,
                Mode.MODE_8BIT_BYTE: 16,
                Mode.MODE_KANJI:     12
            }[self.mode]

        else:
            raise Exception('type:%s' % type)


class QRMath:

    EXP_TABLE = None
    LOG_TABLE = None

    @staticmethod
    def _init():
        QRMath.EXP_TABLE = [0] * 256
        for i in range(256):
            QRMath.EXP_TABLE[i] = (1 << i if i < 8 else
                                   QRMath.EXP_TABLE[i - 4]
                                   ^ QRMath.EXP_TABLE[i - 5]
                                   ^ QRMath.EXP_TABLE[i - 6]
                                   ^ QRMath.EXP_TABLE[i - 8])

        QRMath.LOG_TABLE = [0] * 256
        for i in range(255):
            QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i

    @staticmethod
    def glog(n):
        if n < 1:
            raise Exception('log(%s)' % n)
        return QRMath.LOG_TABLE[n]

    @staticmethod
    def gexp(n):
        while n < 0:
            n += 255
        while n >= 256:
            n -= 255
        return QRMath.EXP_TABLE[n]


# initialize statics
QRMath._init()


class Polynomial:

    def __init__(self, num, shift=0):
        offset = 0
        length = len(num)
        while offset < length and num[offset] == 0:
            offset += 1
        self.num = num[offset:] + [0] * shift

    def get(self, index):
        return self.num[index]

    def getLength(self):
        return len(self.num)

    def __repr__(self):
        return ','.join([str(self.get(i))
                         for i in range(self.getLength())])

    def toLogString(self):
        return ','.join([str(QRMath.glog(self.get(i)))
                         for i in range(self.getLength())])

    def multiply(self, e):
        num = [0] * (self.getLength() + e.getLength() - 1)
        for i in range(self.getLength()):
            for j in range(e.getLength()):
                num[i + j] ^= QRMath.gexp(QRMath.glog(self.get(i)) +
                                          QRMath.glog(e.get(j)))
        return Polynomial(num)

    def mod(self, e):
        if self.getLength() - e.getLength() < 0:
            return self
        ratio = QRMath.glog(self.get(0)) - QRMath.glog(e.get(0))
        num = self.num[:]
        for i in range(e.getLength()):
            num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio)
        return Polynomial(num).mod(e)


class RSBlock:

    RS_BLOCK_TABLE = [

        # L
        # M
        # Q
        # H

        # 1
        [1, 26, 19],
        [1, 26, 16],
        [1, 26, 13],
        [1, 26, 9],

        # 2
        [1, 44, 34],
        [1, 44, 28],
        [1, 44, 22],
        [1, 44, 16],

        # 3
        [1, 70, 55],
        [1, 70, 44],
        [2, 35, 17],
        [2, 35, 13],

        # 4
        [1, 100, 80],
        [2, 50, 32],
        [2, 50, 24],
        [4, 25, 9],

        # 5
        [1, 134, 108],
        [2, 67, 43],
        [2, 33, 15, 2, 34, 16],
        [2, 33, 11, 2, 34, 12],

        # 6
        [2, 86, 68],
        [4, 43, 27],
        [4, 43, 19],
        [4, 43, 15],

        # 7
        [2, 98, 78],
        [4, 49, 31],
        [2, 32, 14, 4, 33, 15],
        [4, 39, 13, 1, 40, 14],

        # 8
        [2, 121, 97],
        [2, 60, 38, 2, 61, 39],
        [4, 40, 18, 2, 41, 19],
        [4, 40, 14, 2, 41, 15],

        # 9
        [2, 146, 116],
        [3, 58, 36, 2, 59, 37],
        [4, 36, 16, 4, 37, 17],
        [4, 36, 12, 4, 37, 13],

        # 10
        [2, 86, 68, 2, 87, 69],
        [4, 69, 43, 1, 70, 44],
        [6, 43, 19, 2, 44, 20],
        [6, 43, 15, 2, 44, 16]
    ]

    def __init__(self, totalCount, dataCount):
        self.totalCount = totalCount
        self.dataCount = dataCount

    def getDataCount(self):
        return self.dataCount

    def getTotalCount(self):
        return self.totalCount

    def __repr__(self):
        return ('(total=%s,data=%s)' % (self.totalCount, self.dataCount))

    @staticmethod
    def getRSBlocks(typeNumber, errorCorrectLevel):
        rsBlock = RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel)
        length = len(rsBlock) // 3
        list = []
        for i in range(length):
            count = rsBlock[i * 3 + 0]
            totalCount = rsBlock[i * 3 + 1]
            dataCount = rsBlock[i * 3 + 2]
            list += [RSBlock(totalCount, dataCount)] * count
        return list

    @staticmethod
    def getRsBlockTable(typeNumber, errorCorrectLevel):
        return {
            ErrorCorrectLevel.L:
                RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0],
            ErrorCorrectLevel.M:
                RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1],
            ErrorCorrectLevel.Q:
                RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2],
            ErrorCorrectLevel.H:
                RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]
        }[errorCorrectLevel]


class BitBuffer:

    def __init__(self, inclements=32):
        self.inclements = inclements
        self.buffer = [0] * self.inclements
        self.length = 0

    def getBuffer(self):
        return self.buffer

    def getLengthInBits(self):
        return self.length

    def get(self, index):
        return ((self.buffer[index // 8] >> (7 - index % 8)) & 1) == 1

    def putBit(self, bit):
        if self.length == len(self.buffer) * 8:
            self.buffer += [0] * self.inclements
        if bit:
            self.buffer[self.length // 8] |= (0x80 >> (self.length % 8))
        self.length += 1

    def put(self, num, length):
        for i in range(length):
            self.putBit(((num >> (length - i - 1)) & 1) == 1)

    def __repr__(self):
        return ''.join('1' if self.get(i) else '0'
                       for i in range(self.getLengthInBits()))
