restfulie 0.8.0 → 0.8.1
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/Gemfile +10 -5
- data/Rakefile +5 -2
- data/lib/restfulie.rb +10 -5
- data/lib/restfulie/client.rb +13 -9
- data/lib/restfulie/client/base.rb +24 -65
- data/lib/restfulie/client/configuration.rb +62 -64
- data/lib/restfulie/client/entry_point.rb +36 -0
- data/lib/restfulie/client/ext/atom_ext.rb +12 -0
- data/lib/restfulie/client/ext/http_ext.rb +22 -0
- data/lib/restfulie/client/ext/json_ext.rb +12 -0
- data/lib/restfulie/client/ext/xml_ext.rb +4 -0
- data/lib/restfulie/client/http.rb +25 -13
- data/lib/restfulie/client/http/cache.rb +22 -22
- data/lib/restfulie/client/http/error.rb +70 -70
- data/lib/restfulie/client/http/link_request_builder.rb +15 -0
- data/lib/restfulie/client/http/request_adapter.rb +209 -0
- data/lib/restfulie/client/http/request_builder.rb +107 -0
- data/lib/restfulie/client/http/request_builder_executor.rb +24 -0
- data/lib/restfulie/client/http/request_executor.rb +17 -0
- data/lib/restfulie/client/http/request_follow.rb +42 -0
- data/lib/restfulie/client/http/request_follow_executor.rb +10 -0
- data/lib/restfulie/client/http/request_history.rb +69 -0
- data/lib/restfulie/client/http/request_history_executor.rb +10 -0
- data/lib/restfulie/client/http/request_marshaller.rb +127 -0
- data/lib/restfulie/client/http/request_marshaller_executor.rb +10 -0
- data/lib/restfulie/client/http/response.rb +23 -0
- data/lib/restfulie/client/http/response_handler.rb +67 -0
- data/lib/restfulie/client/http/response_holder.rb +9 -0
- data/lib/restfulie/client/mikyung.rb +17 -14
- data/lib/restfulie/client/mikyung/concatenator.rb +15 -12
- data/lib/restfulie/client/mikyung/core.rb +65 -39
- data/lib/restfulie/client/mikyung/languages.rb +8 -26
- data/lib/restfulie/client/mikyung/languages/german.rb +24 -0
- data/lib/restfulie/client/mikyung/languages/portuguese.rb +23 -0
- data/lib/restfulie/client/mikyung/rest_process_model.rb +184 -107
- data/lib/restfulie/client/mikyung/steady_state_walker.rb +34 -28
- data/lib/restfulie/client/mikyung/then_condition.rb +33 -27
- data/lib/restfulie/client/mikyung/when_condition.rb +53 -49
- data/lib/restfulie/common.rb +7 -12
- data/lib/restfulie/common/converter.rb +20 -9
- data/lib/restfulie/common/converter/atom.rb +8 -83
- data/lib/restfulie/common/converter/atom/base.rb +89 -0
- data/lib/restfulie/common/converter/atom/builder.rb +101 -99
- data/lib/restfulie/common/converter/atom/helpers.rb +16 -8
- data/lib/restfulie/common/converter/json.rb +12 -0
- data/lib/restfulie/common/converter/json/base.rb +84 -0
- data/lib/restfulie/common/converter/json/builder.rb +102 -0
- data/lib/restfulie/common/converter/json/helpers.rb +17 -0
- data/lib/restfulie/common/converter/values.rb +30 -26
- data/lib/restfulie/common/converter/xml.rb +14 -0
- data/lib/restfulie/common/converter/xml/base.rb +61 -0
- data/lib/restfulie/common/converter/xml/builder.rb +112 -0
- data/lib/restfulie/common/converter/xml/helpers.rb +17 -0
- data/lib/restfulie/common/converter/xml/link.rb +25 -0
- data/lib/restfulie/common/converter/xml/links.rb +25 -0
- data/lib/restfulie/common/core_ext.rb +1 -5
- data/lib/restfulie/common/core_ext/hash.rb +12 -0
- data/lib/restfulie/common/error.rb +19 -0
- data/lib/restfulie/common/logger.rb +17 -9
- data/lib/restfulie/common/representation.rb +9 -10
- data/lib/restfulie/common/representation/atom.rb +15 -47
- data/lib/restfulie/common/representation/atom/base.rb +122 -365
- data/lib/restfulie/common/representation/atom/category.rb +41 -0
- data/lib/restfulie/common/representation/atom/entry.rb +52 -100
- data/lib/restfulie/common/representation/atom/factory.rb +43 -0
- data/lib/restfulie/common/representation/atom/feed.rb +103 -99
- data/lib/restfulie/common/representation/atom/link.rb +68 -0
- data/lib/restfulie/common/representation/atom/person.rb +48 -0
- data/lib/restfulie/common/representation/atom/source.rb +59 -0
- data/lib/restfulie/common/representation/atom/tag_collection.rb +38 -0
- data/lib/restfulie/common/representation/atom/xml.rb +95 -0
- data/lib/restfulie/common/representation/generic.rb +30 -29
- data/lib/restfulie/common/representation/json.rb +10 -22
- data/lib/restfulie/common/representation/json/base.rb +27 -0
- data/lib/restfulie/common/representation/json/keys_as_methods.rb +72 -0
- data/lib/restfulie/common/representation/json/link.rb +29 -0
- data/lib/restfulie/common/representation/json/link_collection.rb +23 -0
- data/lib/restfulie/common/representation/xml.rb +18 -227
- data/lib/restfulie/server.rb +9 -10
- data/lib/restfulie/server/action_controller.rb +10 -12
- data/lib/restfulie/server/action_controller/base.rb +18 -15
- data/lib/restfulie/server/action_controller/{routing/patch.rb → patch.rb} +0 -0
- data/lib/restfulie/server/action_controller/restful_responder.rb +43 -35
- data/lib/restfulie/server/action_view.rb +8 -6
- data/lib/restfulie/server/action_view/helpers.rb +47 -41
- data/lib/restfulie/server/action_view/template_handlers.rb +24 -12
- data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +17 -12
- data/lib/restfulie/server/configuration.rb +22 -19
- data/lib/restfulie/server/{restfulie_controller.rb → controller.rb} +1 -10
- data/lib/restfulie/server/core_ext.rb +1 -1
- data/lib/restfulie/version.rb +14 -0
- metadata +52 -16
- data/lib/restfulie/client/http/adapter.rb +0 -502
- data/lib/restfulie/client/http/atom_ext.rb +0 -4
- data/lib/restfulie/client/http/core_ext.rb +0 -6
- data/lib/restfulie/client/http/core_ext/http.rb +0 -19
- data/lib/restfulie/client/http/marshal.rb +0 -145
- data/lib/restfulie/client/http/xml_ext.rb +0 -7
- data/lib/restfulie/common/core_ext/proc.rb +0 -48
- data/lib/restfulie/common/errors.rb +0 -15
- data/lib/restfulie/server/action_controller/routing.rb +0 -12
- data/lib/restfulie/server/action_controller/routing/restful_route.rb +0 -14
@@ -0,0 +1,68 @@
|
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
module Atom
|
5
|
+
class Link < XML
|
6
|
+
def initialize(options_or_obj)
|
7
|
+
if options_or_obj.kind_of?(Hash)
|
8
|
+
@doc = Nokogiri::XML::Document.new()
|
9
|
+
options_or_obj = create_element("link", options_or_obj)
|
10
|
+
end
|
11
|
+
super(options_or_obj)
|
12
|
+
end
|
13
|
+
|
14
|
+
def href
|
15
|
+
@doc["href"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def href=(value)
|
19
|
+
@doc["href"] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def rel
|
23
|
+
@doc["rel"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def rel=(value)
|
27
|
+
@doc["rel"] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
if method_defined?(:type)
|
31
|
+
alias_method :__type__, :type
|
32
|
+
end
|
33
|
+
def type
|
34
|
+
@doc["type"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def type=(value)
|
38
|
+
@doc["type"] = value
|
39
|
+
end
|
40
|
+
|
41
|
+
def hreflang
|
42
|
+
@doc["hreflang"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def hreflang=(value)
|
46
|
+
@doc["hreflang"] = value
|
47
|
+
end
|
48
|
+
|
49
|
+
def title
|
50
|
+
@doc["title"]
|
51
|
+
end
|
52
|
+
|
53
|
+
def title=(value)
|
54
|
+
@doc["title"] = value
|
55
|
+
end
|
56
|
+
|
57
|
+
def length
|
58
|
+
@doc["length"]
|
59
|
+
end
|
60
|
+
|
61
|
+
def length=(value)
|
62
|
+
@doc["length"] = value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
module Atom
|
5
|
+
class Person < XML
|
6
|
+
def initialize(node_type, options_or_obj)
|
7
|
+
if options_or_obj.kind_of?(Hash)
|
8
|
+
@doc = Nokogiri::XML::Document.new()
|
9
|
+
node = @doc.create_element(node_type)
|
10
|
+
node.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
|
11
|
+
node.parent = @doc
|
12
|
+
super(node)
|
13
|
+
options_or_obj.each do |key,value|
|
14
|
+
self.send("#{key}=".to_sym, value)
|
15
|
+
end
|
16
|
+
else
|
17
|
+
super(options_or_obj)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def name
|
22
|
+
text("name")
|
23
|
+
end
|
24
|
+
|
25
|
+
def name=(value)
|
26
|
+
set_text("name", value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def uri
|
30
|
+
text("uri")
|
31
|
+
end
|
32
|
+
|
33
|
+
def uri=(value)
|
34
|
+
set_text("uri", value)
|
35
|
+
end
|
36
|
+
|
37
|
+
def email
|
38
|
+
text("email")
|
39
|
+
end
|
40
|
+
|
41
|
+
def email=(value)
|
42
|
+
set_text("email", value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
module Atom
|
5
|
+
class Source < XML
|
6
|
+
def initialize(options_or_obj)
|
7
|
+
if options_or_obj.kind_of?(Hash)
|
8
|
+
@doc = Nokogiri::XML::Document.new()
|
9
|
+
node = @doc.create_element("source")
|
10
|
+
node.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
|
11
|
+
node.parent = @doc
|
12
|
+
super(node)
|
13
|
+
options_or_obj.each do |key,value|
|
14
|
+
self.send("#{key}=".to_sym, value)
|
15
|
+
end
|
16
|
+
else
|
17
|
+
super(options_or_obj)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def id
|
22
|
+
text("id")
|
23
|
+
end
|
24
|
+
|
25
|
+
def id=(value)
|
26
|
+
set_text("id", value)
|
27
|
+
end
|
28
|
+
|
29
|
+
# text
|
30
|
+
def title
|
31
|
+
text("title")
|
32
|
+
end
|
33
|
+
|
34
|
+
def title=(value)
|
35
|
+
set_text("title", value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def updated
|
39
|
+
value = text("updated")
|
40
|
+
Time.parse(value) unless value.nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
def updated=(value)
|
44
|
+
set_text("updated", value)
|
45
|
+
end
|
46
|
+
|
47
|
+
# text
|
48
|
+
def rights
|
49
|
+
text("rights")
|
50
|
+
end
|
51
|
+
|
52
|
+
def rights=(value)
|
53
|
+
set_text("rights", value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
module Atom
|
5
|
+
class TagCollection < ::Array
|
6
|
+
def initialize(parent_node, &block)
|
7
|
+
@node = parent_node
|
8
|
+
@method_missing_block = block_given? ? block : nil
|
9
|
+
super(0)
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(obj)
|
13
|
+
obj = [obj] unless obj.kind_of?(Array)
|
14
|
+
obj.each do |o|
|
15
|
+
o.doc.parent = @node
|
16
|
+
super(o)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete(obj)
|
21
|
+
if super(obj)
|
22
|
+
obj.doc.unlink
|
23
|
+
obj = nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(symbol, *args, &block)
|
28
|
+
if @method_missing_block
|
29
|
+
@method_missing_block.call(self, symbol, *args)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
module Atom
|
5
|
+
class XML
|
6
|
+
attr_accessor :doc
|
7
|
+
|
8
|
+
def initialize(xml_obj = nil)
|
9
|
+
if xml_obj
|
10
|
+
xml_obj.kind_of?(Nokogiri::XML::Document) ? @doc = xml_obj.root : @doc = xml_obj
|
11
|
+
else
|
12
|
+
@doc = Nokogiri::XML::Document.new
|
13
|
+
root_node = @doc.create_element(atom_type.to_s)
|
14
|
+
root_node.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
|
15
|
+
root_node.parent = @doc
|
16
|
+
@doc = @doc.root
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Tools
|
21
|
+
def css(*args)
|
22
|
+
@doc.css(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def xpath(*args)
|
26
|
+
@doc.xpath(*args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def atom_type
|
30
|
+
self.class.name.demodulize.downcase
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_xml
|
34
|
+
@doc.to_xml
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
to_xml
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(method)
|
42
|
+
value = text(method)
|
43
|
+
unless value
|
44
|
+
super
|
45
|
+
else
|
46
|
+
value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def text(node_name)
|
53
|
+
(node = @doc.at_xpath("xmlns:#{node_name}")) ? node.content : nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_text(node_name, value)
|
57
|
+
unless (node = @doc.at_xpath("xmlns:#{node_name}"))
|
58
|
+
node = create_element(node_name, value)
|
59
|
+
node.parent = @doc
|
60
|
+
else
|
61
|
+
value = value.xmlschema if value.kind_of?(Time) || value.kind_of?(DateTime)
|
62
|
+
node.content = value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def create_element(node, *args)
|
69
|
+
node = @doc.document.create_element(node) do |n|
|
70
|
+
args.each do |arg|
|
71
|
+
case arg
|
72
|
+
# Adding XML attributes
|
73
|
+
when Hash
|
74
|
+
arg.each { |k,v|
|
75
|
+
key = k.to_s
|
76
|
+
if key =~ /^xmlns(:\w+)?$/
|
77
|
+
ns_name = key.split(":", 2)[1]
|
78
|
+
n.add_namespace_definition(ns_name, v)
|
79
|
+
next
|
80
|
+
end
|
81
|
+
n[k.to_s] = v.to_s
|
82
|
+
}
|
83
|
+
# Adding XML node content
|
84
|
+
else
|
85
|
+
arg.kind_of?(Time) || arg.kind_of?(DateTime) ? content = arg.xmlschema : content = arg
|
86
|
+
n.content = content
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -1,33 +1,34 @@
|
|
1
|
-
module Restfulie
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
# Unknown representation's unmarshalling on the client side
|
5
|
+
class Generic
|
6
|
+
def self.media_type_name
|
7
|
+
raise Error::RestfulieError.new("Generic representation does not have a specific media type")
|
8
|
+
end
|
9
|
+
|
10
|
+
cattr_reader :headers
|
11
|
+
@@headers = {
|
12
|
+
:get => { },
|
13
|
+
:post => { }
|
14
|
+
}
|
15
|
+
|
16
|
+
# Because there is no media type registered, return the content itself
|
17
|
+
def unmarshal(content)
|
18
|
+
def content.links
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
content
|
22
|
+
end
|
23
|
+
|
24
|
+
def marshal(string, rel)
|
25
|
+
string
|
26
|
+
end
|
27
|
+
|
28
|
+
def prepare_link_for(link)
|
29
|
+
link
|
30
|
+
end
|
19
31
|
end
|
20
|
-
content
|
21
|
-
end
|
22
|
-
|
23
|
-
def marshal(string, rel)
|
24
|
-
string
|
25
|
-
end
|
26
|
-
|
27
|
-
def prepare_link_for(link)
|
28
|
-
link
|
29
32
|
end
|
30
33
|
end
|
31
|
-
|
32
34
|
end
|
33
|
-
|
@@ -1,25 +1,13 @@
|
|
1
|
-
module Restfulie
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
:post => { 'Content-Type' => media_type_name }
|
12
|
-
}
|
13
|
-
|
14
|
-
def unmarshal(string)
|
15
|
-
JSON.parse(string)
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
class Json
|
5
|
+
autoload :Base, 'restfulie/common/representation/json/base'
|
6
|
+
autoload :KeysAsMethods, 'restfulie/common/representation/json/keys_as_methods'
|
7
|
+
autoload :Link, 'restfulie/common/representation/json/link'
|
8
|
+
autoload :LinkCollection, 'restfulie/common/representation/json/link_collection'
|
9
|
+
extend Base::ClassMethods
|
10
|
+
end
|
16
11
|
end
|
17
|
-
|
18
|
-
def marshal(entity, rel)
|
19
|
-
return entity if entity.kind_of? String
|
20
|
-
entity.to_json
|
21
|
-
end
|
22
|
-
|
23
12
|
end
|
24
|
-
|
25
13
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
class Json
|
5
|
+
module Base
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
# creates a json unmarshalled version of this object
|
9
|
+
def create(obj = nil)
|
10
|
+
@json = {}
|
11
|
+
return @json.extend(KeysAsMethods) unless obj
|
12
|
+
|
13
|
+
if obj.kind_of?(Hash) || obj.kind_of?(Array)
|
14
|
+
@json = obj
|
15
|
+
else
|
16
|
+
@json = ::JSON.parse(obj)
|
17
|
+
end
|
18
|
+
|
19
|
+
@json.extend(KeysAsMethods)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Restfulie
|
2
|
+
module Common
|
3
|
+
module Representation
|
4
|
+
class Json
|
5
|
+
module KeysAsMethods
|
6
|
+
def self.extended(base)
|
7
|
+
[:type, :id].each { |m| base.__free_method__(m) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
__normalize__(super(key))
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(key, value)
|
15
|
+
super(key,value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
super.to_json
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(name, *args)
|
23
|
+
method_name = name.to_s
|
24
|
+
if method_name.last == '='
|
25
|
+
self[method_name.chop] = args[0]
|
26
|
+
else
|
27
|
+
self[method_name]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# if you have a key that is also a method (such as Array#size)
|
32
|
+
# you can use this to free the method and use the method obj.size
|
33
|
+
# to access the value of key "size".
|
34
|
+
# you still can access the old method with __[method_name]__
|
35
|
+
def __free_method__(sym)
|
36
|
+
if self.__metaclass__.method_defined?(sym) && !respond_to?("__#{sym}__")
|
37
|
+
self.__metaclass__.send(:alias_method, "__#{sym}__", sym)
|
38
|
+
end
|
39
|
+
self.__metaclass__.send(:define_method, sym) { method_missing(sym.to_s) }
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def __metaclass__
|
44
|
+
class << self; self; end
|
45
|
+
end
|
46
|
+
|
47
|
+
# easy accessors to links
|
48
|
+
def links
|
49
|
+
some_links = self["link"]
|
50
|
+
return nil unless some_links
|
51
|
+
some_links = [some_links] unless some_links.kind_of? Array
|
52
|
+
LinkCollection.new(some_links)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def __normalize__(value)
|
58
|
+
case value
|
59
|
+
when Hash
|
60
|
+
value.extend(KeysAsMethods)
|
61
|
+
when Array
|
62
|
+
value.map { |v| __normalize__(v) }
|
63
|
+
else
|
64
|
+
value
|
65
|
+
end
|
66
|
+
value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|