API Docs for: undefined
Show:

File: js/qr-code-generator-base.js

/**
 * gallery-qr-code-generator-base is a slightly low-level utility for generating
 * QR Codes.
 * @module gallery-qr-code-generator-base
 */

/**
 * @class QrCode
 * @static
 */
(function (Y) {
    'use strict';
    
    var _string__empty = '',
        _string_0 = '0',
        _string_1 = '1',
        _string_10 = '10',
        _string_alphanumeric = 'alphanumeric',
        _string_byte = 'byte',
        _string_complete = 'complete',
        _string_E = 'E',
        _string_errorCorrection = 'errorCorrection',
        _string_H = 'H',
        _string_initOnly = 'initOnly',
        _string_L = 'L',
        _string_M = 'M',
        _string_M1 = 'M1',
        _string_M3 = 'M3',
        _string_M4 = 'M4',
        _string_numeric = 'numeric',
        _string_Q = 'Q',
        _string_ucs2 = 'ucs2',
        _string_utf8 = 'utf8',
        _string_value = 'value',
        _string_version = 'version',
        
        _alignmentPatternLocations = [[
            18
        ], [
            22
        ], [
            26
        ], [
            30
        ], [
            34
        ], [
            22,
            38
        ], [
            24,
            42
        ], [
            26,
            46
        ], [
            28,
            50
        ], [
            30,
            54
        ], [
            32,
            58
        ], [
            34,
            62
        ], [
            26,
            46,
            66
        ], [
            26,
            48,
            70
        ], [
            26,
            50,
            74
        ], [
            30,
            54,
            78
        ], [
            30,
            56,
            82
        ], [
            30,
            58,
            86
        ], [
            34,
            62,
            90
        ], [
            28,
            50,
            72,
            94
        ], [
            26,
            50,
            74,
            98
        ], [
            30,
            54,
            78,
            102
        ], [
            28,
            54,
            80,
            106
        ], [
            32,
            58,
            84,
            110
        ], [
            30,
            58,
            86,
            114
        ], [
            34,
            62,
            90,
            118
        ], [
            26,
            50,
            74,
            98,
            122
        ], [
            30,
            54,
            78,
            102,
            126
        ], [
            26,
            52,
            78,
            104,
            130
        ], [
            30,
            56,
            82,
            108,
            134
        ], [
            34,
            60,
            86,
            112,
            138
        ], [
            30,
            58,
            86,
            114,
            142
        ], [
            34,
            62,
            90,
            118,
            146
        ], [
            30,
            54,
            78,
            102,
            126,
            150
        ], [
            24,
            50,
            76,
            102,
            128,
            154
        ], [
            28,
            54,
            80,
            106,
            132,
            158
        ], [
            32,
            58,
            84,
            110,
            136,
            162
        ], [
            26,
            54,
            82,
            110,
            138,
            166
        ], [
            30,
            58,
            86,
            114,
            142,
            170
        ]],
        _alpha = [
            1,
            2,
            4,
            8,
            16,
            32,
            64,
            128,
            29,
            58,
            116,
            232,
            205,
            135,
            19,
            38,
            76,
            152,
            45,
            90,
            180,
            117,
            234,
            201,
            143,
            3,
            6,
            12,
            24,
            48,
            96,
            192,
            157,
            39,
            78,
            156,
            37,
            74,
            148,
            53,
            106,
            212,
            181,
            119,
            238,
            193,
            159,
            35,
            70,
            140,
            5,
            10,
            20,
            40,
            80,
            160,
            93,
            186,
            105,
            210,
            185,
            111,
            222,
            161,
            95,
            190,
            97,
            194,
            153,
            47,
            94,
            188,
            101,
            202,
            137,
            15,
            30,
            60,
            120,
            240,
            253,
            231,
            211,
            187,
            107,
            214,
            177,
            127,
            254,
            225,
            223,
            163,
            91,
            182,
            113,
            226,
            217,
            175,
            67,
            134,
            17,
            34,
            68,
            136,
            13,
            26,
            52,
            104,
            208,
            189,
            103,
            206,
            129,
            31,
            62,
            124,
            248,
            237,
            199,
            147,
            59,
            118,
            236,
            197,
            151,
            51,
            102,
            204,
            133,
            23,
            46,
            92,
            184,
            109,
            218,
            169,
            79,
            158,
            33,
            66,
            132,
            21,
            42,
            84,
            168,
            77,
            154,
            41,
            82,
            164,
            85,
            170,
            73,
            146,
            57,
            114,
            228,
            213,
            183,
            115,
            230,
            209,
            191,
            99,
            198,
            145,
            63,
            126,
            252,
            229,
            215,
            179,
            123,
            246,
            241,
            255,
            227,
            219,
            171,
            75,
            150,
            49,
            98,
            196,
            149,
            55,
            110,
            220,
            165,
            87,
            174,
            65,
            130,
            25,
            50,
            100,
            200,
            141,
            7,
            14,
            28,
            56,
            112,
            224,
            221,
            167,
            83,
            166,
            81,
            162,
            89,
            178,
            121,
            242,
            249,
            239,
            195,
            155,
            43,
            86,
            172,
            69,
            138,
            9,
            18,
            36,
            72,
            144,
            61,
            122,
            244,
            245,
            247,
            243,
            251,
            235,
            203,
            139,
            11,
            22,
            44,
            88,
            176,
            125,
            250,
            233,
            207,
            131,
            27,
            54,
            108,
            216,
            173,
            71,
            142
        ],
        _codewordCount = {
            M1: {
                E: [
                    3,
                    1,
                    3,
                    2
                ]
            },
            M2: {
                L: [
                    5,
                    1,
                    5,
                    5
                ],
                M: [
                    4,
                    1,
                    4,
                    6
                ]
            },
            M3: {
                L: [
                    11,
                    1,
                    11,
                    6
                ],
                M: [
                    9,
                    1,
                    9,
                    8
                ]
            },
            M4: {
                L: [
                    16,
                    1,
                    16,
                    8
                ],
                M: [
                    14,
                    1,
                    14,
                    10
                ],
                Q: [
                    10,
                    1,
                    10,
                    14
                ]
            },
            1: {
                H: [
                    9,
                    1,
                    9,
                    17
                ],
                L: [
                    19,
                    1,
                    19,
                    7
                ],
                M: [
                    16,
                    1,
                    16,
                    10
                ],
                Q: [
                    13,
                    1,
                    13,
                    13
                ]
            },
            2: {
                H: [
                    16,
                    1,
                    16,
                    28
                ],
                L: [
                    34,
                    1,
                    34,
                    10
                ],
                M: [
                    28,
                    1,
                    28,
                    16
                ],
                Q: [
                    22,
                    1,
                    22,
                    22
                ]
            },
            3: {
                H: [
                    26,
                    2,
                    13,
                    22
                ],
                L: [
                    55,
                    1,
                    55,
                    15
                ],
                M: [
                    44,
                    1,
                    44,
                    26
                ],
                Q: [
                    34,
                    2,
                    17,
                    18
                ]
            },
            4: {
                H: [
                    36,
                    4,
                    9,
                    16
                ],
                L: [
                    80,
                    1,
                    80,
                    20
                ],
                M: [
                    64,
                    2,
                    32,
                    18
                ],
                Q: [
                    48,
                    2,
                    24,
                    26
                ]
            },
            5: {
                H: [
                    46,
                    2,
                    11,
                    22
                ],
                L: [
                    108,
                    1,
                    108,
                    26
                ],
                M: [
                    86,
                    2,
                    43,
                    24
                ],
                Q: [
                    62,
                    2,
                    15,
                    18
                ]
            },
            6: {
                H: [
                    60,
                    4,
                    15,
                    28
                ],
                L: [
                    136,
                    2,
                    68,
                    18
                ],
                M: [
                    108,
                    4,
                    27,
                    16
                ],
                Q: [
                    76,
                    4,
                    19,
                    24
                ]
            },
            7: {
                H: [
                    66,
                    4,
                    13,
                    26
                ],
                L: [
                    156,
                    2,
                    78,
                    20
                ],
                M: [
                    124,
                    4,
                    31,
                    18
                ],
                Q: [
                    88,
                    2,
                    14,
                    18
                ]
            },
            8: {
                H: [
                    86,
                    4,
                    14,
                    26
                ],
                L: [
                    194,
                    2,
                    97,
                    24
                ],
                M: [
                    154,
                    2,
                    38,
                    22
                ],
                Q: [
                    110,
                    4,
                    18,
                    22
                ]
            },
            9: {
                H: [
                    100,
                    4,
                    12,
                    24
                ],
                L: [
                    232,
                    2,
                    116,
                    30
                ],
                M: [
                    182,
                    3,
                    36,
                    22
                ],
                Q: [
                    132,
                    4,
                    16,
                    20
                ]
            },
            10: {
                H: [
                    122,
                    6,
                    15,
                    28
                ],
                L: [
                    274,
                    2,
                    68,
                    18
                ],
                M: [
                    216,
                    4,
                    43,
                    26
                ],
                Q: [
                    154,
                    6,
                    19,
                    22
                ]
            },
            11: {
                H: [
                    140,
                    3,
                    12,
                    24
                ],
                L: [
                    324,
                    4,
                    81,
                    20
                ],
                M: [
                    254,
                    1,
                    50,
                    30
                ],
                Q: [
                    180,
                    4,
                    22,
                    28
                ]
            },
            12: {
                H: [
                    158,
                    7,
                    14,
                    28
                ],
                L: [
                    370,
                    2,
                    92,
                    24
                ],
                M: [
                    290,
                    6,
                    36,
                    22
                ],
                Q: [
                    206,
                    4,
                    20,
                    26
                ]
            },
            13: {
                H: [
                    180,
                    12,
                    11,
                    22
                ],
                L: [
                    428,
                    4,
                    107,
                    26
                ],
                M: [
                    334,
                    8,
                    37,
                    22
                ],
                Q: [
                    244,
                    8,
                    20,
                    24
                ]
            },
            14: {
                H: [
                    197,
                    11,
                    12,
                    24
                ],
                L: [
                    461,
                    3,
                    115,
                    30
                ],
                M: [
                    365,
                    4,
                    40,
                    24
                ],
                Q: [
                    261,
                    11,
                    16,
                    20
                ]
            },
            15: {
                H: [
                    223,
                    11,
                    12,
                    24
                ],
                L: [
                    523,
                    5,
                    87,
                    22
                ],
                M: [
                    415,
                    5,
                    41,
                    24
                ],
                Q: [
                    295,
                    5,
                    24,
                    30
                ]
            },
            16: {
                H: [
                    253,
                    3,
                    15,
                    30
                ],
                L: [
                    589,
                    5,
                    98,
                    24
                ],
                M: [
                    453,
                    7,
                    45,
                    28
                ],
                Q: [
                    325,
                    15,
                    19,
                    24
                ]
            },
            17: {
                H: [
                    283,
                    2,
                    14,
                    28
                ],
                L: [
                    647,
                    1,
                    107,
                    28
                ],
                M: [
                    507,
                    10,
                    46,
                    28
                ],
                Q: [
                    367,
                    1,
                    22,
                    28
                ]
            },
            18: {
                H: [
                    313,
                    2,
                    14,
                    28
                ],
                L: [
                    721,
                    5,
                    120,
                    30
                ],
                M: [
                    563,
                    9,
                    43,
                    26
                ],
                Q: [
                    397,
                    17,
                    22,
                    28
                ]
            },
            19: {
                H: [
                    341,
                    9,
                    13,
                    26
                ],
                L: [
                    795,
                    3,
                    113,
                    28
                ],
                M: [
                    627,
                    3,
                    44,
                    26
                ],
                Q: [
                    445,
                    17,
                    21,
                    26
                ]
            },
            20: {
                H: [
                    385,
                    15,
                    15,
                    28
                ],
                L: [
                    861,
                    3,
                    107,
                    28
                ],
                M: [
                    669,
                    3,
                    41,
                    26
                ],
                Q: [
                    485,
                    15,
                    24,
                    30
                ]
            },
            21: {
                H: [
                    406,
                    19,
                    16,
                    30
                ],
                L: [
                    932,
                    4,
                    116,
                    28
                ],
                M: [
                    714,
                    17,
                    42,
                    26
                ],
                Q: [
                    512,
                    17,
                    22,
                    28
                ]
            },
            22: {
                H: [
                    442,
                    34,
                    13,
                    24
                ],
                L: [
                    1006,
                    2,
                    111,
                    28
                ],
                M: [
                    782,
                    17,
                    46,
                    28
                ],
                Q: [
                    568,
                    7,
                    24,
                    30
                ]
            },
            23: {
                H: [
                    464,
                    16,
                    15,
                    30
                ],
                L: [
                    1094,
                    4,
                    121,
                    30
                ],
                M: [
                    860,
                    4,
                    47,
                    28
                ],
                Q: [
                    614,
                    11,
                    24,
                    30
                ]
            },
            24: {
                H: [
                    514,
                    30,
                    16,
                    30
                ],
                L: [
                    1174,
                    6,
                    117,
                    30
                ],
                M: [
                    914,
                    6,
                    45,
                    28
                ],
                Q: [
                    664,
                    11,
                    24,
                    30
                ]
            },
            25: {
                H: [
                    538,
                    22,
                    15,
                    30
                ],
                L: [
                    1276,
                    8,
                    106,
                    26
                ],
                M: [
                    1000,
                    8,
                    47,
                    28
                ],
                Q: [
                    718,
                    7,
                    24,
                    30
                ]
            },
            26: {
                H: [
                    596,
                    33,
                    16,
                    30
                ],
                L: [
                    1370,
                    10,
                    114,
                    28
                ],
                M: [
                    1062,
                    19,
                    46,
                    28
                ],
                Q: [
                    754,
                    28,
                    22,
                    28
                ]
            },
            27: {
                H: [
                    628,
                    12,
                    15,
                    30
                ],
                L: [
                    1468,
                    8,
                    122,
                    30
                ],
                M: [
                    1128,
                    22,
                    45,
                    28
                ],
                Q: [
                    808,
                    8,
                    23,
                    30
                ]
            },
            28: {
                H: [
                    661,
                    11,
                    15,
                    30
                ],
                L: [
                    1531,
                    3,
                    117,
                    30
                ],
                M: [
                    1193,
                    3,
                    45,
                    28
                ],
                Q: [
                    871,
                    4,
                    24,
                    30
                ]
            },
            29: {
                H: [
                    701,
                    19,
                    15,
                    30
                ],
                L: [
                    1631,
                    7,
                    116,
                    30
                ],
                M: [
                    1267,
                    21,
                    45,
                    28
                ],
                Q: [
                    911,
                    1,
                    23,
                    30
                ]
            },
            30: {
                H: [
                    745,
                    23,
                    15,
                    30
                ],
                L: [
                    1735,
                    5,
                    115,
                    30
                ],
                M: [
                    1373,
                    19,
                    47,
                    28
                ],
                Q: [
                    985,
                    15,
                    30
                ]
            },
            31: {
                H: [
                    793,
                    23,
                    15,
                    30
                ],
                L: [
                    1843,
                    13,
                    115,
                    30
                ],
                M: [
                    1455,
                    2,
                    46,
                    28
                ],
                Q: [
                    1033,
                    42,
                    24,
                    30
                ]
            },
            32: {
                H: [
                    845,
                    19,
                    15,
                    30
                ],
                L: [
                    1955,
                    17,
                    115,
                    30
                ],
                M: [
                    1541,
                    10,
                    46,
                    28
                ],
                Q: [
                    1115,
                    10,
                    24,
                    30
                ]
            },
            33: {
                H: [
                    901,
                    11,
                    15,
                    30
                ],
                L: [
                    2071,
                    17,
                    115,
                    30
                ],
                M: [
                    1631,
                    14,
                    46,
                    28
                ],
                Q: [
                    1171,
                    29,
                    24,
                    30
                ]
            },
            34: {
                H: [
                    961,
                    59,
                    16,
                    30
                ],
                L: [
                    2191,
                    13,
                    115,
                    30
                ],
                M: [
                    1725,
                    14,
                    46,
                    28
                ],
                Q: [
                    1231,
                    44,
                    24,
                    30
                ]
            },
            35: {
                H: [
                    986,
                    22,
                    15,
                    30
                ],
                L: [
                    2306,
                    12,
                    121,
                    30
                ],
                M: [
                    1812,
                    12,
                    47,
                    28
                ],
                Q: [
                    1286,
                    39,
                    24,
                    30
                ]
            },
            36: {
                H: [
                    1054,
                    2,
                    15,
                    30
                ],
                L: [
                    2434,
                    6,
                    121,
                    30
                ],
                M: [
                    1914,
                    6,
                    47,
                    28
                ],
                Q: [
                    1354,
                    46,
                    24,
                    30
                ]
            },
            37: {
                H: [
                    1096,
                    24,
                    15,
                    30
                ],
                L: [
                    2566,
                    17,
                    122,
                    30
                ],
                M: [
                    1992,
                    29,
                    46,
                    28
                ],
                Q: [
                    1426,
                    49,
                    24,
                    30
                ]
            },
            38: {
                H: [
                    1142,
                    42,
                    15,
                    30
                ],
                L: [
                    2702,
                    4,
                    122,
                    30
                ],
                M: [
                    2102,
                    13,
                    46,
                    28
                ],
                Q: [
                    1502,
                    48,
                    24,
                    30
                ]
            },
            39: {
                H: [
                    1222,
                    10,
                    15,
                    30
                ],
                L: [
                    2812,
                    20,
                    117,
                    30
                ],
                M: [
                    2216,
                    40,
                    47,
                    28
                ],
                Q: [
                    1582,
                    43,
                    24,
                    30
                ]
            },
            40: {
                H: [
                    1276,
                    20,
                    15,
                    30
                ],
                L: [
                    2956,
                    19,
                    118,
                    30
                ],
                M: [
                    2334,
                    18,
                    47,
                    28
                ],
                Q: [
                    1666,
                    34,
                    24,
                    30
                ]
            }
        },
        _dataTypes = {
            alphanumeric: _string_alphanumeric,
            'byte': _string_byte,
            numeric: _string_numeric,
            ucs2: _string_ucs2,
            utf8: _string_utf8
        },
        _formatInformation = [
            21522,
            20773,
            24188,
            23371,
            17913,
            16590,
            20375,
            19104,
            30660,
            29427,
            32170,
            30877,
            26159,
            25368,
            27713,
            26998,
            5769,
            5054,
            7399,
            6608,
            1890,
            597,
            3340,
            2107,
            13663,
            12392,
            16177,
            14854,
            9396,
            8579,
            11994,
            11245
        ],
        // TODO: Find out if all of these indices are necessary.
        _generatorAlphaIndicies = {
            2: [
                25,
                1
            ],
            5: [
                113,
                164,
                166,
                119,
                10
            ],
            6: [
                116,
                0,
                134,
                5,
                176,
                15
            ],
            7: [
                87,
                299,
                146,
                149,
                238,
                102,
                21
            ],
            8: [
                175,
                238,
                208,
                249,
                215,
                252,
                196,
                28
            ],
            10: [
                251,
                67,
                46,
                61,
                118,
                70,
                64,
                94,
                32,
                45
            ],
            13: [
                74,
                152,
                176,
                100,
                86,
                100,
                106,
                104,
                130,
                218,
                206,
                140,
                78
            ],
            14: [
                199,
                249,
                155,
                48,
                190,
                124,
                218,
                137,
                216,
                87,
                207,
                59,
                22,
                91
            ],
            15: [
                8,
                183,
                61,
                91,
                202,
                37,
                51,
                58,
                58,
                237,
                140,
                124,
                5,
                99,
                105
            ],
            16: [
                120,
                104,
                107,
                109,
                102,
                161,
                76,
                3,
                91,
                191,
                147,
                169,
                182,
                194,
                225,
                120
            ],
            18: [
                215,
                234,
                158,
                94,
                184,
                97,
                118,
                170,
                79,
                187,
                152,
                148,
                252,
                179,
                5,
                98,
                96,
                153
            ],
            20: [
                17,
                60,
                79,
                50,
                61,
                163,
                26,
                187,
                202,
                180,
                221,
                225,
                83,
                239,
                156,
                164,
                212,
                212,
                188,
                190
            ],
            22: [
                210,
                171,
                247,
                242,
                93,
                230,
                14,
                109,
                221,
                53,
                200,
                74,
                8,
                172,
                98,
                80,
                219,
                134,
                160,
                105,
                165,
                231
            ],
            24: [
                229,
                121,
                135,
                48,
                211,
                117,
                251,
                126,
                159,
                180,
                169,
                152,
                192,
                226,
                228,
                218,
                111,
                0,
                117,
                232,
                87,
                96,
                227,
                21
            ],
            26: [
                173,
                125,
                158,
                2,
                103,
                182,
                118,
                17,
                145,
                201,
                111,
                28,
                165,
                53,
                161,
                21,
                245,
                142,
                13,
                102,
                48,
                227,
                153,
                145,
                218,
                70
            ],
            28: [
                168,
                223,
                200,
                104,
                224,
                234,
                108,
                180,
                110,
                190,
                195,
                147,
                205,
                27,
                232,
                201,
                21,
                43,
                245,
                87,
                42,
                195,
                212,
                119,
                242,
                37,
                9,
                123
            ],
            30: [
                41,
                173,
                145,
                152,
                216,
                31,
                179,
                182,
                50,
                48,
                110,
                86,
                239,
                96,
                222,
                125,
                42,
                173,
                226,
                193,
                224,
                130,
                156,
                37,
                251,
                216,
                238,
                40,
                192,
                180
            ],
            32: [
                10,
                6,
                106,
                190,
                249,
                167,
                4,
                67,
                209,
                138,
                138,
                32,
                242,
                123,
                89,
                27,
                120,
                185,
                80,
                156,
                38,
                69,
                171,
                60,
                28,
                222,
                80,
                52,
                254,
                185,
                220,
                241
            ],
            34: [
                111,
                77,
                146,
                94,
                26,
                21,
                108,
                19,
                105,
                94,
                113,
                193,
                86,
                140,
                163,
                125,
                58,
                158,
                229,
                239,
                218,
                103,
                56,
                70,
                114,
                61,
                183,
                129,
                167,
                13,
                98,
                62,
                129,
                51
            ],
            36: [
                200,
                183,
                98,
                16,
                172,
                31,
                246,
                234,
                60,
                152,
                115,
                24,
                167,
                152,
                113,
                248,
                238,
                107,
                18,
                63,
                218,
                37,
                87,
                210,
                105,
                177,
                120,
                74,
                121,
                196,
                117,
                251,
                113,
                233,
                30,
                120
            ],
            40: [
                59,
                116,
                79,
                161,
                252,
                98,
                128,
                205,
                128,
                161,
                247,
                57,
                163,
                56,
                235,
                106,
                53,
                26,
                187,
                174,
                226,
                104,
                170,
                7,
                175,
                35,
                181,
                114,
                88,
                41,
                47,
                163,
                125,
                134,
                72,
                20,
                232,
                53,
                35,
                15
            ],
            42: [
                250,
                103,
                221,
                230,
                25,
                18,
                137,
                231,
                0,
                3,
                58,
                242,
                221,
                191,
                110,
                84,
                230,
                8,
                188,
                106,
                96,
                147,
                15,
                131,
                139,
                34,
                101,
                223,
                39,
                101,
                213,
                199,
                237,
                254,
                201,
                123,
                171,
                162,
                194,
                117,
                50,
                96
            ],
            44: [
                190,
                7,
                61,
                121,
                71,
                246,
                69,
                55,
                168,
                188,
                89,
                243,
                191,
                25,
                72,
                123,
                9,
                145,
                14,
                247,
                1,
                238,
                44,
                78,
                143,
                62,
                224,
                126,
                118,
                114,
                68,
                163,
                52,
                194,
                217,
                147,
                204,
                169,
                37,
                130,
                113,
                102,
                73,
                181
            ],
            46: [
                112,
                94,
                88,
                112,
                253,
                224,
                202,
                115,
                187,
                99,
                89,
                5,
                54,
                113,
                129,
                44,
                58,
                16,
                135,
                216,
                169,
                211,
                36,
                1,
                4,
                96,
                60,
                241,
                73,
                104,
                234,
                8,
                249,
                245,
                119,
                174,
                52,
                25,
                157,
                224,
                43,
                202,
                223,
                19,
                82,
                15
            ],
            48: [
                228,
                25,
                196,
                130,
                211,
                146,
                60,
                24,
                251,
                90,
                39,
                102,
                240,
                61,
                178,
                63,
                46,
                123,
                115,
                18,
                221,
                111,
                135,
                160,
                182,
                205,
                107,
                206,
                95,
                150,
                120,
                184,
                91,
                21,
                247,
                156,
                140,
                238,
                191,
                11,
                94,
                227,
                84,
                50,
                163,
                39,
                34,
                108
            ],
            50: [
                232,
                125,
                157,
                161,
                164,
                9,
                118,
                46,
                209,
                99,
                203,
                193,
                35,
                3,
                209,
                111,
                195,
                242,
                203,
                225,
                46,
                13,
                32,
                160,
                126,
                209,
                130,
                160,
                242,
                215,
                242,
                75,
                77,
                42,
                189,
                32,
                113,
                65,
                124,
                69,
                228,
                114,
                235,
                175,
                124,
                170,
                215,
                232,
                133,
                205
            ],
            52: [
                116,
                50,
                86,
                186,
                50,
                220,
                251,
                89,
                192,
                46,
                86,
                127,
                124,
                19,
                184,
                233,
                151,
                215,
                22,
                14,
                59,
                145,
                37,
                242,
                203,
                134,
                254,
                89,
                190,
                94,
                59,
                65,
                124,
                113,
                100,
                233,
                235,
                121,
                22,
                76,
                86,
                97,
                39,
                242,
                200,
                220,
                101,
                33,
                239,
                254,
                116,
                51
            ],
            54: [
                183,
                26,
                201,
                87,
                210,
                221,
                113,
                21,
                46,
                65,
                45,
                50,
                238,
                184,
                249,
                225,
                102,
                58,
                209,
                218,
                109,
                165,
                26,
                95,
                184,
                192,
                52,
                245,
                35,
                254,
                238,
                175,
                172,
                79,
                123,
                25,
                122,
                43,
                120,
                108,
                215,
                80,
                128,
                201,
                235,
                8,
                153,
                59,
                101,
                31,
                198,
                76,
                31,
                156
            ],
            56: [
                106,
                120,
                107,
                157,
                164,
                216,
                112,
                116,
                2,
                91,
                248,
                163,
                36,
                201,
                202,
                229,
                6,
                144,
                254,
                155,
                135,
                208,
                170,
                209,
                12,
                139,
                127,
                142,
                182,
                249,
                177,
                174,
                190,
                28,
                10,
                85,
                239,
                184,
                101,
                124,
                152,
                206,
                96,
                23,
                163,
                61,
                27,
                196,
                247,
                151,
                154,
                202,
                207,
                20,
                61,
                10
            ],
            58: [
                82,
                116,
                26,
                247,
                66,
                27,
                62,
                107,
                252,
                182,
                200,
                185,
                235,
                55,
                251,
                242,
                210,
                144,
                154,
                237,
                176,
                141,
                192,
                248,
                152,
                249,
                206,
                85,
                253,
                142,
                65,
                165,
                125,
                23,
                24,
                30,
                122,
                240,
                214,
                6,
                129,
                218,
                29,
                145,
                127,
                134,
                206,
                245,
                117,
                29,
                41,
                63,
                159,
                142,
                233,
                125,
                148,
                123
            ],
            60: [
                107,
                140,
                26,
                12,
                9,
                141,
                243,
                197,
                226,
                197,
                219,
                45,
                211,
                101,
                219,
                120,
                28,
                181,
                127,
                6,
                100,
                247,
                2,
                205,
                198,
                57,
                115,
                219,
                101,
                109,
                160,
                82,
                37,
                38,
                238,
                49,
                160,
                209,
                121,
                86,
                11,
                124,
                30,
                181,
                84,
                25,
                194,
                87,
                65,
                102,
                190,
                220,
                70,
                27,
                209,
                16,
                89,
                7,
                33,
                240
            ],
            62: [
                65,
                202,
                113,
                98,
                71,
                223,
                248,
                118,
                214,
                94,
                0,
                122,
                37,
                23,
                2,
                228,
                58,
                121,
                7,
                105,
                135,
                78,
                243,
                118,
                70,
                76,
                223,
                89,
                72,
                50,
                70,
                111,
                194,
                17,
                212,
                126,
                181,
                35,
                221,
                117,
                235,
                11,
                229,
                149,
                147,
                123,
                213,
                40,
                115,
                6,
                200,
                100,
                26,
                246,
                182,
                218,
                127,
                215,
                36,
                186,
                110,
                106
            ],
            64: [
                45,
                51,
                175,
                9,
                7,
                158,
                159,
                49,
                68,
                119,
                92,
                123,
                177,
                204,
                187,
                254,
                200,
                78,
                141,
                149,
                119,
                26,
                127,
                53,
                160,
                93,
                199,
                212,
                29,
                24,
                145,
                156,
                208,
                150,
                218,
                209,
                4,
                216,
                91,
                47,
                184,
                146,
                47,
                140,
                195,
                195,
                125,
                242,
                238,
                63,
                99,
                108,
                140,
                230,
                242,
                31,
                204,
                11,
                178,
                243,
                217,
                156,
                213,
                231
            ],
            66: [
                5,
                118,
                222,
                180,
                136,
                136,
                162,
                51,
                46,
                117,
                13,
                215,
                81,
                17,
                139,
                247,
                197,
                171,
                95,
                173,
                65,
                137,
                178,
                68,
                111,
                95,
                101,
                41,
                72,
                214,
                169,
                197,
                95,
                7,
                44,
                154,
                77,
                111,
                236,
                40,
                121,
                143,
                63,
                87,
                80,
                253,
                240,
                126,
                217,
                77,
                34,
                232,
                106,
                50,
                168,
                82,
                76,
                146,
                67,
                106,
                171,
                25,
                132,
                93,
                45,
                105
            ],
            68: [
                247,
                159,
                223,
                33,
                224,
                93,
                77,
                70,
                90,
                160,
                32,
                254,
                43,
                150,
                84,
                101,
                190,
                205,
                133,
                52,
                60,
                202,
                165,
                220,
                203,
                151,
                93,
                84,
                15,
                84,
                253,
                173,
                160,
                89,
                227,
                52,
                199,
                97,
                95,
                231,
                52,
                177,
                41,
                125,
                137,
                241,
                166,
                225,
                118,
                2,
                54,
                32,
                82,
                215,
                175,
                198,
                43,
                238,
                235,
                27,
                101,
                184,
                127,
                3,
                5,
                8,
                163,
                238
            ]
        },
        _microFormatInformation = [
            17477,
            16754,
            20011,
            19228,
            21934,
            20633,
            24512,
            23287,
            26515,
            25252,
            28157,
            26826,
            30328,
            29519,
            31766,
            31009,
            1758,
            1001,
            3248,
            2439,
            5941,
            4610,
            7515,
            6252,
            9480,
            8255,
            12134,
            10833,
            13539,
            12756,
            16013,
            15290
        ],
        _versionInformation = [
            31892,
            34236,
            39577,
            42195,
            48118,
            51042,
            55367,
            58893,
            63784,
            68472,
            70749,
            76311,
            79154,
            84390,
            87683,
            92361,
            96236,
            102084,
            102881,
            110507,
            110734,
            117786,
            119615,
            126325,
            127568,
            133589,
            136944,
            141498,
            145311,
            150283,
            152622,
            158308,
            161089
        ],
        
        _Array = Array,
        _String = String,
        _YArray = Y.Array,
        _YAsync = Y.Async,
        _YBase = Y.Base,
        _YLang = Y.Lang,
        
        _abs = Math.abs,
        _ceil = Math.ceil,
        _each = Y.each,
        _floor = Math.floor,
        _isArray = _YLang.isArray,
        _indexOf = _YArray.indexOf,
        _isUndefined = _YLang.isUndefined,
        _iterate = _YArray.iterate,
        _map = _YArray.map,
        _max = Math.max,
        _min = Math.min,
        _mix = Y.mix,
        _numberToBinaryString,
        _parseInt = parseInt,
        _reduce = _YArray.reduce,
        _soon = Y.soon,
        
        _cachedIndexOf = Y.cached(_indexOf),
        _maskFunctions = [
            function (x, y) {
                return (x + y) % 2 === 0;
            },
            function (x, y) {
                return y % 2 === 0;
            },
            function (x, y) {
                return x % 3 === 0;
            },
            function (x, y) {
                return (x + y) % 3 === 0;
            },
            function (x, y) {
                return (_floor(x / 3) + _floor(y / 2)) % 2 === 0;
            },
            function (x, y) {
                var product = x * y;
                return product % 2 + product % 3 === 0;
            },
            function (x, y) {
                var product = x * y;
                return (product % 2 + product % 3) % 2 === 0;
            },
            function (x, y) {
                return ((x + y) % 2 + (x * y) % 3) % 2 === 0;
            }
        ],
        _microMaskFunctions = [
            _maskFunctions[1],
            _maskFunctions[4],
            _maskFunctions[6],
            _maskFunctions[7]
        ],
        
        /**
         * This class shouldn't be used directly.  It is intended as an
         * interface to implement a specific data encoding mode.
         * @class Data
         * @constructor
         * @extends Base
         * @namespace QrCode
         * @param {Object} config Configuration object.
         */
        _Data = _YBase.create('qr-code-data', _YBase, [], {
            /**
             * This is an abstract method that should be implemented to return a
             * properly formatted binary string for a specific data encoding
             * mode.
             * @method toBinaryString
             * @for QrCode.Data
             * @param {Number|String} version
             * @return {String}
             */
        }, {
            ATTRS: {
                /**
                 * When extending this class, the value of type should be
                 * specifically defined.  Make sure the type is also set on the
                 * Y.QrCode.Data.Type object.
                 * @attribute type
                 * @initOnly
                 * @type String
                 */
                type: {
                    validator: function (value) {
                        return !!_dataTypes[value];
                    },
                    writeOnce: _string_initOnly
                },
                /**
                 * The value to encode.
                 * @attribute value
                 * @initOnly
                 */
                value: {
                    value: null,
                    writeOnce: _string_initOnly
                }
            },
            /**
             * This object lists all supported data encoding modes.
             * @property Type
             * @static
             * @type [String]
             */
            Type: _dataTypes
        }),
        
        /**
         * This class provides utility methods for generating QR Codes.
         * @class GeneratorBase
         * @constructor
         * @extends Base
         * @namespace QrCode
         * @param {Object} config Configuration object.
         */
        _GeneratorBase = _YBase.create('qr-code-generator-base', _YBase, [], {
            /**
             * Performs a mask operation that inverts some data bits.  QR Codes
             * apply one of eight possible masks to the raw data matrix.
             * Decoders benefit when a mask is used to reduce the occurence of
             * ambiguous patterns within the data matrix.
             * @method applyMask
             * @chainable
             * @for QrCode.GeneratorBase
             * @param {[Boolean]} matrix The array to write the results to.
             * Existing data will be overwritten.
             * @param {[Boolean]} dataMatrix An array with the source data.
             * Non-data elements should be undefined.
             * @param {Function} maskFunction A function that accepts x and y
             * coordinates and returns true or false.  The x and y coordinates
             * passed to the mask function do not account for the quiet zone
             * region.  When the mask function returns true, the data at that
             * position is inverted.
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @param {Number} size The square root of the length of matrix.
             * (dataMatrix and matrix should be the same size.)
             * @param {Function} callbackFunction This function will be called
             * once the mask has been applied.  It is guaranteed to be called in
             * a future turn of the event loop.  The modified matrix will be
             * passed as the only argument.
             */
            applyMask: function (matrix, dataMatrix, maskFunction, quietZoneSize, size, callbackFunction) {
                var maskRowRun = [],
                    i,
                    y = quietZoneSize,
                    
                    maskRowFunction = function (success) {
                        _soon(function () {
                            var index,
                                value,
                                x = size - quietZoneSize - 1;
                                
                            // Iterate through the columns within this row.
                            while (x >= quietZoneSize) {
                                index = x + y * size;
                                value = dataMatrix[index];
                                
                                if (!_isUndefined(value)) {
                                    // Write an inverted value to matrix if maskFunction returns true.
                                    matrix[index] = maskFunction(x - quietZoneSize, y - quietZoneSize) ? !value : value;
                                }
                                
                                x -= 1;
                            }
                            
                            y += 1;
                            success();
                        });
                    };
                    
                // Prepare to iterate through the rows of the matrix.
                for (i = size - quietZoneSize - 1; i >= y; i -= 1) {
                    maskRowRun.push(maskRowFunction);
                }
                
                // Iterate through the rows of the matrix.
                _YAsync.runQueue(maskRowRun).on(_string_complete, function () {
                    _soon(function () {
                        callbackFunction(matrix);
                    });
                });
                
                return this;
            },
            /**
             * Alignment patterns are distinct patterns used to help decoders
             * overcome distortion and perspective when viewing a QR Code.  They
             * are made up of a 5x5 square of dark values surrounding a 3x3
             * square of light values surrounding a single dark value.
             * @method drawAlignmentPattern
             * @chainable
             * @param {[Boolean]} matrix The array to write to.
             * @param {Number} centerX The x coordinate of the center of the
             * alignment pattern.
             * @param {Number} centerY The y coordinate of the center of the
             * alignment pattern.
             * @param {Number} size The square root of the length of matrix.
             * @param {Boolean} overwrite When set to true, the alignment
             * pattern will replace any existing data in the matrix at that
             * location.
             */
            drawAlignmentPattern: function (matrix, centerX, centerY, size, overwrite) {
                var endX = centerX + 2,
                    endY = centerY + 2,
                    index,
                    startX = centerX - 2,
                    startY = centerY - 2,
                    x,
                    y;
                    
                // Iterate through the positions occupied by the alignment pattern.
                for (x = startX; x <= endX; x += 1) {
                    for (y = startY; y <= endY; y += 1) {
                        index = x + y * size;
                        if (overwrite || _isUndefined(matrix[index])) {
                            // Write a light or dark value as required.
                            matrix[index] = x === startX || x === endX || y === startY || y === endY || x === centerX && y === centerY;
                        }
                    }
                }
                
                return this;
            },
            /**
             * Finder patterns are distinct patterns placed in three corners of
             * a QR code.  Finder patterns help decoders determine position,
             * scale, and orientation.  They are made up of a 9x9 square of
             * light values surrounding a 7x7 square of dark values surrounding
             * a 5x5 square of light values surrounding a 3x3 square filled with
             * dark values.
             * @method drawFinderPattern
             * @chainable
             * @param {[Boolean]} matrix The array to write to.
             * @param {Number} centerX The x coordinate of the center of the
             * finder pattern.
             * @param {Number} centerY The y coordinate of the center of the
             * finder pattern.
             * @param {Number} size The square root of the length of matrix.
             * @param {Boolean} overwrite When set to true, the finder pattern
             * will replace any existing data in the matrix at that location.
             */
            drawFinderPattern: function (matrix, centerX, centerY, size, overwrite) {
                var endX = centerX + 3,
                    endY = centerY + 3,
                    index,
                    startX = centerX - 3,
                    startY = centerY - 3,
                    x,
                    y;
                    
                // Iterate through the positions occupied by the finder pattern.
                for (x = startX - 1; x <= endX + 1; x += 1) {
                    for (y = startY - 1; y <= endY + 1; y += 1) {
                        index = x + y * size;
                        if (overwrite || _isUndefined(matrix[index])) {
                            // Write a light or dark value as required.
                            matrix[index] = x >= startX && x <= endX && y >= startY && y <= endY && (x === startX || x === endX || y === startY || y === endY) || x >= centerX - 1 && x <= centerX + 1 && y >= centerY - 1 && y <= centerY + 1;
                        }
                    }
                }
                
                return this;
            },
            /**
             * The error correction level and the id of the mask that has been
             * applied to the data matrix are encoded together as a 5 bit value.
             * This value gets 10 error correction bits appended to it, created
             * by a (15, 5) BCH code.  The final 15 bit format information
             * codeword has specific locations reserved for it within the
             * matrix.  QR Codes contain the format information twice for
             * additional redundancy.
             * @method drawFormatInformation
             * @chainable
             * @param {[Boolean]} matrix The array to write to.
             * @param {String} binaryString A string conatining 15 '1' or '0'
             * characters.
             * @param {Boolean} micro Set this to true for a Micro QR Code or
             * false for a QR Code.
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @param {Number} size The square root of the length of matrix.
             * @param {Boolean} overwrite When set to true, the format
             * information will replace any existing data in the matrix at that
             * location.
             */
            drawFormatInformation: function (matrix, binaryString, micro, quietZoneSize, size, overwrite) {
                var i,
                    index,
                    value,
                    x0 = quietZoneSize + 8,
                    x1 = size - quietZoneSize - 1,
                    y0 = quietZoneSize,
                    y1 = quietZoneSize + 8;
                
                if (micro) {
                    // Skip the timing pattern.
                    y0 += 1;
                }
                
                // Iterate through the binary string once.
                for (i = 0; i < 15; i += 1) {
                    value = binaryString.charAt(14 - i) === _string_1;
                    
                    index = x0 + y0 * size;
                    if (overwrite || _isUndefined(matrix[index])) {
                        matrix[index] = value;
                    }
                    
                    if (!micro) {
                        index = x1 + y1 * size;
                        if (overwrite || _isUndefined(matrix[index])) {
                            matrix[index] = value;
                        }
                    
                        if (i < 7) {
                            y0 += 1;

                            if (i === 5) {
                                // Skip the timing pattern.
                                y0 += 1;
                            }
                        } else {
                            x0 -= 1;

                            if (i === 8) {
                                // Skip the timing pattern.
                                x0 -= 1;
                            }
                        }

                        if (i < 7) {
                            x1 -= 1;
                        } else if (i === 7) {
                            x1 = quietZoneSize + 8;
                            y1 = size - quietZoneSize - 8;

                            index = x1 + y1 * size;
                            if (overwrite || _isUndefined(matrix[index])) {
                                // This position is always a dark value in QR Codes.
                                matrix[index] = true;
                            }

                            y1 += 1;
                        } else {
                            y1 += 1;
                        }
                    } else if (i < 7) {
                        y0 -= 1;
                    } else {
                        x0 -= 1;
                    }
                }
                
                return true;
            },
            /**
             * The quiet zone region is a padding of light values around the
             * outside of a QR Code.  It helps separate the QR Code from other
             * visual elements.
             * @method drawQuietZone
             * @chainable
             * @param {[Boolean]} matrix The array to write to.
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @param {Number} size The square root of the length of matrix.
             * @param {Boolean} overwrite When set to true, the quiet zone
             * region will replace any existing data in the matrix at that
             * location.
             */
            drawQuietZone: function (matrix, quietZoneSize, size, overwrite) {
                var farQuietZoneCoordinate = size - quietZoneSize,
                    index,
                    x,
                    y;
                    
                // Iterate through columns.
                for (x = 0; x < size; x += 1) {
                    // Write top padding.
                    for (y = 0; y < quietZoneSize; y += 1) {
                        index = x + y * size;
                        if (overwrite || _isUndefined(matrix[index])) {
                            matrix[index] = false;
                        }
                    }
                    
                    // Write left and right padding.
                    if (x < quietZoneSize || x >= farQuietZoneCoordinate) {
                        for (y = quietZoneSize; y < farQuietZoneCoordinate; y += 1) {
                            index = x + y * size;
                            if (overwrite || _isUndefined(matrix[index])) {
                                matrix[index] = false;
                            }
                        }
                    }
                    
                    // Write bottom padding.
                    for (y = farQuietZoneCoordinate; y < size; y += 1) {
                        index = x + y * size;
                        if (overwrite || _isUndefined(matrix[index])) {
                            matrix[index] = false;
                        }
                    }
                }
                
                return this;
            },
            /**
             * The timing pattern is a row and column of alternating dark and
             * light values.  The timing pattern allows decoders to determine
             * the version of the QR Code as well as the pixel density and
             * coordinate system.
             * @method drawTimingPattern
             * @chainable
             * @param {[Boolean]} matrix The array to write to.
             * @param {Number} coordinate The row and column index to write to.
             * @param {Number} size The square root of the length of matrix.
             * @param {Boolean} overwrite When set to true, the timing patter
             * will replace any existing data in the matrix at that location.
             */
            drawTimingPattern: function (matrix, coordinate, size, overwrite) {
                var i,
                    index;
                
                // TODO: Skip the quiet zone and finder pattern.
                for (i = 0; i < size; i += 1) {
                    // Write the vertical timing patter.
                    index = coordinate + i * size;
                    if (overwrite || _isUndefined(matrix[index])) {
                        matrix[index] = !(i % 2);
                    }
                    
                    // Write the horizontal timing pattern.
                    index = i + coordinate * size;
                    if (overwrite || _isUndefined(matrix[index])) {
                        matrix[index] = !(i % 2);
                    }
                }
                
                return this;
            },
            /**
             * QR Codes version 7 and higher contain the version number as a 6
             * bit value.  This value gets 12 error correction bits appended to
             * it, created by an (18, 6) Golay code.  The final 18 bit version
             * information codeword has specific locations reserved for it
             * within the matrix.  QR Codes contain the version information
             * twice for additional redundancy.
             * @method drawVersionInformation
             * @chainable
             * @param {[Boolean]} matrix The array to write to.
             * @param {String} binaryString A string conatining 18 '1' or '0'
             * characters.
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @param {Number} size The square root of the length of matrix.
             * @param {Boolean} overwrite When set to true, the version
             * information will replace any existing data in the matrix at that
             * location.
             */
            drawVersionInformation: function (matrix, binaryString, quietZoneSize, size, overwrite) {
                var i,
                    index,
                    value,
                    x0 = size - quietZoneSize - 11,
                    x1 = quietZoneSize,
                    y0 = quietZoneSize,
                    y1 = size - quietZoneSize - 11;
                    
                // Iterate through the binary string once.
                for (i = 17; i >= 0; i -= 1) {
                    value = binaryString.charAt(i) === _string_1;
                    
                    index = x0 + y0 * size;
                    if (overwrite || _isUndefined(matrix[index])) {
                        matrix[index] = value;
                    }
                    
                    index = x1 + y1 * size;
                    if (overwrite || _isUndefined(matrix[index])) {
                        matrix[index] = value;
                    }
                    
                    if (i % 3) {
                        x0 += 1;
                        y1 += 1;
                    } else {
                        x0 -= 2;
                        x1 += 1;
                        y0 += 1;
                        y1 -= 2;
                    }
                }
                
                return this;
            },
            /**
             * Several potential matrices are generated during the masking
             * process.  This method searches a matrix for negative features and
             * generates a penalty score.  This score is used to determine which
             * matrix to keep.
             * @method evaluateMatrix
             * @chainable
             * @param {[Boolean]} matrix The array to examine.
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @param {Number} size The square root of the length of matrix.
             * @param {Function} callbackFunction This function will be called
             * once the matrix has been evaluated.  It is guaranteed to be
             * called in a future turn of the event loop.  The score will be
             * passed as the only argument.
             */
            evaluateMatrix: function (matrix, quietZoneSize, size, callbackFunction) {
                var coordinate = size - quietZoneSize - 1,
                    evaluationRun = [],
                    score = 0,
                    total = 0,
                
                    evaluationFunction = function (success) {
                        _soon(function () {
                            var consecutiveHorizontalCount = 0,
                                consecutiveVerticalCount = 0,
                                index,
                                horizontalPatternIndex = 0,
                                maximumConsecutiveHorizontalCount = 0,
                                maximumConsecutiveVerticalCount = 0,
                                otherCoordinate,
                                pattern = [
                                    true,
                                    false,
                                    true,
                                    true,
                                    true,
                                    false,
                                    true
                                ],
                                previousHorizontalValue,
                                previousVerticalValue,
                                value,
                                verticalPatternIndex = 0;
                            
                            // Iterate through a row and column.
                            for (otherCoordinate = size - quietZoneSize - 1; otherCoordinate >= quietZoneSize; otherCoordinate -= 1) {
                                index = otherCoordinate + coordinate * size;
                                value = matrix[index];
                                
                                // Count consecutive similar values within the row.
                                if (value === previousHorizontalValue) {
                                    consecutiveHorizontalCount += 1;
                                } else {
                                    maximumConsecutiveHorizontalCount = _max(consecutiveHorizontalCount, maximumConsecutiveHorizontalCount);
                                    consecutiveHorizontalCount = 0;
                                    previousHorizontalValue = value;
                                }
                                
                                // Look for patterns that match the finder pattern and quiet zone region within the row.
                                if (value === pattern[horizontalPatternIndex]) {
                                    horizontalPatternIndex += 1;
                                    
                                    if (horizontalPatternIndex === 7 && (otherCoordinate >= quietZoneSize + 4 && !(matrix[index - 1] || matrix[index - 2] || matrix[index - 3] || matrix[index - 4])) || (otherCoordinate < size - quietZoneSize - 10 && !(matrix[index + 7] || matrix[index + 8] || matrix[index + 9] || matrix[index + 10]))) {
                                        // For each of these patterns that exist, add 40 points.
                                        score += 40;
                                    }
                                } else {
                                    horizontalPatternIndex = 0;
                                }
                                
                                // Search for blocks of similar values.
                                if (coordinate > quietZoneSize && otherCoordinate > quietZoneSize && matrix[index - 1] === value && matrix[index - size] === value && matrix[index - size - 1] === value) {
                                    // For each 2x2 block that exists, add 3 points.
                                    score += 3;
                                }
                                
                                // Count the number of dark values.
                                if (value) {
                                    total += 1;
                                }
                                
                                index = coordinate + otherCoordinate * size;
                                value = matrix[index];
                                
                                // Count consecutive similar values within the column.
                                if (value === previousVerticalValue) {
                                    consecutiveVerticalCount += 1;
                                } else {
                                    maximumConsecutiveVerticalCount = _max(consecutiveVerticalCount, maximumConsecutiveVerticalCount);
                                    consecutiveVerticalCount = 0;
                                    previousVerticalValue = value;
                                }
                                
                                // Look for patterns that match the finder pattern and quiet zone region within the colomn.
                                if (value === pattern[verticalPatternIndex]) {
                                    verticalPatternIndex += 1;
                                    
                                    if (verticalPatternIndex === 7 && (otherCoordinate >= quietZoneSize + 4 && !(matrix[index - size] || matrix[index - 2 * size] || matrix[index - 3 * size] || matrix[index - 4 * size])) || (otherCoordinate < size - quietZoneSize - 10 && !(matrix[index + 7 * size] || matrix[index + 8 * size] || matrix[index + 9 * size] || matrix[index + 10 * size]))) {
                                        // For each of these patterns that exist, add 40 points.
                                        score += 40;
                                    }
                                } else {
                                    verticalPatternIndex = 0;
                                }
                            }
                            
                            maximumConsecutiveHorizontalCount = _max(consecutiveHorizontalCount, maximumConsecutiveHorizontalCount);
                            
                            // If 5 consecutive values in a row are the same, add 3 points.
                            if (maximumConsecutiveHorizontalCount >= 5) {
                                // Add 1 point for each similar consecutive value beyond 5.
                                score += 3 + maximumConsecutiveHorizontalCount - 5;
                            }
                            
                            maximumConsecutiveVerticalCount = _max(consecutiveVerticalCount, maximumConsecutiveVerticalCount);
                            
                            // If 5 consecutive values in a column are the same, add 3 points.
                            if (maximumConsecutiveVerticalCount >= 5) {
                                // Add 1 point for each similar consecutive value beyond 5.
                                score += 3 + maximumConsecutiveVerticalCount - 5;
                            }
                            
                            coordinate -= 1;
                            success();
                        });
                    };
                
                _YAsync.runQueue(function (success) {
                    _soon(function () {
                        var i;
                        
                        // Prepare to iterate through the rows and columns of the matrix.
                        for (i = coordinate; i >= quietZoneSize; i -= 1) {
                            evaluationRun.push(evaluationFunction);
                        }
                        
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Iterate through the rows and columns of the matrix.
                        _YAsync.runQueue(evaluationRun).on(_string_complete, success);
                    });
                }).on(_string_complete, function () {
                    _soon(function () {
                        // Points are added to the score as the ratio of light and dark modules gets further from 1:1.
                        callbackFunction(score + 2 * _abs(_floor(100 * total / ((size - quietZoneSize) * (size - quietZoneSize)) - 50)));
                    });
                });
                
                return this;
            },
            /**
             * Several potential matrices are generated during the masking
             * process.  This method searches for dark values along the non
             * timing pattern edges.  Dark values along these edges make it
             * easier for decoders to determine the difference between data and
             * the quiet zone region.  The matrix is given a score used to
             * determine which matrix to keep.
             * @method evaluateMicroMatrix
             * @chainable
             * @param {[Boolean]} matrix The array to examine.
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @param {Number} size The square root of the length of matrix.
             * @param {Function} callbackFunction This function will be called
             * once the matrix has been evaluated.  It is guaranteed to be
             * called in a future turn of the event loop.  The score will be
             * passed as the only argument.
             */
            evaluateMicroMatrix: function (matrix, quietZoneSize, size, callbackFunction) {
                _soon(function () {
                    var bottomScore,
                        coordinate = size - quietZoneSize - 1,
                        otherCoordinate,
                        rightScore;
                        
                    // Iterate through edge values.
                    for (otherCoordinate = quietZoneSize + 1; otherCoordinate <= coordinate; otherCoordinate += 1) {
                        if (matrix[coordinate + otherCoordinate * size]) {
                            rightScore += 1;
                        }
                        
                        if (matrix[otherCoordinate + coordinate * size]) {
                            bottomScore += 1;
                        }
                    }
                    
                    if (bottomScore < rightScore) {
                        callbackFunction(bottomScore * 16 + rightScore);
                    } else {
                        callbackFunction(rightScore * 16 + bottomScore);
                    }
                });
                
                return this;
            },
            /**
             * This method formats the given data into the final binary string
             * used to create a data matrix.
             * @method formatBinaryString
             * @chainable
             * @param {String} binaryString A string of '1' and '0' characters.
             * @param {Function} callbackFunction This function will be called
             * once the binary string has been formated.  It is guaranteed to be
             * called in a future turn of the event loop.  If an error occurs,
             * the error message will be passed as the first argument.  The
             * formatted binary string is passed as the second argument.
             */
            formatBinaryString: function (binaryString, callbackFunction) {
                var blockCount,
                    blockRun = [],
                    blocks,
                    dataBlockLength,
                    dataBlockShiftIndex,
                    dataCodewords,
                    errorCorrectionBlockLength,
                    me = this,
                    missingCodewordCount,
                    
                    blockIterationFunction = function (dataBlockLength) {
                        return function (dataCodeword, index, dataCodewords) {
                            blockRun.push(function (success) {
                                _soon(function () {
                                    // Split the dataCodewords array into smaller blocks.
                                    var dataBlock = dataCodewords.slice(index, index + dataBlockLength);
                                    
                                    me.generateErrorCorrectionBlock(dataBlock, errorCorrectionBlockLength, function (errorCorrectionBlock) {
                                        success([
                                            dataBlock,
                                            errorCorrectionBlock
                                        ]);
                                    });
                                });
                            });
                        };
                    },
                    
                    interleaveCodewordsFunction = function (blocksIndex, codewordIndex) {
                        blockRun.push(function (success) {
                            _soon(function () {
                                success(_reduce(blocks, _string__empty, function (binaryString, blocks) {
                                    return binaryString + (blocks[blocksIndex][codewordIndex] || _string__empty);
                                }));
                            });
                        });
                    };
                
                _YAsync.runQueue(function (success) {
                    _soon(function () {
                        var codewordCount,
                            errorCorrection = me.get(_string_errorCorrection),
                            remainder,
                            version = _String(me.get(_string_version));

                        if (version.charAt(0) === _string_M) {
                            // Sanitize error correction value for Micro QR Codes.
                            if (version === _string_M1) {
                                errorCorrection = _string_E;
                            } else if (version !== _string_M4) {
                                if (errorCorrection === _string_H || errorCorrection === _string_Q) {
                                    errorCorrection = _string_M;
                                }
                            } else if (errorCorrection === _string_H) {
                                errorCorrection = _string_Q;
                            }
                            
                            // Append Micro QR Code terminator.
                            binaryString += _Array(2 + 2 * +version.charAt(1)).join(_string_0);
                        } else {
                            // Sanitize error correction for QR Codes.
                            if (errorCorrection === _string_E) {
                                errorCorrection = _string_L;
                            }
                            
                            // Append QR Code terminator.
                            binaryString += '0000';
                        }
                        
                        me._set(_string_errorCorrection, errorCorrection);

                        remainder = binaryString.length % 8;

                        // Pad with 0 bits to fill out remainder.
                        if (version === _string_M1 || version === _string_M3) {
                            // M1 and M3 versions end with a 4 bit codeword.
                            if (remainder < 4) {
                                binaryString += _Array(5 - remainder).join(_string_0);
                            } else if (remainder > 4) {
                                binaryString += _Array(13 - remainder).join(_string_0);
                            }
                        } else if (remainder) {
                            binaryString += _Array(9 - remainder).join(_string_0);
                        }

                        // Get info required to format binaryData.
                        codewordCount = _codewordCount[version][errorCorrection];
                        blockCount = codewordCount[1];
                        dataBlockLength = codewordCount[2];
                        dataBlockShiftIndex = blockCount * dataBlockLength;
                        errorCorrectionBlockLength = codewordCount[3];
                        codewordCount = codewordCount[0];

                        missingCodewordCount = codewordCount - _ceil(binaryString.length / 8);

                        if (missingCodewordCount < 0) {
                            success.fail('Too much data.');
                        } else {
                            success();
                        }
                    });
                }, function (success) {
                    _soon(function () {
                        // Add padding codewords to fill up available space.
                        var i;
                        
                        for (i = 0; i < missingCodewordCount; i += 1) {
                            binaryString += (i % 2) ? '00010001' : '11101100';
                        }
                        
                        // Split the binary string into an array of codewords.
                        dataCodewords = binaryString.match(/.{1,8}/g);
                        binaryString = _string__empty;
                        
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Get ready to generate the first group of data blocks and error correction blocks.
                        _iterate(dataCodewords.slice(0, dataBlockShiftIndex), dataBlockLength, blockIterationFunction(dataBlockLength));
                        // The second group of blocks contains an extra codeword.
                        dataBlockLength += 1;
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Get ready to generate the second group of data blocks and error correction blocks.
                        _iterate(dataCodewords.slice(dataBlockShiftIndex), dataBlockLength, blockIterationFunction(dataBlockLength));
                        dataCodewords = null;
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Generate data blocks and error correction blocks.
                        _YAsync.runAll(blockRun).on(_string_complete, function (eventFacade) {
                            blockRun = [];
                            blocks = eventFacade.value;
                            success();
                        });
                    });
                }, function (success) {
                    _soon(function () {
                        var i;
                        
                        // Get ready to interleave data block codewords.
                        for (i = 0; i < dataBlockLength; i += 1) {
                            interleaveCodewordsFunction(0, i);
                        }
                        
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        var i;
                        
                        // Get ready to interleave error correction block codewords.
                        for (i = 0; i < errorCorrectionBlockLength; i += 1) {
                            interleaveCodewordsFunction(1, i);
                        }
                        
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Interleave codewords.
                        _YAsync.runAll(blockRun).on(_string_complete, function (eventFacade) {
                            binaryString = eventFacade.value.join(_string__empty);
                            success();
                        });
                    });
                }).on(_string_complete, function (eventFacade) {
                    _soon(function () {
                        if (eventFacade.failed) {
                            callbackFunction(eventFacade.error);
                        } else {
                            callbackFunction(null, binaryString);
                        }
                    });
                });
                
                return me;
            },
            /**
             * Generate a QR Code matrix.
             * @method generate
             * @chainable
             * @param {Function} callbackFunction This function will be called
             * once the matrix has been generated.  It is guaranteed to be
             * called in a future turn of the event loop.  If an error occurs,
             * the error message will be passed as the first argument.  The
             * matrix is passed as the second argument.  The square root of the
             * length of the matrix is passed as the third argument.
             */
            generate: function (callbackFunction) {
                var data,
                    me = this;
                
                _YAsync.runQueue(function (success) {
                    _soon(function () {
                        // Get the initial data.
                        me.getBinaryString(function (binaryString) {
                            data = binaryString;
                            success();
                        });
                    });
                }, function (success) {
                    _soon(function () {
                        // Format the data.
                        me.formatBinaryString(data, function (error, binaryString) {
                            if (error) {
                                success.fail(error);
                            } else {
                                data = binaryString;
                                success();
                            }
                        });
                    });
                }, function (success) {
                    _soon(function () {
                        // Generate the matrix.
                        me.generateMatrix(data, function (matrix, size) {
                            data = [
                                matrix,
                                size
                            ];
                            success();
                        });
                    });
                }).on(_string_complete, function (eventFacade) {
                    _soon(function () {
                        if (eventFacade.failed) {
                            callbackFunction(eventFacade.error);
                        } else {
                            callbackFunction(null, data[0], data[1]);
                        }
                    });
                });
                
                return me;
            },
            /**
             * This method creates a new matrix containing only raw data bits.
             * @method generateDataMatrix
             * @chainable
             * @param {[Boolean]} matrix An array without any data bits defined.
             * This matrix is only used to position data bits around other
             * features that are already present.  This matrix is not modified.
             * @param {String} binaryString A string of '1' and '0' characters.
             * @param {Number} coordinate The coordinate of the vertical timing
             * pattern.
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @param {Number} size The square root of the length of matrix.
             * @param {Function} callbackFunction This function will be called
             * once the dataMatrix has been generated.  It is guaranteed to be
             * called in a future turn of the event loop.  The dataMatrix is
             * passed as the only argument.
             */
            generateDataMatrix: function (matrix, binaryString, coordinate, quietZoneSize, size, callbackFunction) {
                // Split the binary string into 8 bit codewords.
                var codewords = binaryString.match(/.{1,8}/g),
                    dataMatrix = _Array(matrix.length),
                    direction = 1,
                    drawColumnRun = [],
                    i,
                    x = size - quietZoneSize - 1,
                    
                    codeword = codewords.shift(),
                    codewordIndex = 0,
                    
                    drawCodewordBit = function (index) {
                        if (codewordIndex > 7) {
                            codeword = codewords.shift();
                            codewordIndex = 0;
                        }
                        
                        dataMatrix[index] = codeword && codeword.charAt(codewordIndex) === _string_1 || false;
                        codewordIndex += 1;
                    },
                    
                    drawColumnFunction = function (success) {
                        _soon(function () {
                            var index,
                                y;
                                
                            // Iterate through rows in the current direction.
                            for (y = direction ? size - quietZoneSize - 1 : quietZoneSize; direction && y >= quietZoneSize || !direction && y < size - quietZoneSize; y += (direction ? -1 : 1)) {
                                // Write to the right column first if available.
                                index = x + y * size;
                                if (_isUndefined(matrix[index])) {
                                    drawCodewordBit(index);
                                }
                                
                                // Write to the left column if available.
                                index -= 1;
                                if (_isUndefined(matrix[index])) {
                                    drawCodewordBit(index);
                                }
                            }
                            
                            // Change directions at the end of the column.
                            direction = !direction;
                            x -= 2;
                            
                            // Skip the vertical timing pattern.
                            if (x === coordinate) {
                                x -= 1;
                            }
                            
                            success();
                        });
                    };
                    
                binaryString = _string__empty;
                
                // Prepare to iterate through columns, two at a time.
                for (i = quietZoneSize; i <= x; i += 2) {
                    drawColumnRun.push(drawColumnFunction);
                }
                
                // Iterate through columns, two at a time.
                _YAsync.runQueue(drawColumnRun).on(_string_complete, function () {
                    _soon(function () {
                        callbackFunction(dataMatrix);
                    });
                });
                
                return this;
            },
            /**
             * Generates a block of error correction codewords based on a block
             * of data codewords.
             * @method generateErrorCorrectionBlock
             * @chainable
             * @param {[String]} dataBlock Array of strings of '1' and '0'
             * characters, 8 characters long each.
             * @param {Number} errorCorrectionBlockLength The number of 8 bit
             * codewords to generate in the error correction block.
             * @param {Function} callbackFunction This function will be called
             * once the error correction block has been generated.  It is
             * guaranteed to be called in a future turn of the event loop. The
             * error correction block is passed as the only argument.
             */
            generateErrorCorrectionBlock: function (dataBlock, errorCorrectionBlockLength, callbackFunction) {
                var coefficientRun = [],
                    errorCorrectionBlock,
                    generatorAlphaIndicies = _generatorAlphaIndicies[errorCorrectionBlockLength],
                    polynomialAlphaIndicies,
                    
                    coefficientIterationFunction = function (success) {
                        _soon(function () {
                            // Remove the first coefficient.
                            var leadingPolynomialAlphaIndex = polynomialAlphaIndicies.shift();
                            
                            if (leadingPolynomialAlphaIndex) {
                                // Iterate the generator and process the remaining polynomial coefficients.
                                _each(generatorAlphaIndicies, function (generatorAlphaIndex, index) {
                                    var alphaIndex = _cachedIndexOf(_alpha, _alpha[(generatorAlphaIndex + leadingPolynomialAlphaIndex) % 255] ^ (_alpha[polynomialAlphaIndicies[index]] || 0));
                                    polynomialAlphaIndicies[index] = alphaIndex === -1 ? null : alphaIndex;
                                });
                            }
                            
                            success();
                        });
                    };
                    
                _YAsync.runQueue(function (success) {
                    _soon(function () {
                        // Create the polynomial.
                        polynomialAlphaIndicies = _map(dataBlock, function (binaryCodeword) {
                            var alphaIndex = _cachedIndexOf(_alpha, _parseInt(binaryCodeword, 2));
                            return alphaIndex === -1 ? null : alphaIndex;
                        }).concat(_Array(errorCorrectionBlockLength));
                        
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        var dataBlockLength = dataBlock.length,
                            i;
                        
                        // Prepare to process the polynomial with the generator.
                        for (i = 0; i < dataBlockLength; i += 1) {
                            coefficientRun.push(coefficientIterationFunction);
                        }
                        
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Process the polynomial with the generator.
                        _YAsync.runQueue(coefficientRun).on(_string_complete, success);
                    });
                }, function (success) {
                    _soon(function () {
                        // Read error correction codewords from the remaining coefficients.
                        errorCorrectionBlock = _map(polynomialAlphaIndicies, function (alphaIndex) {
                            return _numberToBinaryString(_alpha[alphaIndex] || 0, 8);
                        });
                        success();
                    });
                }).on(_string_complete, function () {
                    _soon(function () {
                        callbackFunction(errorCorrectionBlock);
                    });
                });
                
                return this;
            },
            /**
             * Generates a matrix which represents the given data.
             * @method generateMatrix
             * @chainable
             * @param {String} binaryString A string of '1' and '0' characters.
             * @param {Function} callbackFunction This function will be called
             * once the matrix has been generated.  It is guaranteed to be
             * called in a future turn of the event loop.  The matrix is passed
             * as the first argument.  The square root of the length of the
             * matrix is passed as the second argument.
             */
            generateMatrix: function (binaryString, callbackFunction) {
                var me = this,
                    size = me.getSize(),
                    version = _String(me.get(_string_version)),
                    
                    formatInformation,
                    initialDataMatrix,
                    mask = me.get('mask'),
                    matrix = _Array(size * size),
                    micro = version.charAt(0) === _string_M,
                    quietZoneSize = micro ? 2 : 4;
                    
                _YAsync.runQueue(function (success) {
                    _soon(function () {
                        // Write the quiet zone region.
                        me.drawQuietZone(matrix, quietZoneSize, size);
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Write the upper left finder pattern.
                        var coordinate = quietZoneSize + 3;
                        me.drawFinderPattern(matrix, coordinate, coordinate, size);
                        success();
                    });
                }, function (success) {
                    if (micro) {
                        success();
                    } else {
                        _soon(function () {
                            // Write the upper right finder pattern.
                            me.drawFinderPattern(matrix, size - quietZoneSize - 4, quietZoneSize + 3, size);
                            success();
                        });
                    }
                }, function (success) {
                    if (micro) {
                        success();
                    } else {
                        _soon(function () {
                            // Write the lower left finder pattern.
                            me.drawFinderPattern(matrix, quietZoneSize + 3, size - quietZoneSize - 4, size);
                            success();
                        });
                    }
                }, function (success) {
                    _soon(function () {
                        // Write the timing pattern.
                        me.drawTimingPattern(matrix, micro ? 2 : 10, size);
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        var alignmentPatternRun = [];
                        
                        // Prepare to write the alignment patterns.
                        _each(me.getAlignmentPatternCoordinates(quietZoneSize), function (alignmentPatternCoordinates) {
                            alignmentPatternRun.push(function (success) {
                                _soon(function () {
                                    me.drawAlignmentPattern(matrix, alignmentPatternCoordinates[0], alignmentPatternCoordinates[1], size);
                                    success();
                                });
                            });
                        });
                        
                        // Write the alignment patterns
                        _YAsync.runAll(alignmentPatternRun).on(_string_complete, success);
                    });
                }, function (success) {
                    if (micro || +version < 7) {
                        // Versions less than 7 do not encode version information.
                        success();
                    } else {
                        _soon(function () {
                            // Write the version information.
                            me.drawVersionInformation(matrix, _numberToBinaryString(_versionInformation[+version - 7], 18), quietZoneSize, size);
                            success();
                        });
                    }
                }, function (success) {
                    _soon(function () {
                        // The format information hasn't been determined yet.
                        // Write empty format information to the matrix for now so that
                        // all of the non data bits are defined.
                        me.drawFormatInformation(matrix, _Array(16).join(_string_0), micro, quietZoneSize, size);
                        success();
                    });
                }, function (success) {
                    _soon(function () {
                        // Generate the initial data matrix.
                        me.generateDataMatrix(matrix, binaryString, micro ? 2 : 10, quietZoneSize, size, function (dataMatrix) {
                            initialDataMatrix = dataMatrix;
                            success();
                        });
                    });
                }, function (success) {
                    _soon(function () {
                        // Generate an array of matrix candidates by running
                        // the data through different mask operations.
                        _YAsync.runQueue(_map(micro ? _microMaskFunctions : _maskFunctions, function (maskFunction, index) {
                            return (mask === null || mask === index) && function (success) {
                                _soon(function () {
                                    me.applyMask(matrix.concat(), initialDataMatrix, maskFunction, quietZoneSize, size, success);
                                });
                            } || function (success) {
                                // If mask is already defined, don't waste time generating extra matrices.
                                success();
                            };
                        })).on(_string_complete, function (eventFacade) {
                            var matrices = eventFacade.value;
                            
                            // Evaluate each matrix candidate.
                            _YAsync.runAll(_map(matrices, function (matrix) {
                                return function (success) {
                                    _soon(function () {
                                        if (micro) {
                                            if (matrix) {
                                                me.evaluateMicroMatrix(matrix, quietZoneSize, size, success);
                                            } else {
                                                // This matrix wasn't defined, give it an impossibly low score.
                                                success(-1);
                                            }
                                        } else if (matrix) {
                                            me.evaluateMatrix(matrix, quietZoneSize, size, success);
                                        } else {
                                            // This matrix wasn't defined, give it an impossibly high score.
                                            success(Infinity);
                                        }
                                    });
                                };
                            })).on(_string_complete, function (eventFacade) {
                                var bestIndex,
                                    errorCorrection = me.get(_string_errorCorrection),
                                    values = eventFacade.value;
                                 
                                if (micro) {
                                    // For Micro QR Codes, points are awarded for positive features.
                                    // Accept the matrix with the highest score.
                                    bestIndex = _indexOf(values, _max.apply(Math, values));
                                    
                                    // The error correction mode becomes part of the format information.
                                    // Each version has a different way of encoding the error correction mode.
                                    switch (version) {
                                        case _string_M1:
                                            formatInformation = 0;
                                            break;
                                        case 'M2':
                                            formatInformation = 1;
                                            break;
                                        case _string_M3:
                                            formatInformation = 3;
                                            break;
                                        case _string_M4:
                                            formatInformation = 5;
                                            break;
                                    }
                                    
                                    if (errorCorrection === _string_M) {
                                        formatInformation += 1;
                                    } else if (errorCorrection === _string_Q) {
                                        formatInformation += 2;
                                    }
                                    
                                    // The error correction mode and the index of the mask used in the best matrix
                                    // are combined to form the 15 bit format information codeword.
                                    formatInformation = _numberToBinaryString(_microFormatInformation[_parseInt(_numberToBinaryString(formatInformation, 3) + _numberToBinaryString(bestIndex, 2), 2)], 15);
                                } else {
                                    // For QR Codes, penalty points are given for negative features.
                                    // Accept the matrix with the lowest score.
                                    bestIndex = _indexOf(values, _min.apply(Math, values));
                                    
                                    // The error correction mode becomes part of the format information.
                                    switch (errorCorrection) {
                                        case _string_H:
                                            formatInformation = _string_10;
                                            break;
                                        case _string_L:
                                            formatInformation = '01';
                                            break;
                                        case _string_M:
                                            formatInformation = '00';
                                            break;
                                        case _string_Q:
                                            formatInformation = '11';
                                            break;
                                    }
                                    
                                    // The error correction mode and the index of the mask used in the best matrix
                                    // are combined to form the 15 bit format information codeword.
                                    formatInformation = _numberToBinaryString(_formatInformation[_parseInt(formatInformation + _numberToBinaryString(bestIndex, 3), 2)], 15);
                                }
                                
                                matrix = matrices[bestIndex];
                                success();
                            });
                        });
                    });
                }, function (success) {
                    _soon(function () {
                        // Write the format information, replacing the placeholder bits that were set earlier.
                        me.drawFormatInformation(matrix, formatInformation, micro, quietZoneSize, size, true);
                        success();
                    });
                }).on(_string_complete, function () {
                    _soon(function () {
                        callbackFunction(matrix, size);
                    });
                });
                
                return me;
            },
            /**
             * Each QR Code version has specific requirements for the position
             * of alignment patterns.  This method returns the center position
             * of each required alignment pattern.
             * @method getAlignmentPatternCoordinates
             * @param {Number} quietZoneSize The size of the quiet zone region.
             * @return {[[x, y]]}
             */
            getAlignmentPatternCoordinates: function (quietZoneSize) {
                var version = _String(this.get(_string_version)),
                
                    alignmentPatternCoordinates = [],
                    alignmentPatternLocation = [
                        6
                    ].concat(_alignmentPatternLocations[+version - 2]),
                    alignmentPatternLocationLengthMinusOne = alignmentPatternLocation.length - 1;
                
                if (version.charAt(0) === _string_M || version === _string_1) {
                    return [];
                }

                _each(alignmentPatternLocation, function (x, xIndex) {
                    _each(alignmentPatternLocation, function (y, yIndex) {
                        if ((xIndex || yIndex) && (xIndex || yIndex !== alignmentPatternLocationLengthMinusOne) && (xIndex !== alignmentPatternLocationLengthMinusOne || yIndex)) {
                            alignmentPatternCoordinates.push([
                                quietZoneSize + x,
                                quietZoneSize + y
                            ]);
                        }
                    });
                });

                return alignmentPatternCoordinates;
            },
            /**
             * Converts the value of the data attribute
             * to a string of '1' and '0' characters.
             * @method getBinaryString
             * @chainable
             * @param {Function} callbackFunction This function will be called
             * once the binary string has been created.  It is guaranteed to be
             * called in a future turn of the event loop. The binary string is
             * passed as the only argument.
             */
            getBinaryString: function (callbackFunction) {
                var me = this,
                    version = me.get(_string_version);
                
                _YAsync.runAll(_map(me.get('data'), function (data) {
                    return function (success) {
                        _soon(function () {
                            success(data.toBinaryString(version));
                        });
                    };
                })).on(_string_complete, function (eventFacade) {
                    _soon(function () {
                        callbackFunction(eventFacade.value.join(_string__empty));
                    });
                });
                
                return me;
            },
            /**
             * Returns the proper size of a matrix for this version.
             * @method getSize
             * @return {Number}
             */
            getSize: function () {
                var version = _String(this.get(_string_version));

                if (version.charAt(0) === _string_M) {
                    return 12 + (+version.charAt(1)) * 3;
                }

                return 25 + (+version) * 4;
            }
        }, {
            ATTRS: {
                /**
                 * Input data must be wrapped up in data objects.  A single data
                 * object or an array is acceptable.  Data objects are
                 * responsible for encoding raw values into one of the data
                 * encoding modes supported by QR codes.
                 * @attribute data
                 * @default []
                 * @initOnly
                 * @type Array
                 */
                data: {
                    setter: function (value) {
                        if (!_isArray(value)) {
                            value = [
                                value
                            ];
                        }
                        
                        return value;
                    },
                    value: [],
                    writeOnce: _string_initOnly
                },
                /**
                 * QR Codes use error correction when encoding data.  Error
                 * correction allows a code to be successfully scanned even if
                 * part of the code is damaged, missing, or scanned incorrectly.
                 * There are four different error correction modes.
                 * Mode H can recover from 30% data loss.
                 * Mode L can recover from 7% data loss.
                 * Mode M can recover from 15% data loss.
                 * Mode Q can recover from 25% data loss.
                 * The more error correction added, the less data the QR Code
                 * can hold.
                 * @attribute errorCorrection
                 * @default 'M',
                 * @initOnly
                 * @type String
                 */
                errorCorrection: {
                    validator: function (value) {
                        if (value === _string_E || value === _string_H || value === _string_L || value === _string_M || value === _string_Q) {
                            return true;
                        }
                        
                        return false;
                    },
                    value: _string_M,
                    writeOnce: _string_initOnly
                },
                /**
                 * QR Codes apply one of eight possible masks to the raw data
                 * matrix.  Decoders benefit when a mask is used to reduce the
                 * occurence of ambiguous patterns within the data matrix.  When
                 * this attribute is set to null, the data matrix will be have
                 * all 8 masks applied to it.  Each one will be evaluated and
                 * the one with the fewest ambiguous patterns will be used.
                 * When this attribute is set to a value from 0 to 7, only that
                 * specific mask will be applied and used.  This improves the
                 * performace of the encoding process by cutting out a complex
                 * step but manually selecting a mask is not recommended because
                 * it can negatively affect decoder performance and/or accuracy.
                 * Using different masks on the same data can result in QR Codes
                 * that appear very different, so some choose to select a mask
                 * for aesthetic reasons.
                 * @attribute mask
                 * @default null
                 * @initOnly
                 * @type Number
                 */
                mask: {
                    value: null,
                    writeOnce: _string_initOnly
                },
                /**
                 * There are 40 different versions of QR Codes. A QR Code's
                 * version is just a confusing way to specify how big it is.  A
                 * version 1 QR Code is a 25x25 grid.  That size increases by 4
                 * up to the 181x181 grid of a version 40 QR code.  The larger
                 * the grid, the more data the QR Code can hold.
                 * @attribute version
                 * @default '1'
                 * @initOnly
                 * @type String
                 */
                version: {
                    value: _string_1,
                    writeOnce: _string_initOnly
                }
            }
        }),
        
        /**
         * This class encodes a value in alphanumeric mode.  Alphanumeric mode
         * encodes strings containing only numeric characters, capital-letter
         * characters, space, dollar sign, percent sign, asterisk, plus sign,
         * hyphen-minus, full stop, solidus, and colon.
         * 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:
         * @class AlphanumericData
         * @constructor
         * @extends QrCode.Data
         * @namespace QrCode
         * @param {Object} config Configuration object.
         */
        _AlphanumericData = _YBase.create('qr-code-alphanumeric-data', _Data, [], {
            /**
             * Returns a properly formatted binary string for alphanumeric data.
             * @method toBinaryString
             * @for QrCode.AlphanumericData
             * @param {Number|String} version
             * @return {String}
             */
            toBinaryString: function (version) {
                version = _String(version);
                
                var characterCountIndicatorBitLength,
                    characters = [
                        ' ',
                        '$',
                        '%',
                        '*',
                        '+',
                        '-',
                        '.',
                        '/',
                        ':'
                    ],
                    modeIndicator,
                    value = this.get(_string_value),
                    // Split the string into 2-character chunks.
                    valueBinaryString = _reduce(value.match(/.{1,2}/g), _string__empty, function (binaryString, value) {
                        var character = value.charAt(0),
                            characterIndex = _indexOf(characters, character),
                            characterValue;
                            
                        // Assign a value to the first character.
                        if (characterIndex === -1) {
                            characterValue = _parseInt(character, 36);
                        } else {
                            characterValue = characterIndex + 36;
                        }
                        
                        // If the last chunk only contains one character, append its value as a 6 bit binary string.
                        if (value.length === 1) {
                            return binaryString + _numberToBinaryString(characterValue, 6);
                        }
                        
                        characterValue *= 45;
                        
                        // Assign a value to the second character.
                        character = value.charAt(1);
                        characterIndex = _indexOf(characters, character);
                        
                        if (characterIndex === -1) {
                            characterValue += _parseInt(character, 36);
                        } else {
                            characterValue += characterIndex + 36;
                        }
                        
                        // Append the sum of the two character values as an 11 bit binary string.
                        return binaryString + _numberToBinaryString(characterValue, 11);
                    });
                
                // The mode indicator value and the bit length of the character count indicator depend on the version.
                if (version.charAt(0) === _string_M) {
                    version = +version.charAt(1);
                    characterCountIndicatorBitLength = version + 1;
                    modeIndicator = _Array(version - 1).join(0) + _string_1;
                } else {
                    version = +version;
                    
                    if (version <= 9) {
                        characterCountIndicatorBitLength = 9;
                    } else if (version <= 26) {
                        characterCountIndicatorBitLength = 11;
                    } else {
                        characterCountIndicatorBitLength = 13;
                    }
                    
                    modeIndicator = '0010';
                }
                
                return modeIndicator + _numberToBinaryString(value.length, characterCountIndicatorBitLength) + valueBinaryString;
            }
        }, {
            ATTRS: {
                /**
                 * @attribute type
                 * @default 'alphanumeric'
                 * @readOnly
                 * @type String
                 */
                type: {
                    readOnly: true,
                    value: _string_alphanumeric
                },
                /**
                 * @attribute value
                 * @initOnly
                 * @type Number|String
                 */
                value: {
                    setter: function (value) {
                        return _String(value).toUpperCase().replace(/[^0-9A-Z $%*+\-.\/:]/g, _string__empty);
                    },
                    value: _string__empty,
                    writeOnce: _string_initOnly
                }
            }
        }),
        
        /**
         * This class encodes a value in byte mode.  Byte mode encodes strings
         * as raw binary data.
         * @class ByteData
         * @constructor
         * @extends QrCode.Data
         * @namespace QrCode
         * @param {Object} config Configuration object.
         */
        _ByteData = _YBase.create('qr-code-byte-data', _Data, [], {
            /**
             * Returns a properly formatted binary string for byte data.
             * @method toBinaryString
             * @for QrCode.ByteData
             * @param {Number|String} version
             * @return {String}
             */
            toBinaryString: function (version) {
                version = _String(version);
                
                var characterCountIndicatorBitLength,
                    characterWidth = this.get('characterWidth'),
                    i,
                    length,
                    modeIndicator,
                    value = this.get(_string_value),
                    valueBinaryString = _string__empty;
                    
                for (i = 0, length = value.length; i < length; i += 1) {
                    valueBinaryString += _numberToBinaryString(value.charCodeAt(i), characterWidth);
                }
                
                // The mode indicator value and the bit length of the character count indicator depend on the version.
                if (version.charAt(0) === _string_M) {
                    version = +version.charAt(1);
                    characterCountIndicatorBitLength = version + 1;
                    modeIndicator = _Array(version - 2).join(0) + _string_10;
                } else {
                    version = +version;
                    
                    if (version <= 9) {
                        characterCountIndicatorBitLength = 8;
                    } else {
                        characterCountIndicatorBitLength = 16;
                    }
                    
                    modeIndicator = '0100';
                }
                
                return modeIndicator + _numberToBinaryString(valueBinaryString.length / 8, characterCountIndicatorBitLength) + valueBinaryString;
            }
        }, {
            ATTRS: {
                /**
                 * The number of bits used to encode each character.
                 * @attribute characterWidth
                 * @default 8
                 * @initOnly
                 * @type Number
                 */
                characterWidth: {
                    value: 8,
                    writeOnce: _string_initOnly
                },
                /**
                 * @attribute type
                 * @default 'byte'
                 * @readOnly
                 * @type String
                 */
                type: {
                    readOnly: true,
                    value: 'byte'
                },
                /**
                 * @attribute value
                 * @initOnly
                 * @type Number|String
                 */
                value: {
                    value: _string__empty,
                    writeOnce: _string_initOnly
                }
            }
        }),
        
        /**
         * This class encodes a value in numeric mode.  Numeric mode encodes
         * strings containing only numeric characters.
         * 0123456789
         * @class NumericData
         * @constructor
         * @extends QrCode.Data
         * @namespace QrCode
         * @param {Object} config Configuration object.
         */
        _NumericData = _YBase.create('qr-code-numeric-data', _Data, [], {
            /**
             * Returns a properly formatted binary string for numeric data.
             * @method toBinaryString
             * @for QrCode.NumericData
             * @param {Number|String} version
             * @return {String}
             */
            toBinaryString: function (version) {
                version = _String(version);
                
                var characterCountIndicatorBitLength,
                    modeIndicator,
                    value = this.get(_string_value),
                    // Split the string into 3-character chunks
                    valueBinaryString = _reduce(value.match(/.{1,3}/g), _string__empty, function (binaryString, value) {
                        // Convert 3-character chunks into 10 bit binary strings.
                        // If the last chunk only contains 1 or 2 characters, convert it to a 4 or 7 bit binary string.
                        // Concatenate the binary strings.
                        return binaryString + _numberToBinaryString(value, value.length >= 3 ? 10 : (value.length <= 1 ? 4 : 7));
                    });
                
                // The mode indicator value and the bit length of the character count indicator depend on the version.
                if (version.charAt(0) === _string_M) {
                    version = +version.charAt(1);
                    characterCountIndicatorBitLength = version + 2;
                    modeIndicator = _Array(version).join(0);
                } else {
                    version = +version;
                    
                    if (version <= 9) {
                        characterCountIndicatorBitLength = 10;
                    } else if (version <= 26) {
                        characterCountIndicatorBitLength = 12;
                    } else {
                        characterCountIndicatorBitLength = 14;
                    }
                    
                    modeIndicator = '0001';
                }
                
                return modeIndicator + _numberToBinaryString(value.length, characterCountIndicatorBitLength) + valueBinaryString;
            }
        }, {
            ATTRS: {
                /**
                 * @attribute type
                 * @default 'numeric'
                 * @readOnly
                 * @type String
                 */
                type: {
                    readOnly: true,
                    value: _string_numeric
                },
                /**
                 * @attribute value
                 * @initOnly
                 * @type Number|String
                 */
                value: {
                    setter: function (value) {
                        return _String(value).replace(/[\D]/g, _string__empty);
                    },
                    value: _string__empty,
                    writeOnce: _string_initOnly
                }
            }
        }),
        
        /**
         * This class sets the extended channel interpretation mode indicator
         * for the ucs2 character set.  While this is a Data object, it does not
         * directly encode data.  Instead, it sets a flag in the data stream
         * which tells a decoder how to interpret the data that follows.  Ucs2
         * is an interesting character set because JavaScript strings are
         * handled in ucs2.  Combined with the ByteData object and a character
         * width set to 16, any JavaScript string can be precisely encoded.
         * Unfortunately it appears that many decoders lack support for the ucs2
         * character set.  Android's standard Barcode Scanner application does
         * provide support, but the font used to display the result is not able
         * to render the entire range of unicode characters.
         * @class Ucs2Data
         * @constructor
         * @extends QrCode.Data
         * @namespace QrCode
         * @param {Object} config Configuration object.
         */
        _Ucs2Data = _YBase.create('qr-code-ucs2-data', _Data, [], {
            /**
             * Returns a properly formatted binary string for ucs2 data.
             * @method toBinaryString
             * @for QrCode.Ucs2Data
             * @param {Number|String} version
             * @return {String}
             */
            toBinaryString: function (version) {
                return '011100011001';
            }
        }, {
            ATTRS: {
                /**
                 * @attribute type
                 * @default 'ucs2'
                 * @readOnly
                 * @type String
                 */
                type: {
                    readOnly: true,
                    value: _string_ucs2
                },
                /**
                 * This object does not require a value.
                 * @attribute value
                 * @default ''
                 * @readOnly
                 * @type Number|String
                 */
                value: {
                    readOnly: true,
                    value: _string__empty
                }
            }
        }),
        
        /**
         * This class sets the extended channel interpretation mode indicator
         * for the utf8 character set.  While this is a Data object, it does not
         * directly encode data.  Instead, it sets a flag in the data stream
         * which tells a decoder how to interpret the data that follows.  Utf8
         * is a widely supported character set, so this may be a good choice if
         * you need to encode characters that are not supported in alphanumeric
         * mode.  Note that JavaScript strings do not use utf8 characters.  This
         * module does not provide the functionality required to convert
         * characters to utf8.
         * @class Utf8Data
         * @constructor
         * @extends QrCode.Data
         * @namespace QrCode
         * @param {Object} config Configuration object.
         */
        _Utf8Data = _YBase.create('qr-code-utf8-data', _Data, [], {
            /**
             * Returns a properly formatted binary string for utf8 data.
             * @method toBinaryString
             * @for QrCode.Utf8Data
             * @param {Number|String} version
             * @return {String}
             */
            toBinaryString: function (version) {
                return '011100011010';
            }
        }, {
            ATTRS: {
                /**
                 * @attribute type
                 * @default 'utf8'
                 * @readOnly
                 * @type String
                 */
                type: {
                    readOnly: true,
                    value: _string_ucs2
                },
                /**
                 * This object does not require a value.
                 * @attribute value
                 * @default ''
                 * @readOnly
                 * @type Number|String
                 */
                value: {
                    readOnly: true,
                    value: _string__empty
                }
            }
        });
    
    /**
     * Converts a decimal non-negative integer to a string containing '1' and
     * '0' characters.  If the number does not fit within the given length, null
     * is returned.  If the number is smaller than the given length, it is
     * padded with '0' and a string with the given length is returned.
     * @method numberToBinaryString
     * @for QrCode
     * @param {Number} number
     * @param {Number} length
     * @return {String}
     * @static
     */
    _numberToBinaryString = function (number, length) {
        number = (+number).toString(2);
        
        var numberLength = number.length;
        if (numberLength > length) {
            return null;
        }
        
        return _Array(length - numberLength + 1).join(0) + number;
    };
    
    _mix(Y.namespace('QrCode'), {
        AlphanumericData: _AlphanumericData,
        ByteData: _ByteData,
        Data: _Data,
        GeneratorBase: _GeneratorBase,
        NumericData: _NumericData,
        numberToBinaryString: _numberToBinaryString,
        Ucs2Data: _Ucs2Data,
        Utf8Data: _Utf8Data
    });
}(Y));