/**
* 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));