marc 1.0.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91f847e4c58a60a123919914206e8b41935d1268
4
- data.tar.gz: b9485bfa59528e3703cc5bc4b45ec10df6dea502
3
+ metadata.gz: 6944f89278a06152fa5710a34fa3c959d9300bc5
4
+ data.tar.gz: 87e131c8dbe524d724062741de10da219d30b83b
5
5
  SHA512:
6
- metadata.gz: 7434cec1dd28cd9bdbf0390958d5f663f187720597c8bc5a0a45d04d6a84409bada2c6974e94b48effdc2e33fbb48fe54b3b86fb050a7e2bfa17da49bada3831
7
- data.tar.gz: 83d5be3ce3eaa6da114101fe4dcbe15320b394184aeafa9aa20b8f7254c25d01f42f62d7153546909310adcb44d7f809c95f467c66f123435705b587957901b2
6
+ metadata.gz: 6bae7428d9c5c6c791a8c03687fb48d5ab5d0e3eec2005d8e9637bd6a9202c164b4e0882c6134526a7c64819dca6e7fc5dac17f9797c9891cbd743a1c231a7fc
7
+ data.tar.gz: b1420e8c1b7e991f878be77a1331a06bb83206b3a74f70057b8de8a3b579bb4900c0bb111bed7c5a88187241ac8b7dbcc07af4e085a3e07e9e0d0cee3ce7a0a4
data/Changes CHANGED
@@ -1,15 +1,25 @@
1
+ v1.0.2 July 2017
2
+ - Now (correctly) throw an error if datafield string is the empty string
3
+ (thanks to @bibliotechy)
4
+
5
+ v1.0.1 February 2016
6
+ - Non-user-facing change in implementation of FieldMap strictly for performance
7
+
8
+ v1.0.0 January 2015
9
+ - Mostly changes that deal with encoding, plus the plunge to a 1.0 release
10
+
1
11
  v0.5.0 April 2012
2
- - Extensive rewrite of MARC::Reader (ISO 2709 binary reader) to provide a
3
- fairly complete and consistent handing of char encoding issues in ruby 1.9.
12
+ - Extensive rewrite of MARC::Reader (ISO 2709 binary reader) to provide a
13
+ fairly complete and consistent handing of char encoding issues in ruby 1.9.
4
14
  - This code is well covered by automated tests, but ends up complex, there
5
- may be bugs, please report them.
6
- - May not work properly under jruby with non-unicode source encodings.
7
- - Still can't handle Marc8 encoding.
15
+ may be bugs, please report them.
16
+ - May not work properly under jruby with non-unicode source encodings.
17
+ - Still can't handle Marc8 encoding.
8
18
  - May not have entirely backwards compatible behavior with regard to char
9
- encodings under ruby 1.9.x as previous 0.4.x versions. Test your code.
19
+ encodings under ruby 1.9.x as previous 0.4.x versions. Test your code.
10
20
  In particular, previous versions may have automatically _transcoded_
11
21
  non-unicode encodings to UTF-8 for you. This version will not do
12
- so unless you ask it to with correct arguments.
22
+ so unless you ask it to with correct arguments.
13
23
 
14
24
  v0.4.4 Sat Mar 03 14:55:00 EDT 2012
15
25
  - Fixed performance regression: strict reader will parse about 5x faster now
@@ -26,8 +36,8 @@ v0.2.1 Mon Aug 18 14:14:16 EDT 2008
26
36
  Ross Singer)
27
37
 
28
38
  v0.2.0 Wed Jun 11 12:42:20 EDT 2008
29
- - added newline to output generated by REXML::Formatters::Default to make
30
- it a bit more friendly. REXML::Formatters::Pretty and Transitive just
39
+ - added newline to output generated by REXML::Formatters::Default to make
40
+ it a bit more friendly. REXML::Formatters::Pretty and Transitive just
31
41
  don't do what I want (whitespace in weird places).
32
42
 
33
43
  v0.1.9 Thu Jun 5 12:00:01 EDT 2008
@@ -36,7 +46,7 @@ v0.1.9 Thu Jun 5 12:00:01 EDT 2008
36
46
 
37
47
  v0.1.8 Tue Nov 13 22:51:03 EST 2007
38
48
  - added examples directory
39
- - fixed problem with leading whitespace and the leader in xml reader
49
+ - fixed problem with leading whitespace and the leader in xml reader
40
50
  (thanks Morgan Cundiff)
41
51
 
42
52
  v0.1.7 Mon Nov 12 09:33:57 EST 2007
@@ -58,7 +68,7 @@ v0.1.4 Tue Jan 2 15:45:53 EST 2007
58
68
  - fixed bug in MARC::XMLWriter that was outputting all control field tags as 00z
59
69
  (thanks Ross Singer)
60
70
  - added :include_namespace option to MARC::XMLWriter::encode to include the
61
- marcxml namespace, which allows MARC::Record::to_xml to emit the namespace
71
+ marcxml namespace, which allows MARC::Record::to_xml to emit the namespace
62
72
  for a single record.
63
73
 
64
74
  v0.1.3 Tue Jan 2 12:56:36 EST 2007
@@ -67,11 +77,11 @@ v0.1.3 Tue Jan 2 12:56:36 EST 2007
67
77
  as the hash keys.
68
78
 
69
79
  v0.1.2 Thu Dec 21 18:46:01 EST 2007
70
- - fixed MARC::Record::to_xml so that it actually is tested and works (thanks
80
+ - fixed MARC::Record::to_xml so that it actually is tested and works (thanks
71
81
  Ross Singer)
72
82
 
73
83
  v0.1.1
74
- - added ability to pass File like objects to the constructor for
84
+ - added ability to pass File like objects to the constructor for
75
85
  MARC::XMLReader like MARC::Reader (thanks Jake Glenn)
76
86
 
77
87
  v0.1.0 Wed Dec 6 15:40:40 EST 2006
@@ -93,11 +103,11 @@ v0.0.9 Tue Mar 28 10:02:16 CST 2006
93
103
  - added :stylesheet argument to XLMWriter.new
94
104
 
95
105
  v0.0.8 Mon Jan 16 22:31:00 EST 2006
96
- - removed control tests out of tc_field.rb into tc_control.rb
106
+ - removed control tests out of tc_field.rb into tc_control.rb
97
107
  - fixed some formatting
98
108
  - changed control/field to controlfield/datafield
99
109
  - added == check for controlfield
100
- - removed namespace declarations on record elements in favor of default
110
+ - removed namespace declarations on record elements in favor of default
101
111
  namespace on collection element
102
112
  - added spaces around subfield code and delimeter in to_s
103
113
  - fixed up relevant tests that were expecting old formatting
@@ -106,8 +116,8 @@ v0.0.8 Mon Jan 16 22:31:00 EST 2006
106
116
 
107
117
  v0.0.7 Mon Jan 2 21:39:28 CST 2006
108
118
  - MARC::XMLWriter added
109
- - removed encode/decode methods in MARC::MARC21 into MARC::Writer and
110
- MARC::Reader respectively. This required pushing MARC21 specific constants
119
+ - removed encode/decode methods in MARC::MARC21 into MARC::Writer and
120
+ MARC::Reader respectively. This required pushing MARC21 specific constants
111
121
  out into MARC::Constants which is required as necessary.
112
122
  - moved encode from MARC::MARXML into MARC::XMLWriter and added constants
113
123
  to MARC::Constants
data/README.md CHANGED
@@ -69,8 +69,6 @@ Developers, release new version of gem to rubygems with `rake release`
69
69
  (bundler-supplied task). Note that one nice thing this will do is automatically
70
70
  tag the version in git, very important for later figuring out what's going on.
71
71
 
72
- Please send bugs, requests and comments to Code4Lib Mailing list (https://listserv.nd.edu/cgi-bin/wa?A0=CODE4LIB).
73
-
74
72
  ## Authors
75
73
 
76
74
  Kevin Clarke <ksclarke@gmail.com>
@@ -50,7 +50,7 @@ module MARC
50
50
  def initialize(tag, i1=' ', i2=' ', *subfields)
51
51
  # if the tag is less than 3 characters long and
52
52
  # the string is all numeric then we pad with zeros
53
- if tag.length < 3 and /^[0-9]*$/ =~ tag
53
+ if tag.length < 3 and /^[0-9]+$/ =~ tag
54
54
  @tag = "%03d" % tag
55
55
  else
56
56
  @tag = tag
@@ -1,16 +1,17 @@
1
- module MARC
2
-
1
+ module MARC
2
+
3
3
  # The FieldMap is an Array of DataFields and Controlfields.
4
- # It also contains a Hash representation
4
+ # It also contains a Hash representation
5
5
  # of the fields for faster lookups (under certain conditions)
6
6
  class FieldMap < Array
7
7
  attr_reader :tags
8
8
  attr_accessor :clean
9
+
9
10
  def initialize
10
- @tags = {}
11
+ @tags = {}
11
12
  @clean = true
12
13
  end
13
-
14
+
14
15
  # Rebuild the HashWithChecksumAttribute with the current
15
16
  # values of the fields Array
16
17
  def reindex
@@ -21,28 +22,42 @@ module MARC
21
22
  end
22
23
  @clean = true
23
24
  end
24
-
25
+
25
26
  # Returns an array of all of the tags that appear in the record (not in the order they appear, however).
26
27
  def tag_list
27
28
  reindex unless @clean
28
29
  @tags.keys
29
30
  end
30
-
31
+
31
32
  # Returns an array of fields, in the order they appear, according to their tag.
32
33
  # The tags argument can be a string (e.g. '245'), an array (['100','700','800'])
33
34
  # or a range (('600'..'699')).
35
+
34
36
  def each_by_tag(tags)
35
37
  reindex unless @clean
36
- indices = @tags.values_at(*(@tags.keys & [*tags])).flatten.sort
38
+ indices = []
39
+ # Get all the indices associated with the tags
40
+ Array(tags).each do |t|
41
+ indices.concat @tags[t] if @tags[t]
42
+ end
43
+
44
+ # Remove any nils
45
+ indices.compact!
37
46
  return [] if indices.empty?
38
- self.values_at(*indices).each do |tag|
39
- yield tag
47
+
48
+ # Sort it, so we get the fields back in the order they appear in the record
49
+ indices.sort!
50
+
51
+ indices.each do |tag|
52
+ yield self[tag]
40
53
  end
41
54
  end
42
55
 
43
- # Freeze for immutability, first reindexing if needed.
56
+
57
+
58
+ # Freeze for immutability, first reindexing if needed.
44
59
  # A frozen FieldMap is safe for concurrent access, and also
45
- # can more easily avoid accidental reindexing on even read-only use.
60
+ # can more easily avoid accidental reindexing on even read-only use.
46
61
  def freeze
47
62
  self.reindex unless @clean
48
63
  super
@@ -50,18 +65,18 @@ module MARC
50
65
  end
51
66
 
52
67
  # A class that represents an individual MARC record. Every record
53
- # is made up of a collection of MARC::DataField objects.
68
+ # is made up of a collection of MARC::DataField objects.
54
69
  #
55
70
  # MARC::Record mixes in Enumerable to enable access to constituent
56
71
  # DataFields. For example, to return a list of all subject DataFields:
57
72
  #
58
- # record.find_all {|field| field.tag =~ /^6../}
59
- #
73
+ # record.find_all {|field| field.tag =~ /^6../}
74
+ #
60
75
  # The accessor 'fields' is also an Array of MARC::DataField objects which
61
76
  # the client can modify if neccesary.
62
77
  #
63
78
  # record.fields.delete(field)
64
- #
79
+ #
65
80
  # Other accessor attribute: 'leader' for record leader as String
66
81
  #
67
82
  # == High-performance lookup by tag
@@ -82,13 +97,13 @@ module MARC
82
97
  #
83
98
  # MARC::Record is not generally safe for sharing between threads.
84
99
  # Even if you think you are just acccessing it read-only,
85
- # you may accidentally trigger a reindex of the by-tag cache (see above).
100
+ # you may accidentally trigger a reindex of the by-tag cache (see above).
86
101
  #
87
102
  # However, after you are done constructing a Record, you can mark
88
103
  # the `fields` array as immutable. This makes a Record safe for sharing
89
104
  # between threads for read-only use, and also helps you avoid accidentally
90
105
  # triggering a reindex, as accidental reindexes can harm by-tag
91
- # lookup performance.
106
+ # lookup performance.
92
107
  #
93
108
  # record.fields.freeze
94
109
  class Record
@@ -101,9 +116,9 @@ module MARC
101
116
  attr_accessor :leader
102
117
 
103
118
  def initialize
104
- @fields = FieldMap.new
119
+ @fields = FieldMap.new
105
120
  # leader is 24 bytes
106
- @leader = ' ' * 24
121
+ @leader = ' ' * 24
107
122
  # leader defaults:
108
123
  # http://www.loc.gov/marc/bibliographic/ecbdldrd.html
109
124
  @leader[10..11] = '22'
@@ -119,9 +134,9 @@ module MARC
119
134
  end
120
135
 
121
136
  # alias to append
122
-
137
+
123
138
  def <<(field)
124
- append(field)
139
+ append(field)
125
140
  end
126
141
 
127
142
  # each() is here to support iterating and searching since MARC::Record
@@ -141,20 +156,20 @@ module MARC
141
156
  yield field
142
157
  end
143
158
  end
144
-
145
- # A more convenient way to iterate over each field with a given tag.
159
+
160
+ # A more convenient way to iterate over each field with a given tag.
146
161
  # The filter argument can be a string, array or range.
147
162
  def each_by_tag(filter)
148
- @fields.each_by_tag(filter) {|tag| yield tag }
163
+ @fields.each_by_tag(filter) { |tag| yield tag }
149
164
  end
150
165
 
151
166
  # You can lookup fields using this shorthand:
152
167
  # title = record['245']
153
168
 
154
169
  def [](tag)
155
- return self.find {|f| f.tag == tag}
170
+ return self.find { |f| f.tag == tag }
156
171
  end
157
-
172
+
158
173
  # Provides a backwards compatible means to access the FieldMap.
159
174
  # No argument returns the FieldMap array in entirety. Providing
160
175
  # a string, array or range of tags will return an array of fields
@@ -163,9 +178,9 @@ module MARC
163
178
  unless filter
164
179
  # Since we're returning the FieldMap object, which the caller
165
180
  # may mutate, we precautionarily mark dirty -- unless it's frozen
166
- # immutable.
181
+ # immutable.
167
182
  @fields.clean = false unless @fields.frozen?
168
- return @fields
183
+ return @fields
169
184
  end
170
185
  @fields.reindex unless @fields.clean
171
186
  flds = []
@@ -180,18 +195,18 @@ module MARC
180
195
  end
181
196
  flds
182
197
  end
183
-
198
+
184
199
  # Returns an array of all of the tags that appear in the record (not necessarily in the order they appear).
185
200
  def tags
186
201
  return @fields.tag_list
187
202
  end
188
203
 
189
- # Factory method for creating a MARC::Record from MARC21 in
204
+ # Factory method for creating a MARC::Record from MARC21 in
190
205
  # transmission format.
191
206
  #
192
207
  # record = MARC::Record.new_from_marc(marc21)
193
208
  #
194
- # in cases where you might be working with somewhat flawed
209
+ # in cases where you might be working with somewhat flawed
195
210
  # MARC data you may want to use the :forgiving parameter which
196
211
  # will bypass using field byte offsets and simply look for the
197
212
  # end of field byte to figure out the end of fields.
@@ -203,12 +218,12 @@ module MARC
203
218
  end
204
219
 
205
220
 
206
- # Returns a record in MARC21 transmission format (ANSI Z39.2).
221
+ # Returns a record in MARC21 transmission format (ANSI Z39.2).
207
222
  # Really this is just a wrapper around MARC::MARC21::encode
208
223
  #
209
224
  # marc = record.to_marc()
210
225
 
211
- def to_marc
226
+ def to_marc
212
227
  return MARC::Writer.encode(self)
213
228
  end
214
229
 
@@ -235,51 +250,51 @@ module MARC
235
250
  # Return a marc-hash version of the record
236
251
  def to_marchash
237
252
  return {
238
- 'type' => 'marc-hash',
239
- 'version' => [MARCHASH_MAJOR_VERSION, MARCHASH_MINOR_VERSION],
240
- 'leader' => self.leader,
241
- 'fields' => self.map {|f| f.to_marchash}
253
+ 'type' => 'marc-hash',
254
+ 'version' => [MARCHASH_MAJOR_VERSION, MARCHASH_MINOR_VERSION],
255
+ 'leader' => self.leader,
256
+ 'fields' => self.map { |f| f.to_marchash }
242
257
  }
243
- end #to_hash
258
+ end
259
+
260
+ #to_hash
244
261
 
245
262
  # Factory method for creating a new MARC::Record from
246
263
  # a marchash object
247
264
  #
248
265
  # record = MARC::Record->new_from_marchash(mh)
249
-
266
+
250
267
  def self.new_from_marchash(mh)
251
- r = self.new()
268
+ r = self.new()
252
269
  r.leader = mh['leader']
253
270
  mh['fields'].each do |f|
254
- if (f.length == 2)
271
+ if (f.length == 2)
255
272
  r << MARC::ControlField.new(f[0], f[1])
256
- elsif
257
- r << MARC::DataField.new(f[0], f[1], f[2], *f[3])
273
+ elsif r << MARC::DataField.new(f[0], f[1], f[2], *f[3])
258
274
  end
259
275
  end
260
276
  return r
261
277
  end
262
-
263
278
 
264
-
279
+
265
280
  # Returns a (roundtrippable) hash representation for MARC-in-JSON
266
281
  def to_hash
267
- record_hash = {'leader'=>@leader, 'fields'=>[]}
282
+ record_hash = {'leader' => @leader, 'fields' => []}
268
283
  @fields.each do |field|
269
284
  record_hash['fields'] << field.to_hash
270
285
  end
271
286
  record_hash
272
- end
287
+ end
273
288
 
274
289
  def self.new_from_hash(h)
275
- r = self.new
290
+ r = self.new
276
291
  r.leader = h['leader']
277
292
  if h['fields']
278
293
  h['fields'].each do |position|
279
294
  position.each_pair do |tag, field|
280
295
  if field.is_a?(Hash)
281
296
  f = MARC::DataField.new(tag, field['ind1'], field['ind2'])
282
- field['subfields'].each do | pos |
297
+ field['subfields'].each do |pos|
283
298
  pos.each_pair do |code, value|
284
299
  f.append MARC::Subfield.new(code, value)
285
300
  end
@@ -290,9 +305,10 @@ module MARC
290
305
  end
291
306
  end
292
307
  end
293
- end
294
- return r
308
+ end
309
+ return r
295
310
  end
311
+
296
312
  # Returns a string version of the record, suitable for printing
297
313
 
298
314
  def to_s
@@ -315,7 +331,7 @@ module MARC
315
331
  # if record =~ /Gravity's Rainbow/ then print "Slothrop" end
316
332
 
317
333
  def =~(regex)
318
- return self.to_s =~ regex
334
+ return self.to_s =~ regex
319
335
  end
320
336
 
321
337
  end
@@ -1,3 +1,3 @@
1
1
  module MARC
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Clarke
@@ -13,54 +13,60 @@ authors:
13
13
  autorequire: marc
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2015-01-28 00:00:00.000000000 Z
16
+ date: 2017-08-01 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
+ name: scrub_rb
19
20
  requirement: !ruby/object:Gem::Requirement
20
21
  requirements:
21
- - - '>='
22
+ - - ">="
22
23
  - !ruby/object:Gem::Version
23
24
  version: 1.0.1
24
- - - <
25
+ - - "<"
25
26
  - !ruby/object:Gem::Version
26
27
  version: '2'
27
- name: scrub_rb
28
- prerelease: false
29
28
  type: :runtime
29
+ prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: 1.0.1
35
- - - <
35
+ - - "<"
36
36
  - !ruby/object:Gem::Version
37
37
  version: '2'
38
38
  - !ruby/object:Gem::Dependency
39
+ name: unf
39
40
  requirement: !ruby/object:Gem::Requirement
40
41
  requirements:
41
- - - '>='
42
+ - - ">="
42
43
  - !ruby/object:Gem::Version
43
44
  version: '0'
44
- name: unf
45
- prerelease: false
46
45
  type: :runtime
46
+ prerelease: false
47
47
  version_requirements: !ruby/object:Gem::Requirement
48
48
  requirements:
49
- - - '>='
49
+ - - ">="
50
50
  - !ruby/object:Gem::Version
51
51
  version: '0'
52
- description:
52
+ description:
53
53
  email: ehs@pobox.com
54
54
  executables: []
55
55
  extensions: []
56
56
  extra_rdoc_files: []
57
57
  files:
58
+ - Changes
59
+ - LICENSE
60
+ - README.md
61
+ - Rakefile
58
62
  - lib/marc.rb
59
63
  - lib/marc/constants.rb
60
64
  - lib/marc/controlfield.rb
61
65
  - lib/marc/datafield.rb
62
66
  - lib/marc/dublincore.rb
63
67
  - lib/marc/exception.rb
68
+ - lib/marc/marc8/map_to_unicode.rb
69
+ - lib/marc/marc8/to_unicode.rb
64
70
  - lib/marc/reader.rb
65
71
  - lib/marc/record.rb
66
72
  - lib/marc/subfield.rb
@@ -69,14 +75,16 @@ files:
69
75
  - lib/marc/xml_parsers.rb
70
76
  - lib/marc/xmlreader.rb
71
77
  - lib/marc/xmlwriter.rb
72
- - lib/marc/marc8/map_to_unicode.rb
73
- - lib/marc/marc8/to_unicode.rb
74
78
  - test/bad_eacc_encoding.marc8.marc
75
79
  - test/batch.dat
76
80
  - test/batch.xml
77
81
  - test/cp866_multirecord.marc
78
82
  - test/cp866_unimarc.marc
79
83
  - test/escaped_character_reference.marc8.marc
84
+ - test/marc8/data/test_marc8.txt
85
+ - test/marc8/data/test_utf8.txt
86
+ - test/marc8/tc_marc8_mapping.rb
87
+ - test/marc8/tc_to_unicode.rb
80
88
  - test/marc8_accented_chars.marc
81
89
  - test/marc_with_bad_utf8.utf8.marc
82
90
  - test/no-leading-zero.xml
@@ -102,38 +110,29 @@ files:
102
110
  - test/utf8.marc
103
111
  - test/utf8_multirecord.marc
104
112
  - test/utf8_with_bad_bytes.marc
105
- - test/marc8/tc_marc8_mapping.rb
106
- - test/marc8/tc_to_unicode.rb
107
- - test/marc8/data/test_marc8.txt
108
- - test/marc8/data/test_utf8.txt
109
- - Rakefile
110
- - README.md
111
- - Changes
112
- - LICENSE
113
113
  homepage: https://github.com/ruby-marc/ruby-marc/
114
114
  licenses:
115
115
  - MIT
116
116
  metadata: {}
117
- post_install_message:
117
+ post_install_message:
118
118
  rdoc_options: []
119
119
  require_paths:
120
120
  - lib
121
121
  required_ruby_version: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - '>='
123
+ - - ">="
124
124
  - !ruby/object:Gem::Version
125
125
  version: 1.8.6
126
126
  required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - '>='
128
+ - - ">="
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
131
  requirements: []
132
- rubyforge_project:
133
- rubygems_version: 2.1.9
134
- signing_key:
132
+ rubyforge_project:
133
+ rubygems_version: 2.6.8
134
+ signing_key:
135
135
  specification_version: 4
136
136
  summary: A ruby library for working with Machine Readable Cataloging
137
137
  test_files:
138
138
  - test/ts_marc.rb
139
- has_rdoc: true