barcode1dtools 0.9.4.1 → 0.9.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/barcode1dtools.rb +3 -2
- data/lib/barcode1dtools/codabar.rb +249 -0
- data/test/test_barcode1dcodabar.rb +67 -0
- metadata +29 -50
data/lib/barcode1dtools.rb
CHANGED
@@ -16,8 +16,8 @@ module Barcode1DTools
|
|
16
16
|
# 1-dimensional barcode patterns for various code types. The
|
17
17
|
# library currently includes EAN-13, EAN-8, UPC-A, UPC-E, UPC
|
18
18
|
# Supplemental 2, UPC Supplemental 5, Interleaved 2 of 5 (I 2/5),
|
19
|
-
# Code 3 of 9,
|
20
|
-
# symbologies in the near future.
|
19
|
+
# Code 3 of 9, Code 93, and Codabar, but will be expanded to
|
20
|
+
# include most 1D symbologies in the near future.
|
21
21
|
#
|
22
22
|
#== Example
|
23
23
|
# ean13 = Barcode1DTools::EAN13.new('0012676510226', :line_character => 'x', :space_character => ' ')
|
@@ -119,3 +119,4 @@ require 'barcode1dtools/upc_supplemental_2'
|
|
119
119
|
require 'barcode1dtools/upc_supplemental_5'
|
120
120
|
require 'barcode1dtools/code3of9'
|
121
121
|
require 'barcode1dtools/code93'
|
122
|
+
require 'barcode1dtools/codabar'
|
@@ -0,0 +1,249 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2012 Michael Chaney Consulting Corporation
|
3
|
+
#
|
4
|
+
# Released under the terms of the MIT License or the GNU
|
5
|
+
# General Public License, v. 2
|
6
|
+
#++
|
7
|
+
|
8
|
+
module Barcode1DTools
|
9
|
+
|
10
|
+
# Barcode1DTools::Codabar - Create and decode bar patterns for
|
11
|
+
# Codabar. The value encoded is a string which may contain the
|
12
|
+
# digits 0-9 and the symbols dash "-", dollar sign "$", plus
|
13
|
+
# sign "+", colon ":", forward slash "/", and dot ".". There are
|
14
|
+
# four start/stop characters which are A, B, C, and D or T, N,
|
15
|
+
# asterisk "*", and E. Note that A and T are equivalent, as are
|
16
|
+
# B and N, C and asterisk, and D and E. Any may be used as start
|
17
|
+
# and stop characters giving 16 possible combinations.
|
18
|
+
#
|
19
|
+
# Because there is no standard for check digits, we implement
|
20
|
+
# neither generation nor checking of one. It is up to the caller
|
21
|
+
# to present a check digit if it is part of the payload.
|
22
|
+
#
|
23
|
+
# Additionally, the caller must present the start and stop
|
24
|
+
# characters as part of the value. When decoding, the start/stop
|
25
|
+
# cahracters will be presented as A, B, C, or D.
|
26
|
+
#
|
27
|
+
# val = "A29322930C"
|
28
|
+
# bc = Barcode1DTools::Codabar.new(val)
|
29
|
+
# pattern = bc.bars
|
30
|
+
# rle_pattern = bc.rle
|
31
|
+
# width = bc.width
|
32
|
+
#
|
33
|
+
# The object created is immutable.
|
34
|
+
#
|
35
|
+
# Barcode1DTools::Codabar creates the patterns that you need to
|
36
|
+
# display Codabar barcodes. It can also decode a simple w/n
|
37
|
+
# string.
|
38
|
+
#
|
39
|
+
# Codabar characters consist of 4 bars and 3 spaces, with a narrow
|
40
|
+
# space between them. The main characters (0-9, dash, and dollar
|
41
|
+
# sign) each have one wide bar and one wide space (hence the
|
42
|
+
# alternate name "code 2 of 7"). The start/stop codes have one
|
43
|
+
# wide bar and two adjacent wide spaces. The extended characters
|
44
|
+
# (dot, forward slash, colon, and plus sign) each have three wide
|
45
|
+
# bars and all narrow spaces.
|
46
|
+
#
|
47
|
+
# There are three formats for the returned pattern:
|
48
|
+
#
|
49
|
+
# bars - 1s and 0s specifying black lines and white spaces. Actual
|
50
|
+
# characters can be changed from "1" and 0" with options
|
51
|
+
# :line_character and :space_character.
|
52
|
+
#
|
53
|
+
# rle - Run-length-encoded version of the pattern. The first
|
54
|
+
# number is always a black line, with subsequent digits
|
55
|
+
# alternating between spaces and lines. The digits specify
|
56
|
+
# the width of each line or space.
|
57
|
+
#
|
58
|
+
# wn - The native format for this barcode type. The string
|
59
|
+
# consists of a series of "w" and "n" characters. The first
|
60
|
+
# item is always a black line, with subsequent characters
|
61
|
+
# alternating between spaces and lines. A "wide" item
|
62
|
+
# is twice the width of a "narrow" item.
|
63
|
+
#
|
64
|
+
# The "width" method will tell you the total end-to-end width, in
|
65
|
+
# units, of the entire barcode. Note that the w/n format is
|
66
|
+
# unavailable for this symbology.
|
67
|
+
#
|
68
|
+
#== Rendering
|
69
|
+
#
|
70
|
+
# The original Codabar specification actually included a varied
|
71
|
+
# w/n ratio depending on whether there were two or three wide
|
72
|
+
# elements in a character. Those with two wide elements used a 3:1
|
73
|
+
# ratio while those with three wide elements used a 2:1 ratio. In
|
74
|
+
# that way, the characters were consistently 10 units wide.
|
75
|
+
#
|
76
|
+
# Our default ratio is 3:1 for the entire code, but if you include
|
77
|
+
# :varied_wn_ratio => true in the options the rle and bars strings
|
78
|
+
# will have variable ratio that shifts between 2:1 and 3:1 and the
|
79
|
+
# "wn_ratio" option will be ignored.
|
80
|
+
|
81
|
+
class Codabar < Barcode1D
|
82
|
+
|
83
|
+
# Character sequence - 0-based offset in this string is character
|
84
|
+
# number
|
85
|
+
CHAR_SEQUENCE = "0123456789-$:/.+ABCD"
|
86
|
+
|
87
|
+
# Patterns for making bar codes
|
88
|
+
PATTERNS = {
|
89
|
+
'0'=> {'val'=>0 ,'wn'=>'nnnnnww'},
|
90
|
+
'1'=> {'val'=>1 ,'wn'=>'nnnnwwn'},
|
91
|
+
'2'=> {'val'=>2 ,'wn'=>'nnnwnnw'},
|
92
|
+
'3'=> {'val'=>3 ,'wn'=>'wwnnnnn'},
|
93
|
+
'4'=> {'val'=>4 ,'wn'=>'nnwnnwn'},
|
94
|
+
'5'=> {'val'=>5 ,'wn'=>'wnnnnwn'},
|
95
|
+
'6'=> {'val'=>6 ,'wn'=>'nwnnnnw'},
|
96
|
+
'7'=> {'val'=>7 ,'wn'=>'nwnnwnn'},
|
97
|
+
'8'=> {'val'=>8 ,'wn'=>'nwwnnnn'},
|
98
|
+
'9'=> {'val'=>9 ,'wn'=>'wnnwnnn'},
|
99
|
+
'-'=> {'val'=>10 ,'wn'=>'nnnwwnn'},
|
100
|
+
'$'=> {'val'=>11 ,'wn'=>'nnwwnnn'},
|
101
|
+
':'=> {'val'=>12 ,'wn'=>'wnnnwnw'},
|
102
|
+
'/'=> {'val'=>13 ,'wn'=>'wnwnnnw'},
|
103
|
+
'.'=> {'val'=>14 ,'wn'=>'wnwnwnn'},
|
104
|
+
'+'=> {'val'=>15 ,'wn'=>'nnwnwnw'},
|
105
|
+
|
106
|
+
'A'=> {'val'=>16 ,'wn'=>'nnwwnwn'},
|
107
|
+
'B'=> {'val'=>17 ,'wn'=>'nwnwnnw'},
|
108
|
+
'C'=> {'val'=>18 ,'wn'=>'nnnwnww'},
|
109
|
+
'D'=> {'val'=>19 ,'wn'=>'nnnwwwn'},
|
110
|
+
|
111
|
+
'T'=> {'val'=>16 ,'wn'=>'nnwwnwn'},
|
112
|
+
'N'=> {'val'=>17 ,'wn'=>'nwnwnnw'},
|
113
|
+
'*'=> {'val'=>18 ,'wn'=>'nnnwnww'},
|
114
|
+
'E'=> {'val'=>19 ,'wn'=>'nnnwwwn'}
|
115
|
+
}
|
116
|
+
|
117
|
+
DEFAULT_OPTIONS = {
|
118
|
+
:line_character => '1',
|
119
|
+
:space_character => '0',
|
120
|
+
:w_character => 'w',
|
121
|
+
:n_character => 'n',
|
122
|
+
:wn_ratio => '3',
|
123
|
+
:varied_wn_ratio => false
|
124
|
+
}
|
125
|
+
|
126
|
+
attr_reader :start_character, :stop_character, :payload
|
127
|
+
|
128
|
+
class << self
|
129
|
+
# Codabar can encode digits, dash, dollar, colon, forward
|
130
|
+
# slash, dot, and plus. The string must start and stop with
|
131
|
+
# start/stop characters.
|
132
|
+
def can_encode?(value)
|
133
|
+
value.to_s =~ /\A[ABCD][0-9\$:\/\.\+\-]*[ABCD]\z/ || value.to_s =~ /\A[TN\*E][0-9\$:\/\.\+\-]*[TN\*E]\z/
|
134
|
+
end
|
135
|
+
|
136
|
+
# We don't generate a check digit
|
137
|
+
def generate_check_digit_for(value)
|
138
|
+
raise NotImplementedError
|
139
|
+
end
|
140
|
+
|
141
|
+
def validate_check_digit_for(value)
|
142
|
+
raise NotImplementedError
|
143
|
+
end
|
144
|
+
|
145
|
+
# Decode a string in rle format. This will return a Codabar
|
146
|
+
# object.
|
147
|
+
def decode(str, options = {})
|
148
|
+
if str =~ /[^1-3]/ && str =~ /[^wn]/
|
149
|
+
raise UnencodableCharactersError, "Pattern must be rle or wn"
|
150
|
+
end
|
151
|
+
|
152
|
+
# ensure a wn string
|
153
|
+
if str =~ /[1-3]/
|
154
|
+
str = str.tr('123','nww')
|
155
|
+
end
|
156
|
+
|
157
|
+
start_stop_pattern_match = Regexp.new(['A','B','C','D'].collect { |c| PATTERNS[c]['wn'] }.join('|'))
|
158
|
+
|
159
|
+
if str.reverse =~ /\A#{start_stop_pattern_match}n.*?#{start_stop_pattern_match}\z/
|
160
|
+
str.reverse!
|
161
|
+
end
|
162
|
+
|
163
|
+
unless str =~ /\A(#{start_stop_pattern_match}n.*?#{start_stop_pattern_match})\z/
|
164
|
+
raise UnencodableCharactersError, "Start/stop pattern is not detected."
|
165
|
+
end
|
166
|
+
|
167
|
+
# Adding an "n" to make it easier to scan
|
168
|
+
wn_pattern = $1 + 'n'
|
169
|
+
|
170
|
+
# Each pattern is 4 bars and 3 spaces, with a space between.
|
171
|
+
unless wn_pattern.size % 8 == 0
|
172
|
+
raise UnencodableCharactersError, "Wrong number of bars."
|
173
|
+
end
|
174
|
+
|
175
|
+
decoded_string = ''
|
176
|
+
|
177
|
+
wn_pattern.scan(/(.{7})n/).each do |chunk|
|
178
|
+
|
179
|
+
chunk = chunk.first
|
180
|
+
found = false
|
181
|
+
|
182
|
+
PATTERNS.each do |char,hsh|
|
183
|
+
if !['T', 'E', '*', 'N'].include?(char) && chunk == hsh['wn']
|
184
|
+
decoded_string += char
|
185
|
+
found = true
|
186
|
+
break;
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
raise UndecodableCharactersError, "Invalid sequence: #{chunk}" unless found
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
Codabar.new(decoded_string)
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
# Options are :line_character, :space_character, :w_character,
|
200
|
+
# :n_character, and :varied_wn_ratio.
|
201
|
+
def initialize(value, options = {})
|
202
|
+
|
203
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
204
|
+
|
205
|
+
# Can we encode this value?
|
206
|
+
raise UnencodableCharactersError unless self.class.can_encode?(value)
|
207
|
+
|
208
|
+
@value = value.to_s
|
209
|
+
@check_digit = nil
|
210
|
+
|
211
|
+
@encoded_string = @value
|
212
|
+
md = @value.match(/\A([ABCDTNE\*])(.*?)([ABCDTNE\*])\z/)
|
213
|
+
@start_character, @payload, @stop_character = md[1], md[2], md[3]
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns a string of "w" or "n" ("wide" and "narrow")
|
217
|
+
def wn
|
218
|
+
@wn ||= wn_str.tr('wn', @options[:w_character].to_s + @options[:n_character].to_s)
|
219
|
+
end
|
220
|
+
|
221
|
+
# returns a run-length-encoded string representation
|
222
|
+
def rle
|
223
|
+
if @options[:varied_wn_ratio]
|
224
|
+
@rle ||= @encoded_string.split('').collect { |c| PATTERNS[c]['wn'] }.collect { |p| p.tr('wn',(p=~/.*w.*w.*w/ ? '21' : '31')) }.join('1')
|
225
|
+
else
|
226
|
+
@rle ||= self.class.wn_to_rle(self.wn, @options)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# returns 1s and 0s (for "black" and "white")
|
231
|
+
def bars
|
232
|
+
@bars ||= self.class.rle_to_bars(self.rle, @options)
|
233
|
+
end
|
234
|
+
|
235
|
+
# returns the total unit width of the bar code
|
236
|
+
def width
|
237
|
+
@width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
# Creates the actual w/n pattern. Note that there is a narrow space
|
243
|
+
# between each character.
|
244
|
+
def wn_str
|
245
|
+
@wn_str ||= @encoded_string.split('').collect { |c| PATTERNS[c]['wn'] }.join('n')
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2012 Michael Chaney Consulting Corporation
|
3
|
+
#
|
4
|
+
# Released under the terms of the MIT License or the GNU
|
5
|
+
# General Public License, v. 2
|
6
|
+
#++
|
7
|
+
|
8
|
+
require 'test/unit'
|
9
|
+
require 'barcode1dtools'
|
10
|
+
|
11
|
+
class Barcode1DToolsCodabarTest < Test::Unit::TestCase
|
12
|
+
def setup
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a random Codabar string
|
19
|
+
def random_codabar_value
|
20
|
+
['A','B','C','D'][rand(4)] + (1..5+rand(10)).collect { "0123456789-$:/.+"[rand(16),1] }.join + ['A','B','C','D'][rand(4)]
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_no_check_digit
|
24
|
+
assert_raise(Barcode1DTools::NotImplementedError) { Barcode1DTools::Codabar.generate_check_digit_for(random_codabar_value) }
|
25
|
+
assert_raise(Barcode1DTools::NotImplementedError) { Barcode1DTools::Codabar.validate_check_digit_for(random_codabar_value) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_attr_readers
|
29
|
+
codabar = Barcode1DTools::Codabar.new('A12345678C')
|
30
|
+
assert_nil codabar.check_digit
|
31
|
+
assert_equal 'A12345678C', codabar.value
|
32
|
+
assert_equal 'A12345678C', codabar.encoded_string
|
33
|
+
assert_equal 'A', codabar.start_character
|
34
|
+
assert_equal 'C', codabar.stop_character
|
35
|
+
assert_equal '12345678', codabar.payload
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_bad_character_errors
|
39
|
+
# Characters that cannot be encoded
|
40
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Codabar.new('thisisnotgood') }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Only need to test wn, as bars and rle are based on wn
|
44
|
+
def test_barcode_generation
|
45
|
+
codabar = Barcode1DTools::Codabar.new('A1B')
|
46
|
+
assert_equal "nnwwnwnnnnnnwwnnnwnwnnw", codabar.wn
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_decode_error
|
50
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Codabar.decode('x') }
|
51
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Codabar.decode('x'*60) }
|
52
|
+
# proper start & stop, but crap in middle
|
53
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Codabar.decode('nnnnwwwwnn') }
|
54
|
+
# wrong start/stop
|
55
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Codabar.decode('nwwnwnwnwnwnwnw') }
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_decoding
|
59
|
+
random_codabar_num=random_codabar_value
|
60
|
+
codabar = Barcode1DTools::Codabar.new(random_codabar_num)
|
61
|
+
codabar2 = Barcode1DTools::Codabar.decode(codabar.wn)
|
62
|
+
assert_equal codabar.value, codabar2.value
|
63
|
+
# Should also work in reverse
|
64
|
+
codabar4 = Barcode1DTools::Codabar.decode(codabar.wn.reverse)
|
65
|
+
assert_equal codabar.value, codabar4.value
|
66
|
+
end
|
67
|
+
end
|
metadata
CHANGED
@@ -1,41 +1,29 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: barcode1dtools
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.5.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 9
|
9
|
-
- 4
|
10
|
-
- 1
|
11
|
-
version: 0.9.4.1
|
12
6
|
platform: ruby
|
13
|
-
authors:
|
7
|
+
authors:
|
14
8
|
- Michael Chaney
|
15
9
|
autorequire:
|
16
10
|
bindir: bin
|
17
11
|
cert_chain: []
|
18
|
-
|
19
|
-
date: 2012-08-05 00:00:00 -05:00
|
20
|
-
default_executable:
|
12
|
+
date: 2012-08-05 00:00:00.000000000Z
|
21
13
|
dependencies: []
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
\t
|
26
|
-
\t
|
27
|
-
\t
|
28
|
-
\
|
29
|
-
\t display or reading from a device must be implemented by the\n\
|
30
|
-
\t programmer. More symbologies will be added as time permits.\n"
|
14
|
+
description: ! "\t Barcode1D is a small library for handling many kinds of\n\t 1-dimensional
|
15
|
+
barcodes. Currently implemented are Code 3 of 9, Code\n\t 93, Codabar, Interleaved
|
16
|
+
2 of 5, EAN-13, EAN-8, UPC-A, UPC-E, UPC\n\t Supplemental 2, and UPC Supplemental
|
17
|
+
5. Patterns are created in\n\t either a simple format of bars and spaces or as
|
18
|
+
a run-length encoded\n\t string. This only generates and decodes the patterns;
|
19
|
+
actual\n\t display or reading from a device must be implemented by the\n\t programmer.
|
20
|
+
\ More symbologies will be added as time permits.\n"
|
31
21
|
email: mdchaney@michaelchaney.com
|
32
22
|
executables: []
|
33
|
-
|
34
23
|
extensions: []
|
35
|
-
|
36
24
|
extra_rdoc_files: []
|
37
|
-
|
38
|
-
|
25
|
+
files:
|
26
|
+
- lib/barcode1dtools/codabar.rb
|
39
27
|
- lib/barcode1dtools/code3of9.rb
|
40
28
|
- lib/barcode1dtools/code93.rb
|
41
29
|
- lib/barcode1dtools/ean13.rb
|
@@ -48,6 +36,7 @@ files:
|
|
48
36
|
- lib/barcode1dtools.rb
|
49
37
|
- MIT-LICENSE
|
50
38
|
- test/test_barcode1d.rb
|
39
|
+
- test/test_barcode1dcodabar.rb
|
51
40
|
- test/test_barcode1dcode3of9.rb
|
52
41
|
- test/test_barcode1dcode93.rb
|
53
42
|
- test/test_barcode1dean13.rb
|
@@ -57,45 +46,35 @@ files:
|
|
57
46
|
- test/test_barcode1dupce.rb
|
58
47
|
- test/test_barcode1dupcsupp2.rb
|
59
48
|
- test/test_barcode1dupcsupp5.rb
|
60
|
-
has_rdoc: true
|
61
49
|
homepage: http://rubygems.org/gems/barcode1dtools
|
62
|
-
licenses:
|
50
|
+
licenses:
|
63
51
|
- MIT
|
64
52
|
- GPL-2
|
65
53
|
post_install_message:
|
66
54
|
rdoc_options: []
|
67
|
-
|
68
|
-
require_paths:
|
55
|
+
require_paths:
|
69
56
|
- lib
|
70
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
58
|
none: false
|
72
|
-
requirements:
|
73
|
-
- -
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
hash: 59
|
76
|
-
segments:
|
77
|
-
- 1
|
78
|
-
- 8
|
79
|
-
- 6
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
80
62
|
version: 1.8.6
|
81
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
64
|
none: false
|
83
|
-
requirements:
|
84
|
-
- -
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
|
87
|
-
segments:
|
88
|
-
- 0
|
89
|
-
version: "0"
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
90
69
|
requirements: []
|
91
|
-
|
92
70
|
rubyforge_project:
|
93
|
-
rubygems_version: 1.
|
71
|
+
rubygems_version: 1.8.10
|
94
72
|
signing_key:
|
95
73
|
specification_version: 3
|
96
74
|
summary: Pattern generators for 1D barcodes
|
97
|
-
test_files:
|
75
|
+
test_files:
|
98
76
|
- test/test_barcode1d.rb
|
77
|
+
- test/test_barcode1dcodabar.rb
|
99
78
|
- test/test_barcode1dcode3of9.rb
|
100
79
|
- test/test_barcode1dcode93.rb
|
101
80
|
- test/test_barcode1dean13.rb
|