gedcom 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
+