barby 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/bin/barby +40 -0
  2. data/lib/barby.rb +3 -0
  3. data/lib/barby/barcode.rb +6 -0
  4. data/lib/barby/barcode/code_128.rb +16 -3
  5. data/lib/barby/barcode/code_25.rb +161 -0
  6. data/lib/barby/barcode/code_25_interleaved.rb +73 -0
  7. data/lib/barby/barcode/code_93.rb +225 -0
  8. data/lib/barby/barcode/qr_code.rb +93 -0
  9. data/lib/barby/outputter.rb +56 -2
  10. data/lib/barby/outputter/ascii_outputter.rb +20 -1
  11. data/lib/barby/outputter/cairo_outputter.rb +38 -7
  12. data/lib/barby/outputter/pdfwriter_outputter.rb +44 -35
  13. data/lib/barby/outputter/png_outputter.rb +48 -16
  14. data/lib/barby/outputter/prawn_outputter.rb +100 -0
  15. data/lib/barby/outputter/rmagick_outputter.rb +48 -20
  16. data/lib/barby/vendor.rb +3 -0
  17. data/vendor/rqrcode/CHANGELOG +21 -0
  18. data/vendor/rqrcode/COPYING +19 -0
  19. data/vendor/rqrcode/README +98 -0
  20. data/vendor/rqrcode/Rakefile +65 -0
  21. data/vendor/rqrcode/lib/rqrcode.rb +13 -0
  22. data/vendor/rqrcode/lib/rqrcode/core_ext.rb +5 -0
  23. data/vendor/rqrcode/lib/rqrcode/core_ext/array.rb +5 -0
  24. data/vendor/rqrcode/lib/rqrcode/core_ext/array/behavior.rb +9 -0
  25. data/vendor/rqrcode/lib/rqrcode/core_ext/integer.rb +5 -0
  26. data/vendor/rqrcode/lib/rqrcode/core_ext/integer/bitwise.rb +11 -0
  27. data/vendor/rqrcode/lib/rqrcode/qrcode.rb +4 -0
  28. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_8bit_byte.rb +35 -0
  29. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_bit_buffer.rb +56 -0
  30. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_code.rb +421 -0
  31. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_math.rb +63 -0
  32. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_polynomial.rb +78 -0
  33. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_rs_block.rb +134 -0
  34. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_util.rb +254 -0
  35. data/vendor/rqrcode/test/runtest.rb +78 -0
  36. data/vendor/rqrcode/test/test_data.rb +21 -0
  37. metadata +86 -44
data/bin/barby ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'rubygems'
4
+
5
+ #$: << File.join(File.dirname(__FILE__), '..', 'lib')
6
+ require 'barby'
7
+
8
+ options = {
9
+ :outputter => 'Png',
10
+ :outputter_method => 'to_png'
11
+ }
12
+
13
+ ARGV.options do |o|
14
+ o.banner = " Usage: #{File.basename(__FILE__)} [OPTIONS] data"
15
+ o.define_head ' Generates barcodes and prints the generated output to STDOUT'
16
+
17
+ o.separator ''
18
+ o.separator ' EXPERIMENTAL'
19
+ o.separator ''
20
+
21
+ o.on('-b', '--barcode=ClassName', String, 'Barcode type'){|v| options[:barcode] = v }
22
+ o.on('-o', '--outputter=ClassName', String, 'Outputter'){|v| options[:outputter] = v }
23
+ o.on('-m', '--method=method_name', String, 'Outputter method'){|v| options[:outputter_method] = v }
24
+
25
+ o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
26
+
27
+ o.parse!
28
+ end
29
+
30
+ #p STDIN.read
31
+ #exit
32
+
33
+ require "barby/outputter/#{options[:outputter].gsub(/[A-Z]/){|c| '_'+c.downcase }[1..-1]}_outputter"
34
+
35
+ barcode_class = Barby.const_get(options[:barcode])
36
+ barcode = barcode_class.new($*.empty? ? STDIN.read.chomp : $*)
37
+ outputter_class = Barby.const_get("#{options[:outputter]}Outputter")
38
+ outputter = outputter_class.new(barcode)
39
+
40
+ print eval("outputter.#{options[:outputter_method]}(#{ENV['OPTIONS']})")
data/lib/barby.rb CHANGED
@@ -1,11 +1,14 @@
1
+ require 'barby/vendor'
1
2
  require 'barby/version'
2
3
 
3
4
  require 'barby/barcode'
4
5
  require 'barby/barcode/code_128'
5
6
  require 'barby/barcode/gs1_128'
6
7
  require 'barby/barcode/code_39'
8
+ require 'barby/barcode/code_93'
7
9
  require 'barby/barcode/ean_13'
8
10
  require 'barby/barcode/ean_8'
9
11
  require 'barby/barcode/bookland'
12
+ require 'barby/barcode/qr_code'
10
13
 
11
14
  require 'barby/outputter'
data/lib/barby/barcode.rb CHANGED
@@ -41,6 +41,12 @@ module Barby
41
41
  end
42
42
 
43
43
 
44
+ #Is this barcode 2D?
45
+ def two_dimensional?
46
+ is_a? Barcode2D
47
+ end
48
+
49
+
44
50
  def method_missing(name, *args, &b)#:nodoc:
45
51
  #See if an outputter has registered this method
46
52
  if self.class.outputters.include?(name)
@@ -4,6 +4,19 @@ module Barby
4
4
 
5
5
 
6
6
  #Code 128 barcodes
7
+ #
8
+ #Note that you must provide a type for each object, either by passing a string
9
+ #as a second parameter to Code128.new or by instantiating one of the child classes.
10
+ #
11
+ #You can switch type by using the CODEA, CODEB and CODEC characters:
12
+ #
13
+ # "\305" => A
14
+ # "\306" => B
15
+ # "\307" => C
16
+ #
17
+ #As an example, here's one that starts out as type A and then switches to B and then C:
18
+ #
19
+ # Code128A.new("ABC123\306def\3074567")
7
20
  class Code128 < Barcode1D
8
21
 
9
22
  ENCODINGS = {
@@ -47,7 +60,7 @@ module Barby
47
60
 
48
61
  VALUES = {
49
62
  'A' => {
50
- 0 => "SP", 1 => "!", 2 => "\"",
63
+ 0 => " ", 1 => "!", 2 => "\"",
51
64
  3 => "#", 4 => "$", 5 => "%",
52
65
  6 => "&", 7 => "'", 8 => "(",
53
66
  9 => ")", 10 => "*", 11 => "+",
@@ -80,13 +93,13 @@ module Barby
80
93
  90 => "\032", 91 => "\e", 92 => "\034",
81
94
  93 => "\035", 94 => "\036", 95 => "\037",
82
95
  96 => "\303", 97 => "\302", 98 => "SHIFT",
83
- 99 => "\307", 100 => "\306", 101 => "\304",
96
+ 99 => "\307", 100 => "\306", 101 => "\304",
84
97
  102 => "\301", 103 => "STARTA", 104 => "STARTB",
85
98
  105 => "STARTC"
86
99
  }.invert,
87
100
 
88
101
  'B' => {
89
- 0 => "SP", 1 => "!", 2 => "\"", 3 => "#", 4 => "$", 5 => "%",
102
+ 0 => " ", 1 => "!", 2 => "\"", 3 => "#", 4 => "$", 5 => "%",
90
103
  6 => "&", 7 => "'", 8 => "(", 9 => ")", 10 => "*", 11 => "+",
91
104
  12 => ",", 13 => "-", 14 => ".", 15 => "/", 16 => "0", 17 => "1",
92
105
  18 => "2", 19 => "3", 20 => "4", 21 => "5", 22 => "6", 23 => "7",
@@ -0,0 +1,161 @@
1
+ require 'barby/barcode'
2
+
3
+ module Barby
4
+
5
+
6
+ #Standard/Industrial 2 of 5, non-interleaved
7
+ #
8
+ #Checksum not included by default, to include it,
9
+ #set include_checksum = true
10
+ class Code25 < Barcode1D
11
+
12
+ WIDE = W = true
13
+ NARROW = N = false
14
+
15
+ START_ENCODING = [W,W,N]
16
+ STOP_ENCODING = [W,N,W]
17
+
18
+ ENCODINGS = {
19
+ 0 => [N,N,W,W,N],
20
+ 1 => [W,N,N,N,W],
21
+ 2 => [N,W,N,N,W],
22
+ 3 => [W,W,N,N,N],
23
+ 4 => [N,N,W,N,W],
24
+ 5 => [W,N,W,N,N],
25
+ 6 => [N,W,W,N,N],
26
+ 7 => [N,N,N,W,W],
27
+ 8 => [W,N,N,W,N],
28
+ 9 => [N,W,N,W,N]
29
+ }
30
+
31
+ attr_accessor :data, :narrow_width, :wide_width, :space_width, :include_checksum
32
+
33
+
34
+ def initialize(data)
35
+ self.data = data
36
+ end
37
+
38
+
39
+ def data_encoding
40
+ digit_encodings.join
41
+ end
42
+
43
+ def data_encoding_with_checksum
44
+ data_encoding+checksum_encoding
45
+ end
46
+
47
+ def encoding
48
+ start_encoding+(include_checksum? ? data_encoding_with_checksum : data_encoding)+stop_encoding
49
+ end
50
+
51
+
52
+ def characters
53
+ data.split(//)
54
+ end
55
+
56
+ def digits
57
+ characters.map{|c| c.to_i }
58
+ end
59
+
60
+ def even_and_odd_digits
61
+ alternater = false
62
+ digits.reverse.partition{ alternater = !alternater }
63
+ end
64
+
65
+
66
+ def digit_encodings
67
+ digits.map{|d| encoding_for(d) }
68
+ end
69
+ alias character_encodings digit_encodings
70
+
71
+
72
+ #Returns the encoding for a single digit
73
+ def encoding_for(digit)
74
+ encoding_for_bars(ENCODINGS[digit])
75
+ end
76
+
77
+ #Generate encoding for an array of W,N
78
+ def encoding_for_bars(*bars)
79
+ wide, narrow, space = wide_encoding, narrow_encoding, space_encoding
80
+ bars.flatten.inject '' do |enc,bar|
81
+ enc + (bar == WIDE ? wide : narrow) + space
82
+ end
83
+ end
84
+
85
+
86
+ #Mod10
87
+ def checksum
88
+ evens, odds = even_and_odd_digits
89
+ sum = odds.inject(0){|sum,d| sum + d } + evens.inject(0){|sum,d| sum + (d*3) }
90
+ sum %= 10
91
+ sum.zero? ? 0 : 10-sum
92
+ end
93
+
94
+ def checksum_encoding
95
+ encoding_for(checksum)
96
+ end
97
+
98
+
99
+ #The width of a narrow bar in xdims
100
+ def narrow_width
101
+ @narrow_width || 1
102
+ end
103
+
104
+ #The width of a wide bar in xdims
105
+ #By default three times as wide as a narrow bar
106
+ def wide_width
107
+ @wide_width || narrow_width*3
108
+ end
109
+
110
+ #The width of the space between the bars in xdims
111
+ #By default the same width as a narrow bar
112
+ #
113
+ #A space serves only as a separator for the bars,
114
+ #there is no encoded meaning in them
115
+ def space_width
116
+ @space_width || narrow_width
117
+ end
118
+
119
+
120
+ def include_checksum?
121
+ include_checksum
122
+ end
123
+
124
+
125
+ def data=(data)
126
+ @data = "#{data}"
127
+ end
128
+
129
+
130
+ def start_encoding
131
+ encoding_for_bars(START_ENCODING)
132
+ end
133
+
134
+ def stop_encoding
135
+ #Removes trailing space generated by encoding_for_bars
136
+ encoding_for_bars(STOP_ENCODING).gsub(/0+$/, '')
137
+ end
138
+
139
+
140
+ def narrow_encoding
141
+ '1' * narrow_width
142
+ end
143
+
144
+ def wide_encoding
145
+ '1' * wide_width
146
+ end
147
+
148
+ def space_encoding
149
+ '0' * space_width
150
+ end
151
+
152
+
153
+ def valid?
154
+ data =~ /^[0-9]*$/
155
+ end
156
+
157
+
158
+ end
159
+
160
+
161
+ end
@@ -0,0 +1,73 @@
1
+ require 'barby/barcode/code_25'
2
+
3
+ module Barby
4
+
5
+ class Code25Interleaved < Code25
6
+
7
+ START_ENCODING = [N,N,N,N]
8
+ STOP_ENCODING = [W,N,N]
9
+
10
+
11
+ def data_encoding
12
+ digit_pair_encodings.join
13
+ end
14
+
15
+
16
+ def character_pairs
17
+ chars = characters
18
+ pairs = Array.new((chars.size/2.0).ceil){ [] }
19
+ chars.each_with_index{|c,i| pairs[(i/2.0).floor] << c }
20
+ pairs
21
+ end
22
+
23
+ def digit_pairs
24
+ d = digits
25
+ pairs = Array.new((d.size/2.0).ceil){ [] }
26
+ d.each_with_index{|dd,i| pairs[(i/2.0).floor] << dd }
27
+ pairs
28
+ end
29
+
30
+
31
+ def digit_pair_encodings
32
+ digit_pairs.map{|p| encoding_for_pair(p) }
33
+ end
34
+
35
+
36
+ def encoding_for_pair(pair)
37
+ bars, spaces = ENCODINGS[pair.first], ENCODINGS[pair.last]
38
+ bars.zip(spaces).inject '' do |enc,p|
39
+ bar, space = *p
40
+ enc + ('1' * (bar == WIDE ? wide_width : narrow_width)) +
41
+ ('0' * (space == WIDE ? wide_width : narrow_width))
42
+ end
43
+ end
44
+
45
+ #def encoding_for_bars(*bars_and_spaces)
46
+ # bar = false
47
+ # bars_and_spaces.flatten.inject '' do |enc,bar_or_space|
48
+ # bar = !bar
49
+ # enc + (bar ? '1' : '0')*(bar_or_space == WIDE ? wide_width : narrow_width)
50
+ # end
51
+ #end
52
+
53
+
54
+ def start_encoding
55
+ bar = false
56
+ START_ENCODING.inject '' do |enc,bar_or_space|
57
+ bar = !bar
58
+ enc << (bar ? '1' : '0') * (bar_or_space == WIDE ? wide_width : narrow_width)
59
+ end
60
+ end
61
+
62
+ def stop_encoding
63
+ bar = false
64
+ STOP_ENCODING.inject '' do |enc,bar_or_space|
65
+ bar = !bar
66
+ enc << (bar ? '1' : '0') * (bar_or_space == WIDE ? wide_width : narrow_width)
67
+ end
68
+ end
69
+
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,225 @@
1
+ require 'barby/barcode'
2
+
3
+ module Barby
4
+
5
+ class Code93 < Barcode1D
6
+
7
+ SHIFT_DOLLAR = "\301" # ($)
8
+ SHIFT_PERCENT = "\302" # (%)
9
+ SHIFT_SLASH = "\303" # (/)
10
+ SHIFT_PLUS = "\304" # (+)
11
+
12
+ SHIFT_CHARACTERS = [SHIFT_DOLLAR, SHIFT_PERCENT, SHIFT_SLASH, SHIFT_PLUS]
13
+
14
+ ENCODINGS = {
15
+ "0" => "100010100", "1" => "101001000",
16
+ "2" => "101000100", "3" => "101000010",
17
+ "4" => "100101000", "5" => "100100100",
18
+ "6" => "100100010", "7" => "101010000",
19
+ "8" => "100010010", "9" => "100001010",
20
+ "A" => "110101000", "B" => "110100100",
21
+ "C" => "110100010", "D" => "110010100",
22
+ "E" => "110010010", "F" => "110001010",
23
+ "G" => "101101000", "H" => "101100100",
24
+ "I" => "101100010", "J" => "100110100",
25
+ "K" => "100011010", "L" => "101011000",
26
+ "M" => "101001100", "N" => "101000110",
27
+ "O" => "100101100", "P" => "100010110",
28
+ "Q" => "110110100", "R" => "110110010",
29
+ "S" => "110101100", "T" => "110100110",
30
+ "U" => "110010110", "V" => "110011010",
31
+ "W" => "101101100", "X" => "101100110",
32
+ "Y" => "100110110", "Z" => "100111010",
33
+ "-" => "100101110", "." => "111010100",
34
+ " " => "111010010", "$" => "111001010",
35
+ "/" => "101101110", "+" => "101110110",
36
+ "%" => "110101110",
37
+ SHIFT_DOLLAR => "100100110",
38
+ SHIFT_PERCENT => "111011010",
39
+ SHIFT_SLASH => "111010110",
40
+ SHIFT_PLUS => "100110010"
41
+ }
42
+
43
+ EXTENDED_MAPPING = {
44
+ "\000" => "\302U", " " => " ", "@" => "\302V", "`" => "\302W",
45
+ "\001" => "\301A", "!" => "\303A", "A" => "A", "a" => "\304A",
46
+ "\002" => "\301B", '"' => "\303B", "B" => "B", "b" => "\304B",
47
+ "\003" => "\301C", "#" => "\303C", "C" => "C", "c" => "\304C",
48
+ "\004" => "\301D", "$" => "\303D", "D" => "D", "d" => "\304D",
49
+ "\005" => "\301E", "%" => "\303E", "E" => "E", "e" => "\304E",
50
+ "\006" => "\301F", "&" => "\303F", "F" => "F", "f" => "\304F",
51
+ "\007" => "\301G", "'" => "\303G", "G" => "G", "g" => "\304G",
52
+ "\010" => "\301H", "(" => "\303H", "H" => "H", "h" => "\304H",
53
+ "\011" => "\301I", ")" => "\303I", "I" => "I", "i" => "\304I",
54
+ "\012" => "\301J", "*" => "\303J", "J" => "J", "j" => "\304J",
55
+ "\013" => "\301K", "/" => "\303K", "K" => "K", "k" => "\304K",
56
+ "\014" => "\301L", "," => "\303L", "L" => "L", "l" => "\304L",
57
+ "\015" => "\301M", "-" => "-", "M" => "M", "m" => "\304M",
58
+ "\016" => "\301N", "." => ".", "N" => "N", "n" => "\304N",
59
+ "\017" => "\301O", "+" => "\303O", "O" => "O", "o" => "\304O",
60
+ "\020" => "\301P", "0" => "0", "P" => "P", "p" => "\304P",
61
+ "\021" => "\301Q", "1" => "1", "Q" => "Q", "q" => "\304Q",
62
+ "\022" => "\301R", "2" => "2", "R" => "R", "r" => "\304R",
63
+ "\023" => "\301S", "3" => "3", "S" => "S", "s" => "\304S",
64
+ "\024" => "\301T", "4" => "4", "T" => "T", "t" => "\304T",
65
+ "\025" => "\301U", "5" => "5", "U" => "U", "u" => "\304U",
66
+ "\026" => "\301V", "6" => "6", "V" => "V", "v" => "\304V",
67
+ "\027" => "\301W", "7" => "7", "W" => "W", "w" => "\304W",
68
+ "\030" => "\301X", "8" => "8", "X" => "X", "x" => "\304X",
69
+ "\031" => "\301Y", "9" => "9", "Y" => "Y", "y" => "\304Y",
70
+ "\032" => "\301Z", ":" => "\303Z", "Z" => "Z", "z" => "\304Z",
71
+ "\033" => "\302A", ";" => "\302F", "[" => "\302K", "{" => "\302P",
72
+ "\034" => "\302B", "<" => "\302G", "\\" => "\302L", "|" => "\302Q",
73
+ "\035" => "\302C", "=" => "\302H", "]" => "\302M", "}" => "\302R",
74
+ "\036" => "\302D", ">" => "\302I", "^" => "\302N", "~" => "\302S",
75
+ "\037" => "\302E", "?" => "\302J", "_" => "\302O", "\177" => "\302T"
76
+ }
77
+
78
+ EXTENDED_CHARACTERS = EXTENDED_MAPPING.keys - ENCODINGS.keys
79
+
80
+ CHARACTERS = {
81
+ 0 => "0", 1 => "1", 2 => "2", 3 => "3",
82
+ 4 => "4", 5 => "5", 6 => "6", 7 => "7",
83
+ 8 => "8", 9 => "9", 10 => "A", 11 => "B",
84
+ 12 => "C", 13 => "D", 14 => "E", 15 => "F",
85
+ 16 => "G", 17 => "H", 18 => "I", 19 => "J",
86
+ 20 => "K", 21 => "L", 22 => "M", 23 => "N",
87
+ 24 => "O", 25 => "P", 26 => "Q", 27 => "R",
88
+ 28 => "S", 29 => "T", 30 => "U", 31 => "V",
89
+ 32 => "W", 33 => "X", 34 => "Y", 35 => "Z",
90
+ 36 => "-", 37 => ".", 38 => " ", 39 => "$",
91
+ 40 => "/", 41 => "+", 42 => "%",
92
+ 43 => SHIFT_DOLLAR, 44 => SHIFT_PERCENT,
93
+ 45 => SHIFT_SLASH, 46 => SHIFT_PLUS
94
+ }
95
+
96
+ VALUES = CHARACTERS.invert
97
+
98
+ START_ENCODING = '101011110' # *
99
+ STOP_ENCODING = '101011110'
100
+ TERMINATE_ENCODING = '1'
101
+
102
+ attr_accessor :data
103
+
104
+
105
+ def initialize(data)
106
+ self.data = data
107
+ end
108
+
109
+
110
+ def extended?
111
+ raw_characters.any?{|c| EXTENDED_CHARACTERS.include?(c) }
112
+ end
113
+
114
+
115
+ def raw_characters
116
+ data.split(//)
117
+ end
118
+
119
+ def characters
120
+ raw_characters.map{|c| EXTENDED_MAPPING[c].split(//) }.flatten
121
+ end
122
+
123
+ def encoded_characters
124
+ characters.map{|c| ENCODINGS[c] }
125
+ end
126
+ alias character_encodings encoded_characters
127
+
128
+
129
+ def start_encoding
130
+ START_ENCODING
131
+ end
132
+
133
+ #The stop encoding includes the termination bar
134
+ def stop_encoding
135
+ STOP_ENCODING+TERMINATE_ENCODING
136
+ end
137
+
138
+
139
+ def encoding
140
+ start_encoding+data_encoding_with_checksums+stop_encoding
141
+ end
142
+
143
+ def data_encoding
144
+ character_encodings.join
145
+ end
146
+
147
+ def data_encoding_with_checksums
148
+ (character_encodings + checksum_encodings).join
149
+ end
150
+
151
+ def checksum_encodings
152
+ checksum_characters.map{|c| ENCODINGS[c] }
153
+ end
154
+
155
+ def checksum_encoding
156
+ checksum_encodings.join
157
+ end
158
+
159
+
160
+ def checksums
161
+ [c_checksum, k_checksum]
162
+ end
163
+
164
+ def checksum_characters
165
+ checksums.map{|s| CHARACTERS[s] }
166
+ end
167
+
168
+
169
+ #Returns the values used for computing the C checksum
170
+ #in the "right" order (i.e. reversed)
171
+ def checksum_values
172
+ characters.map{|c| VALUES[c] }.reverse
173
+ end
174
+
175
+ #Returns the normal checksum plus the c_checksum
176
+ #This is used for calculating the k_checksum
177
+ def checksum_values_with_c_checksum
178
+ [c_checksum] + checksum_values
179
+ end
180
+
181
+
182
+ #Calculates the C checksum based on checksum_values
183
+ def c_checksum
184
+ sum = 0
185
+ checksum_values.each_with_index do |value, index|
186
+ sum += ((index % 20) + 1) * value
187
+ end
188
+ sum % 47
189
+ end
190
+
191
+ def c_checksum_character
192
+ CHARACTERS[c_checksum]
193
+ end
194
+
195
+ def c_checksum_encoding
196
+ ENCODINGS[c_checksum_character]
197
+ end
198
+
199
+
200
+ #Calculates the K checksum based on checksum_values_with_c_checksum
201
+ def k_checksum
202
+ sum = 0
203
+ checksum_values_with_c_checksum.each_with_index do |value, index|
204
+ sum += ((index % 15) + 1) * value
205
+ end
206
+ sum % 47
207
+ end
208
+
209
+ def k_checksum_character
210
+ CHARACTERS[k_checksum]
211
+ end
212
+
213
+ def k_checksum_encoding
214
+ ENCODINGS[k_checksum_character]
215
+ end
216
+
217
+
218
+ def valid?
219
+ characters.all?{|c| ENCODINGS.include?(c) }
220
+ end
221
+
222
+
223
+ end
224
+
225
+ end