gedcom 0.9.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.
Files changed (75) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +74 -0
  3. data/README.txt +129 -0
  4. data/Rakefile +13 -0
  5. data/lib/gedcom.rb +105 -0
  6. data/lib/gedcom/address_record.rb +77 -0
  7. data/lib/gedcom/adoption_record.rb +57 -0
  8. data/lib/gedcom/association_record.rb +79 -0
  9. data/lib/gedcom/cause_record.rb +45 -0
  10. data/lib/gedcom/change_date_record.rb +39 -0
  11. data/lib/gedcom/character_set_record.rb +41 -0
  12. data/lib/gedcom/citation_data_record.rb +49 -0
  13. data/lib/gedcom/citation_event_type_record.rb +42 -0
  14. data/lib/gedcom/corporate_record.rb +36 -0
  15. data/lib/gedcom/date_record.rb +206 -0
  16. data/lib/gedcom/encoded_line_record.rb +34 -0
  17. data/lib/gedcom/event_age_record.rb +36 -0
  18. data/lib/gedcom/event_record.rb +258 -0
  19. data/lib/gedcom/events_list_record.rb +61 -0
  20. data/lib/gedcom/families_individuals.rb +79 -0
  21. data/lib/gedcom/family_record.rb +89 -0
  22. data/lib/gedcom/gedcom_all.rb +41 -0
  23. data/lib/gedcom/gedcom_base.rb +337 -0
  24. data/lib/gedcom/gedcom_record.rb +44 -0
  25. data/lib/gedcom/header_data_record.rb +49 -0
  26. data/lib/gedcom/header_record.rb +75 -0
  27. data/lib/gedcom/header_source_record.rb +42 -0
  28. data/lib/gedcom/individual_attribute_record.rb +86 -0
  29. data/lib/gedcom/individual_record.rb +128 -0
  30. data/lib/gedcom/multimedia_citation_record.rb +55 -0
  31. data/lib/gedcom/multimedia_record.rb +72 -0
  32. data/lib/gedcom/name_record.rb +58 -0
  33. data/lib/gedcom/note_citation_record.rb +37 -0
  34. data/lib/gedcom/note_record.rb +61 -0
  35. data/lib/gedcom/place_record.rb +46 -0
  36. data/lib/gedcom/refn_record.rb +32 -0
  37. data/lib/gedcom/repository_caln.rb +33 -0
  38. data/lib/gedcom/repository_citation_record.rb +43 -0
  39. data/lib/gedcom/repository_record.rb +41 -0
  40. data/lib/gedcom/source_citation_record.rb +74 -0
  41. data/lib/gedcom/source_record.rb +84 -0
  42. data/lib/gedcom/source_scope_record.rb +35 -0
  43. data/lib/gedcom/submission_record.rb +53 -0
  44. data/lib/gedcom/submitter_record.rb +53 -0
  45. data/lib/gedcom/text_record.rb +31 -0
  46. data/lib/gedcom/trailer_record.rb +22 -0
  47. data/lib/gedcom/transmission.rb +103 -0
  48. data/lib/gedcom/transmission_base.rb +267 -0
  49. data/lib/parser/class_tracker.rb +33 -0
  50. data/lib/parser/ged_line.rb +99 -0
  51. data/lib/parser/gedcom_parser.rb +798 -0
  52. data/lib/parser/instruction.rb +14 -0
  53. data/lib/parser/parse_state.rb +49 -0
  54. data/test/test_gedcom.rb +7 -0
  55. data/test_data/Document.RTF +1 -0
  56. data/test_data/Document.tex +1 -0
  57. data/test_data/ImgFile.BMP +0 -0
  58. data/test_data/ImgFile.GIF +0 -0
  59. data/test_data/ImgFile.JPG +0 -0
  60. data/test_data/ImgFile.MAC +0 -0
  61. data/test_data/ImgFile.PCX +0 -0
  62. data/test_data/ImgFile.PIC +0 -0
  63. data/test_data/ImgFile.PNG +0 -0
  64. data/test_data/ImgFile.PSD +0 -0
  65. data/test_data/ImgFile.TGA +0 -0
  66. data/test_data/ImgFile.TIF +0 -0
  67. data/test_data/README.txt +1 -16
  68. data/test_data/TGC551.ged +1 -0
  69. data/test_data/TGC551LF.ged +2162 -0
  70. data/test_data/TGC55C.ged +1 -0
  71. data/test_data/TGC55CLF.ged +2202 -0
  72. data/test_data/force.wav +0 -0
  73. data/test_data/suntun.mov +0 -0
  74. data/test_data/top.mpg +0 -0
  75. metadata +140 -0
@@ -0,0 +1,89 @@
1
+ require 'gedcom_base.rb'
2
+
3
+ #Family_record is the internal representation of a level 0 GEDCOM FAM record.
4
+ #
5
+ #=FAM_RECORD:=
6
+ # 0 @<XREF:FAM>@ FAM {0:M}
7
+ # +1 <<FAMILY_EVENT_STRUCTURE>> {0:M} p.28
8
+ # +2 HUSB {0:1}
9
+ # +3 AGE <AGE_AT_EVENT> {1:1} p.35
10
+ # +2 WIFE {0:1}
11
+ # +3 AGE <AGE_AT_EVENT> {1:1}
12
+ # +1 HUSB @<XREF:INDI>@ {0:1} p.52
13
+ # +1 WIFE @<XREF:INDI>@ {0:1} p.52
14
+ # +1 CHIL @<XREF:INDI>@ {0:M} p.52
15
+ # +1 NCHI <COUNT_OF_CHILDREN> {0:1} p.37
16
+ # +1 SUBM @<XREF:SUBM>@ {0:M} p.52
17
+ # +1 <<LDS_SPOUSE_SEALING>> {0:M} p.30
18
+ # +1 <<SOURCE_CITATION>> {0:M} p.32
19
+ # +1 <<MULTIMEDIA_LINK>> {0:M} p.30,23
20
+ # +1 <<NOTE_STRUCTURE>> {0:M} p.31
21
+ # +1 REFN <USER_REFERENCE_NUMBER> {0:M} p.51
22
+ # +2 TYPE <USER_REFERENCE_TYPE> {0:1} p.51
23
+ # +1 RIN <AUTOMATED_RECORD_ID> {0:1} p.36
24
+ # +1 <<CHANGE_DATE>> {0:1} p.27
25
+ #
26
+ # The FAMily record is used to record marriages, common law marriages, and family unions caused by
27
+ # two people becoming the parents of a child (i.e they may not be married). There can be no more
28
+ # than one HUSB/father and one WIFE/mother listed in each FAM_RECORD. We are recording parentage,
29
+ # rather than marriages per se. If, for example, a man participated in more than one
30
+ # family union (or with more than 1 wife) then he would appear in more than one FAM_RECORD. The
31
+ # family record structure assumes that the HUSB/father is male and WIFE/mother is female. Again,
32
+ # as we are recording parentage, and we can't yet clone or reproduce from two males. or from two females.
33
+ #
34
+ # The preferred order of the CHILdren pointers within a FAMily structure is chronological by birth.
35
+ #
36
+ #The attributes are all arrays for the level +1 tags/records.
37
+ #* Those ending in _ref are GEDCOM XREF index keys
38
+ #* Those ending in _record are array of classes of that type.
39
+ #* The remainder are arrays of attributes that could be present in this record.
40
+ class Family_record < GEDCOMBase
41
+ attr_accessor :restriction #not standard at the event level, but we might want this in DB.
42
+ attr_accessor :family_ref, :event_record, :husband_ref, :wife_ref, :child_ref, :number_children, :submitter_ref
43
+ attr_accessor :source_citation_record, :multimedia_citation_record
44
+ attr_accessor :note_citation_record, :refn_record, :automated_record_id, :change_date_record
45
+
46
+ ClassTracker << :Family_record
47
+
48
+ #new sets up the state engine arrays @this_level and @sub_level, which drive the to_gedcom method generating GEDCOM output.
49
+ def initialize(*a)
50
+ super(*a)
51
+ @this_level = [ [:xref, "FAM", :family_ref] ]
52
+ @sub_level = [ #level + 1
53
+ [:xref, "HUSB", :husband_ref],
54
+ [:xref, "WIFE", :wife_ref],
55
+ [:xref, "CHIL", :child_ref],
56
+ [:print, "NCHI", :number_children],
57
+ [:walk, nil, :event_record],
58
+ [:xref, "SUBM", :submitter_ref],
59
+ [:walk, nil, :multimedia_citation_record],
60
+ [:walk, nil, :source_citation_record],
61
+ [:walk, nil, :note_citation_record],
62
+ [:walk, nil, :refn_record],
63
+ [:print, "RIN", :automated_record_id],
64
+ [:walk, nil, :change_date_record],
65
+ ]
66
+ end
67
+
68
+ def id
69
+ #temporary
70
+ @family_ref
71
+ end
72
+
73
+ def husband
74
+ if @husband_ref != nil
75
+ find(@husband_ref[0], @husband_ref[1])
76
+ else
77
+ nil
78
+ end
79
+ end
80
+
81
+ def wife
82
+ if @wife_ref != nil
83
+ find(@wife_ref[0], @wife_ref[1])
84
+ else
85
+ nil
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,41 @@
1
+ require 'address_record.rb'
2
+ require 'adoption_record.rb'
3
+ require 'cause_record.rb'
4
+ require 'change_date_record.rb'
5
+ require 'character_set_record.rb'
6
+ require 'citation_data_record.rb'
7
+ require 'citation_event_type_record.rb'
8
+ require 'corporate_record.rb'
9
+ require 'date_record.rb'
10
+ require 'encoded_line_record.rb'
11
+ require 'event_age_record.rb'
12
+ require 'event_record.rb'
13
+ require 'events_list_record.rb'
14
+ require 'families_individuals.rb'
15
+ require 'family_record.rb'
16
+ require 'gedcom_base.rb'
17
+ require 'gedcom_record.rb'
18
+ require 'header_data_record.rb'
19
+ require 'header_record.rb'
20
+ require 'header_source_record.rb'
21
+ require 'individual_attribute_record.rb'
22
+ require 'individual_record.rb'
23
+ require 'association_record.rb'
24
+ require 'multimedia_citation_record.rb'
25
+ require 'multimedia_record.rb'
26
+ require 'name_record.rb'
27
+ require 'note_citation_record.rb'
28
+ require 'note_record.rb'
29
+ require 'place_record.rb'
30
+ require 'refn_record.rb'
31
+ require 'repository_caln.rb'
32
+ require 'repository_citation_record.rb'
33
+ require 'repository_record.rb'
34
+ require 'source_citation_record.rb'
35
+ require 'source_record.rb'
36
+ require 'source_scope_record.rb'
37
+ require 'submission_record.rb'
38
+ require 'submitter_record.rb'
39
+ require 'text_record.rb'
40
+ require 'trailer_record.rb'
41
+ require 'transmission_base.rb'
@@ -0,0 +1,337 @@
1
+ require "class_tracker.rb"
2
+ require "instruction.rb"
3
+
4
+ #base routines shared by all gedcom objects.
5
+ class GEDCOMBase
6
+ attr_accessor :class_stack, :indexes
7
+ @@tabs = false #If true, indent gedcom lines on output a tab per level. Normally wouldn't have tabs in a transmission file.
8
+
9
+ #Create a new GEDCOMBase or most likely a subclass of GEDCOMBase.
10
+ #* transmission is the current transmission this object came from.
11
+ # This is useful in searchs of the transmission, starting from a reference in a record in that transmission.
12
+ #* changed indicates that we have altered the data in the record
13
+ # The default is true, as the normal instantiation is creating a new record.
14
+ # to_db uses this to determine if the record needs to be saved to the DB.
15
+ #* created indicates that this is a new record, rather than one we may have loaded from a DB.
16
+ def initialize(transmission = nil, changed=true,created=true)
17
+ @changed = changed
18
+ @created = created
19
+ @this_level = []
20
+ @sub_level = []
21
+ @transmission = transmission
22
+ end
23
+
24
+ #sets @@tabs to true.
25
+ #This indents gedcom lines on output a tab per level.
26
+ #This is useful if pretty printing, but not normal in a gedcom file
27
+ #as most GEDCOM file parsers don't like leading tabs on lines of a transmission file.
28
+ #I use this only for debugging.
29
+ def self.tabs
30
+ @@tabs = true
31
+ end
32
+
33
+ #sets @@tabs to false.
34
+ #This is the default as a lot of GEDCOM parsers don't like leading white space on lines.
35
+ def self.no_tabs
36
+ @@tabs = false #The default
37
+ end
38
+
39
+ #Marks this object as having been altered so we know to synchronise it with the DB.
40
+ def changed
41
+ @changed = true
42
+ end
43
+
44
+ #Tests for this object having been altered, so we know to synchronise it with the DB.
45
+ def changed?
46
+ @changed
47
+ end
48
+
49
+ #Tests to see if this is a new object, not one we have loaded from elsewhere (say a DB)
50
+ def created?
51
+ @created
52
+ end
53
+
54
+ #create a string from the objects instance variables, one per line, in the form "variable = value\n" ... .
55
+ #For an ordered list, see to_s_ordered
56
+ def to_s
57
+ s = ''
58
+ self.instance_variables.each do |v| #look at each of the instance variables
59
+ if self.class.method_defined?(v_sym = v[1..-1].to_sym) #see if there is a method defined for this symbol (strip the :)
60
+ s += "#{v} = " + pv_byname(v_sym) + "\n" #print it
61
+ end
62
+ end
63
+ s
64
+ end
65
+
66
+ #Need to flesh this out. Right now it pretends to work and marks records as saved.
67
+ def to_db(level = 0, this_level=[], sub_levels=[])
68
+ @changed = false
69
+ @created = false
70
+ end
71
+
72
+ #This is the default method, used by all classes inheriting from GEDCOMBase, to recursively generate GEDCOM lines from that Object downward.
73
+ #All subclasses of GEDCOMBase are expected to define @this_level and @sub_level arrays, which are instructions to to_s_r on how to generate
74
+ #GEDCOM lines from the attributes of the object.
75
+ def to_gedcom(level = 0)
76
+ to_s_r( level, @this_level, @sub_level )
77
+ end
78
+
79
+ #This is the default method, used by all classes inheriting from GEDCOMBase, to recursively save the object and its sub-records to a DB.
80
+ #All subclasses of GEDCOMBase are expected to define @this_level and @sub_level arrays, which are instructions to to_db on how to generate
81
+ #GEDCOM lines from the attributes of the object.
82
+ def save
83
+ to_db( level, @this_level, @sub_level)
84
+ end
85
+
86
+ private
87
+
88
+ #Somewhat cryptic. This takes the symbol (variable name) and returns the object associatied with it.
89
+ def pv_byname(v_sym, indent = 0)
90
+ a = self.send( v_sym )
91
+ pv(a)
92
+ end
93
+
94
+ #return a string of ',' separated values stored in the object in the variable v.
95
+ def pv(v)
96
+ s = ''
97
+ if v == nil #nil object
98
+ s += 'nil'
99
+ elsif v.class == Array #object is an Array, so enumerate each to get each value (with recursive call).
100
+ s += "[\n"
101
+ s += v.inject('') { |x,y| x + pv(y) + ',' }
102
+ s[-1,1] = "\n"
103
+ s += "]"
104
+ s
105
+ else #object is singular, so return its to_s value if it has one.
106
+ if x = v.to_s
107
+ s += x
108
+ else
109
+ s += 'nil'
110
+ end
111
+ end
112
+ end
113
+
114
+ #Return and empty string unless @@tabs is true.
115
+ #Returns a string of tabs (actually of pairs of spaces), one pair per GEDCOM level.
116
+ #Used to indent GEDCOM output for pretty printing.
117
+ def tabstop(level)
118
+ #printing aid for indenting each level
119
+ return "" if !@@tabs || level <= 0
120
+ ' ' * level
121
+ end
122
+
123
+ #Returns a GEDCOM line, with optional leading tabs.
124
+ def single_line(level, tag, data = nil)
125
+ #printing aid for tags that can have CONT or CONC sub-tags
126
+ s_out = "#{tabstop(level)}#{level} #{tag}"
127
+ if data != nil
128
+ data.each do |word|
129
+ if word != "\n"
130
+ s_out += " #{word}"
131
+ end
132
+ end
133
+ end
134
+ s_out += "\n"
135
+ end
136
+
137
+ #Returns a GEDCOM line for this tag, with CONC lines if the length
138
+ #of a line exceeds the GEDCOM standard line length.
139
+ #Recognises '\n' chars in the data and creates a CONT line after the '\n'
140
+ #Recognised @@tab to indent lines if pretty printing the output.
141
+ #Nb. Lots of GEDCOM files ignore the line lengths in the standard, so this
142
+ #method can created extra CONC lines in the output if a transmission is read
143
+ #then dumped again.
144
+ #The standard says that
145
+ #* Leading white space should be ignored, though a lot of systems can't cope with leading white space.
146
+ #* levels can be up to 2 digits (i.e. up to 99). 0 - 9 should not have a leading 0.
147
+ #* XREFs can be 20 chars plus 2 for the enclosing '@'s
148
+ #* GEDCOM tags can be 31 chars (though only 15 matter). No tag in the standard is bigger than 4 chars
149
+ #* The Line terminator can end in LF, CR LF, CR, LF CR.
150
+ #* The entire record should be no more than 32K, which mainly affects inline multimedia records.
151
+ #* Individual lines should not exceed 255 bytes (not chars). This is effectively a max line buffer size.
152
+ #* This includes the leading-space + level + delimiter + tag + delimiter + xref + delimiter + data-value + line-terminator.
153
+ #* Many data values have tag specific recommended lengths for use in fixed length data base schemas.
154
+ # These are usually much smaller than the line length would allow.
155
+ def cont_conc(level,tag, conc=nil, data = nil)
156
+ #printing aid for tags that can have CONT or CONC sub-tags
157
+ s_out = "#{tabstop(level)}#{level} #{tag}"
158
+ nlevel = level + (conc ? 0 : 1)
159
+
160
+ if data != nil
161
+ length = s_out.length
162
+ data.each_with_index do |word,i|
163
+ if length > 253 && word != "\n" && data.length != i #253 allows for CR LF or LF CR pairs as the line terminator.
164
+ s_tmp = "#{tabstop(nlevel)}#{nlevel} CONC"
165
+ length = s_tmp.length #new line, so reset length
166
+ s_out += "\n" + s_tmp
167
+ end
168
+ s_out += " #{word}"
169
+ if word == "\n"
170
+ s_tmp = "#{tabstop(nlevel)}#{nlevel} CONT" #Start a CONT line after the '\n'
171
+ length = s_tmp.length #new line, so reset length
172
+ s_out += s_tmp
173
+ else
174
+ length += word.length
175
+ end
176
+ end
177
+ end
178
+ s_out += "\n"
179
+ end
180
+
181
+ #Generate a Multimedia_record's Encoded_line_record.
182
+ #This is an inline Multimedia data source, rather than a file reference.
183
+ #The blob is stored internally as a multiline string. In the GEDCOM file
184
+ #a blob is stored as multiple GEDCOM lines. The first uses a BLOB tag.
185
+ #Subsequent lines use CONT tags.
186
+ def blob(level, data = nil)
187
+ #blobs only have CONT sub-tags
188
+ s_out = "#{tabstop(level)}#{level} CONT"
189
+
190
+ if data != nil
191
+ data.each_with_index do |word,i|
192
+ s_out += " #{word}"
193
+ if word == "\n"
194
+ s_out += "#{tabstop(level)}#{level} CONT"
195
+ end
196
+ end
197
+ end
198
+ s_out += "\n"
199
+ end
200
+
201
+ #returns a XREF gedcom line.
202
+ #Level 0 GEDCOM has the @XREF@ before the tag.
203
+ #Level n GEDCOM records have the @XREF@ after the tag.
204
+ def xref(level, tag, xref)
205
+ if level == 0
206
+ "#{tabstop(level)}#{level} @#{xref}@ #{tag}\n"
207
+ else
208
+ "#{tabstop(level)}#{level} #{tag} @#{xref}@\n"
209
+ end
210
+ end
211
+
212
+ #Process an instruction, defined by action, for this level, tag and data value
213
+ #The actions:
214
+ #* :xref indicates that we need to generate a GEDCOM line with an @XREF@ tag
215
+ #* :print indicates that we need to generate a non-XREF GEDCOM line
216
+ #* :conc indicates that this GEDCOM line can be split into multiple lines with CONC or CONT
217
+ # The first line output uses the tag, subsequent lines use CONC or CONT.
218
+ #* :cont indicates that this GEDCOM line con be split into multiple lines with CONC or CONT.
219
+ # This differs for :conc, in that the tags level starts at level+1, not at level.
220
+ #* :blob indicates the GEDCOM line can be split over multiple lines using just CONT tags.
221
+ # These occur in inline multimedia records.
222
+ #* :date outputs a GEDCOM date line from a Date_record
223
+ #* :time outputs a GEDCOM time line from a Time_record
224
+ #* :nodata indicates that only the level and tag need to output. There is no data value.
225
+ #* :walk indicates this item is a sub-record, therefore we need to recurse and process it using
226
+ # its action arrays, not this objects action arrays. These are the @this_level and @sub_level
227
+ # arrays, which are usually defined in the classes initialize method, but sometimes in a
228
+ # an object specific to_gedcom method.
229
+ def to_s_r_action(level, action, tag, data=nil)
230
+ case action
231
+ when :xref then
232
+ xref_check(level, tag, data[0], data[1])
233
+ xref(level, tag, data[1])
234
+ when :print then single_line(level, tag, data )
235
+ when :conc then cont_conc(level, tag, true, data )
236
+ when :cont then cont_conc(level, tag, false, data )
237
+ when :blob then blob(level, data )
238
+ when :walk then data.to_gedcom(level)
239
+ when :date then single_line(level, tag, data ) #fix later to format date records
240
+ when :time then single_line(level, tag, data ) #fix later to format time records
241
+ when :nodata then single_line(level, tag, nil )
242
+ end
243
+ end
244
+
245
+ protected
246
+
247
+ #validate that the record referenced by the XREF actually exists in this transmission.
248
+ #Genearte a warning if it does not. It does not stop the processing of this line.
249
+ def xref_check(level, tag, index, xref)
250
+ if @transmission != nil && @transmission.find(index, xref) == nil
251
+ #Warning message that reference points to an unknown target.
252
+ print "#{level+1} NOTE ****************Key not found: #{index} #{xref}\n"
253
+ end
254
+ end
255
+
256
+ #to_s with the variable list (as symbols) passed to it in the order they are to be printed
257
+ def to_s_ordered(variable_list)
258
+ if variable_list != nil
259
+ s = ''
260
+ variable_list.each do |v|
261
+ s += "@#{v} = " + pv_byname(v) + "\n"
262
+ end
263
+ s
264
+ else
265
+ ''
266
+ end
267
+ end
268
+
269
+
270
+ #recursive to_s. We want to print this object and its sub-records.
271
+ #the definition of how we want to print and when to recurse, is in the this_level and sub_level arrays.
272
+ #These have the form [ [ action, tag, data_source ],...] (see to_s_r_action )
273
+ def to_s_r(level = 0, this_level=[], sub_levels=[])
274
+ s_out = ""
275
+ this_level.each do |l|
276
+ this_level_instruction = Instruction.new(l)
277
+ if this_level_instruction.data != nil
278
+ data = self.send( this_level_instruction.data ) #gets the contents using the symbol, and sending "self" a message
279
+ else
280
+ data = [['']]
281
+ end
282
+ if data != nil #could be if the self.send targets a variable that doesn't exist.
283
+ data.each do |data_instance|
284
+ s_out += to_s_r_action(level, this_level_instruction.action, this_level_instruction.tag, data_instance)
285
+
286
+ sub_levels.each do |sl|
287
+ sub_level_instruction = Instruction.new(sl)
288
+ if sub_level_instruction.data != nil
289
+ sub_level_data = self.send( sub_level_instruction.data ) #gets the contents using the symbol, and sending "self" a message
290
+ else
291
+ sub_level_data = [['']]
292
+ end
293
+ if sub_level_data != nil #could be if the self.send targets a variable that doesn't exist.
294
+ sub_level_data.each do |sub_data_instance|
295
+ s_out += to_s_r_action(level+1, sub_level_instruction.action, sub_level_instruction.tag, sub_data_instance )
296
+ end
297
+ end
298
+ end
299
+
300
+ end
301
+ end
302
+ end
303
+ return s_out
304
+ end
305
+
306
+
307
+
308
+ end
309
+
310
+
311
+
312
+
313
+
314
+
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+
337
+