restfulie 0.1.0.beta1 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +87 -99
- data/Rakefile +14 -109
- data/lib/restfulie.rb +183 -23
- metadata +12 -197
- data/Gemfile +0 -28
- data/Gemfile.lock +0 -128
- data/LICENSE +0 -17
- data/lib/restfulie/client.rb +0 -26
- data/lib/restfulie/client/base.rb +0 -36
- data/lib/restfulie/client/cache.rb +0 -11
- data/lib/restfulie/client/cache/basic.rb +0 -76
- data/lib/restfulie/client/cache/fake.rb +0 -15
- data/lib/restfulie/client/cache/http_ext.rb +0 -123
- data/lib/restfulie/client/cache/restrictions.rb +0 -13
- data/lib/restfulie/client/configuration.rb +0 -67
- data/lib/restfulie/client/dsl.rb +0 -66
- data/lib/restfulie/client/entry_point.rb +0 -61
- data/lib/restfulie/client/ext/atom_ext.rb +0 -14
- data/lib/restfulie/client/ext/http_ext.rb +0 -22
- data/lib/restfulie/client/ext/json_ext.rb +0 -16
- data/lib/restfulie/client/feature.rb +0 -5
- data/lib/restfulie/client/feature/base.rb +0 -75
- data/lib/restfulie/client/feature/base_request.rb +0 -35
- data/lib/restfulie/client/feature/cache.rb +0 -16
- data/lib/restfulie/client/feature/enhance_response.rb +0 -12
- data/lib/restfulie/client/feature/follow_request.rb +0 -41
- data/lib/restfulie/client/feature/history.rb +0 -26
- data/lib/restfulie/client/feature/history_request.rb +0 -19
- data/lib/restfulie/client/feature/open_search.rb +0 -21
- data/lib/restfulie/client/feature/open_search/pattern_matcher.rb +0 -25
- data/lib/restfulie/client/feature/serialize_body.rb +0 -32
- data/lib/restfulie/client/feature/setup_header.rb +0 -22
- data/lib/restfulie/client/feature/throw_error.rb +0 -41
- data/lib/restfulie/client/feature/verb.rb +0 -119
- data/lib/restfulie/client/http.rb +0 -7
- data/lib/restfulie/client/http/cache.rb +0 -28
- data/lib/restfulie/client/http/error.rb +0 -77
- data/lib/restfulie/client/http/response_holder.rb +0 -29
- data/lib/restfulie/client/master_delegator.rb +0 -31
- data/lib/restfulie/client/mikyung.rb +0 -15
- data/lib/restfulie/client/mikyung/concatenator.rb +0 -18
- data/lib/restfulie/client/mikyung/core.rb +0 -70
- data/lib/restfulie/client/mikyung/languages.rb +0 -11
- data/lib/restfulie/client/mikyung/languages/german.rb +0 -24
- data/lib/restfulie/client/mikyung/languages/portuguese.rb +0 -23
- data/lib/restfulie/client/mikyung/rest_process_model.rb +0 -191
- data/lib/restfulie/client/mikyung/steady_state_walker.rb +0 -38
- data/lib/restfulie/client/mikyung/then_condition.rb +0 -39
- data/lib/restfulie/client/mikyung/when_condition.rb +0 -57
- data/lib/restfulie/common.rb +0 -18
- data/lib/restfulie/common/converter.rb +0 -43
- data/lib/restfulie/common/converter/atom.rb +0 -12
- data/lib/restfulie/common/converter/atom/base.rb +0 -91
- data/lib/restfulie/common/converter/atom/builder.rb +0 -111
- data/lib/restfulie/common/converter/atom/helpers.rb +0 -17
- data/lib/restfulie/common/converter/json.rb +0 -12
- data/lib/restfulie/common/converter/json/base.rb +0 -87
- data/lib/restfulie/common/converter/json/builder.rb +0 -102
- data/lib/restfulie/common/converter/json/helpers.rb +0 -17
- data/lib/restfulie/common/converter/open_search.rb +0 -16
- data/lib/restfulie/common/converter/open_search/descriptor.rb +0 -32
- data/lib/restfulie/common/converter/values.rb +0 -33
- data/lib/restfulie/common/converter/xml.rb +0 -14
- data/lib/restfulie/common/converter/xml/base.rb +0 -63
- data/lib/restfulie/common/converter/xml/builder.rb +0 -113
- data/lib/restfulie/common/converter/xml/helpers.rb +0 -17
- data/lib/restfulie/common/converter/xml/link.rb +0 -30
- data/lib/restfulie/common/converter/xml/links.rb +0 -21
- data/lib/restfulie/common/core_ext.rb +0 -1
- data/lib/restfulie/common/core_ext/hash.rb +0 -18
- data/lib/restfulie/common/error.rb +0 -19
- data/lib/restfulie/common/links.rb +0 -9
- data/lib/restfulie/common/logger.rb +0 -19
- data/lib/restfulie/common/representation.rb +0 -3
- data/lib/restfulie/common/representation/atom.rb +0 -20
- data/lib/restfulie/common/representation/atom/atom.rng +0 -597
- data/lib/restfulie/common/representation/atom/base.rb +0 -142
- data/lib/restfulie/common/representation/atom/category.rb +0 -41
- data/lib/restfulie/common/representation/atom/entry.rb +0 -59
- data/lib/restfulie/common/representation/atom/factory.rb +0 -43
- data/lib/restfulie/common/representation/atom/feed.rb +0 -110
- data/lib/restfulie/common/representation/atom/link.rb +0 -68
- data/lib/restfulie/common/representation/atom/person.rb +0 -48
- data/lib/restfulie/common/representation/atom/source.rb +0 -59
- data/lib/restfulie/common/representation/atom/tag_collection.rb +0 -38
- data/lib/restfulie/common/representation/atom/xml.rb +0 -90
- data/lib/restfulie/common/representation/generic.rb +0 -22
- data/lib/restfulie/common/representation/json.rb +0 -13
- data/lib/restfulie/common/representation/json/base.rb +0 -27
- data/lib/restfulie/common/representation/json/keys_as_methods.rb +0 -74
- data/lib/restfulie/common/representation/json/link.rb +0 -29
- data/lib/restfulie/common/representation/json/link_collection.rb +0 -23
- data/lib/restfulie/common/representation/links.rb +0 -11
- data/lib/restfulie/server.rb +0 -25
- data/lib/restfulie/server/action_controller.rb +0 -11
- data/lib/restfulie/server/action_controller/base.rb +0 -48
- data/lib/restfulie/server/action_controller/params_parser.rb +0 -100
- data/lib/restfulie/server/action_controller/patch.rb +0 -6
- data/lib/restfulie/server/action_controller/restful_responder.rb +0 -12
- data/lib/restfulie/server/action_controller/trait.rb +0 -9
- data/lib/restfulie/server/action_controller/trait/cacheable.rb +0 -81
- data/lib/restfulie/server/action_controller/trait/created.rb +0 -17
- data/lib/restfulie/server/action_view.rb +0 -10
- data/lib/restfulie/server/action_view/helpers.rb +0 -50
- data/lib/restfulie/server/action_view/template_handlers.rb +0 -30
- data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +0 -21
- data/lib/restfulie/server/configuration.rb +0 -24
- data/lib/restfulie/server/controller.rb +0 -74
- data/lib/restfulie/server/core_ext.rb +0 -1
- data/lib/restfulie/server/core_ext/array.rb +0 -61
- data/lib/restfulie/version.rb +0 -14
@@ -1,119 +0,0 @@
|
|
1
|
-
module Restfulie::Client::Feature::Verb
|
2
|
-
|
3
|
-
# GET HTTP verb without {Error}
|
4
|
-
# * <tt>path: '/posts'</tt>
|
5
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
6
|
-
def get(params = {})
|
7
|
-
@verb = :get
|
8
|
-
at query_string(params)
|
9
|
-
request_flow
|
10
|
-
end
|
11
|
-
|
12
|
-
# HEAD HTTP verb without {Error}
|
13
|
-
# * <tt>path: '/posts'</tt>
|
14
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
15
|
-
def head
|
16
|
-
@verb = :head
|
17
|
-
request_flow
|
18
|
-
end
|
19
|
-
|
20
|
-
# POST HTTP verb without {Error}
|
21
|
-
# * <tt>path: '/posts'</tt>
|
22
|
-
# * <tt>payload: 'some text'</tt>
|
23
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
24
|
-
def post(payload, options = {:recipe => nil})
|
25
|
-
@verb = :post
|
26
|
-
request_flow :body => payload
|
27
|
-
end
|
28
|
-
|
29
|
-
# PATCH HTTP verb without {Error}
|
30
|
-
# * <tt>path: '/posts'</tt>
|
31
|
-
# * <tt>payload: 'some text'</tt>
|
32
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
33
|
-
def patch(payload)
|
34
|
-
@verb = :patch
|
35
|
-
request_flow :body => payload
|
36
|
-
end
|
37
|
-
|
38
|
-
# PUT HTTP verb without {Error}
|
39
|
-
# * <tt>path: '/posts'</tt>
|
40
|
-
# * <tt>payload: 'some text'</tt>
|
41
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
42
|
-
def put(payload)
|
43
|
-
@verb = :put
|
44
|
-
request_flow :body => payload
|
45
|
-
end
|
46
|
-
|
47
|
-
# DELETE HTTP verb without {Error}
|
48
|
-
# * <tt>path: '/posts'</tt>
|
49
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
50
|
-
def delete
|
51
|
-
@verb = :delete
|
52
|
-
request_flow
|
53
|
-
end
|
54
|
-
|
55
|
-
# GET HTTP verb {Error}
|
56
|
-
# * <tt>path: '/posts'</tt>
|
57
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
58
|
-
def get!(params = {})
|
59
|
-
@verb = :get
|
60
|
-
at query_string(params)
|
61
|
-
request :throw_error
|
62
|
-
request_flow
|
63
|
-
end
|
64
|
-
|
65
|
-
# HEAD HTTP verb {Error}
|
66
|
-
# * <tt>path: '/posts'</tt>
|
67
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
68
|
-
def head!
|
69
|
-
@verb = :head
|
70
|
-
request :throw_error
|
71
|
-
request_flow
|
72
|
-
end
|
73
|
-
|
74
|
-
# POST HTTP verb {Error}
|
75
|
-
# * <tt>path: '/posts'</tt>
|
76
|
-
# * <tt>payload: 'some text'</tt>
|
77
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
78
|
-
def post!(payload, options = {:recipe => nil})
|
79
|
-
@verb = :post
|
80
|
-
request :throw_error
|
81
|
-
request_flow :body => payload
|
82
|
-
end
|
83
|
-
|
84
|
-
# PATCH HTTP verb {Error}
|
85
|
-
# * <tt>path: '/posts'</tt>
|
86
|
-
# * <tt>payload: 'some text'</tt>
|
87
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
88
|
-
def patch!(payload)
|
89
|
-
@verb = :patch
|
90
|
-
request :throw_error
|
91
|
-
request_flow :body => payload
|
92
|
-
end
|
93
|
-
|
94
|
-
# PUT HTTP verb {Error}
|
95
|
-
# * <tt>path: '/posts'</tt>
|
96
|
-
# * <tt>payload: 'some text'</tt>
|
97
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
98
|
-
def put!(payload)
|
99
|
-
@verb = :put
|
100
|
-
request :throw_error
|
101
|
-
request_flow :body => payload
|
102
|
-
end
|
103
|
-
|
104
|
-
# DELETE HTTP verb {Error}
|
105
|
-
# * <tt>path: '/posts'</tt>
|
106
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
107
|
-
def delete!
|
108
|
-
@verb = :delete
|
109
|
-
request :throw_error
|
110
|
-
request_flow
|
111
|
-
end
|
112
|
-
|
113
|
-
protected
|
114
|
-
|
115
|
-
def query_string(params)
|
116
|
-
params = params.map { |param, value| "#{param}=#{value}"}.join("&")
|
117
|
-
params.blank? ? "" : URI.escape("?#{params}")
|
118
|
-
end
|
119
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP
|
4
|
-
module Cache
|
5
|
-
def store
|
6
|
-
@store || @store = ::ActiveSupport::Cache::MemoryStore.new
|
7
|
-
end
|
8
|
-
|
9
|
-
def get
|
10
|
-
store.fetch(@uri) do
|
11
|
-
request(:get, @uri, @headers)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def head
|
16
|
-
store.fetch(@uri) do
|
17
|
-
request(:head, @uri, @headers)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class RequestBuilderExecutorWithCache < RequestBuilderExecutor
|
23
|
-
include Cache
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
@@ -1,77 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP#:nodoc:
|
4
|
-
#Client errors
|
5
|
-
module Error
|
6
|
-
# Standard error thrown on major client exceptions
|
7
|
-
class RESTError < StandardError
|
8
|
-
attr_reader :response
|
9
|
-
attr_reader :request
|
10
|
-
|
11
|
-
def initialize(request, response)
|
12
|
-
@request = request
|
13
|
-
@response = response
|
14
|
-
end
|
15
|
-
|
16
|
-
def to_s
|
17
|
-
"HTTP error #{@response.code} when invoking #{@request.host} via #{@response.method}. " +
|
18
|
-
((@response.body.blank?) ? "No additional data was sent." : "The complete response was:\n" + @response.body)
|
19
|
-
rescue
|
20
|
-
super
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class AutoFollowWithoutLocationError < RESTError; end
|
25
|
-
|
26
|
-
# Represents the HTTP code 503
|
27
|
-
class ServerNotAvailableError < RESTError
|
28
|
-
def initialize(request, response, exception)
|
29
|
-
super(request, response)
|
30
|
-
set_backtrace(exception.backtrace)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class UnknownError < RESTError; end
|
35
|
-
|
36
|
-
# Represents the HTTP code 300 range
|
37
|
-
class Redirection < RESTError; end
|
38
|
-
|
39
|
-
class ClientError < RESTError; end
|
40
|
-
|
41
|
-
# Represents the HTTP code 400
|
42
|
-
class BadRequest < ClientError; end
|
43
|
-
|
44
|
-
# Represents the HTTP code 401
|
45
|
-
class Unauthorized < ClientError; end
|
46
|
-
|
47
|
-
# Represents the HTTP code 403
|
48
|
-
class Forbidden < ClientError; end
|
49
|
-
|
50
|
-
# Represents the HTTP code 404
|
51
|
-
class NotFound < ClientError; end
|
52
|
-
|
53
|
-
# Represents the HTTP code 405
|
54
|
-
class MethodNotAllowed < ClientError; end
|
55
|
-
|
56
|
-
# Represents the HTTP code 412
|
57
|
-
class PreconditionFailed < ClientError; end
|
58
|
-
|
59
|
-
# Represents the HTTP code 407
|
60
|
-
class ProxyAuthenticationRequired < ClientError; end
|
61
|
-
|
62
|
-
# Represents the HTTP code 409
|
63
|
-
class Conflict < ClientError; end
|
64
|
-
|
65
|
-
# Represents the HTTP code 410
|
66
|
-
class Gone < ClientError; end
|
67
|
-
|
68
|
-
# Represents the HTTP code 500
|
69
|
-
class ServerError < RESTError; end
|
70
|
-
|
71
|
-
# Represents the HTTP code 501
|
72
|
-
class NotImplemented < ServerError; end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Restfulie::Client::HTTP
|
2
|
-
module ResponseHolder
|
3
|
-
attr_reader :response, :request
|
4
|
-
|
5
|
-
def resource
|
6
|
-
type = headers['content-type'] || response['Content-Type']
|
7
|
-
representation = Restfulie::Common::Converter.content_type_for(type[0]) || Restfulie::Common::Representation::Generic.new
|
8
|
-
representation.unmarshal(response.body)
|
9
|
-
end
|
10
|
-
|
11
|
-
def at(uri)
|
12
|
-
request.clone.at(uri)
|
13
|
-
end
|
14
|
-
|
15
|
-
def headers
|
16
|
-
response.to_hash
|
17
|
-
end
|
18
|
-
|
19
|
-
def results_from(request, response)
|
20
|
-
@request = request
|
21
|
-
@response = response
|
22
|
-
end
|
23
|
-
|
24
|
-
def verb
|
25
|
-
@request.verb
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
class MasterDelegator
|
2
|
-
|
3
|
-
alias_method :original_respond_to?, :respond_to?
|
4
|
-
|
5
|
-
def respond_to?(sym)
|
6
|
-
original_respond_to?(sym) || @requester.respond_to?(sym)
|
7
|
-
end
|
8
|
-
|
9
|
-
def method_missing(sym, *args, &block)
|
10
|
-
if original_respond_to?(sym)
|
11
|
-
result = super(sym, *args, &block)
|
12
|
-
elsif @requester.respond_to?(sym)
|
13
|
-
result = @requester.send(sym, *args, &block)
|
14
|
-
else
|
15
|
-
# let it go
|
16
|
-
return super(sym, *args, &block)
|
17
|
-
end
|
18
|
-
delegate_parse result
|
19
|
-
end
|
20
|
-
|
21
|
-
protected
|
22
|
-
|
23
|
-
def delegate(what, *args, &block)
|
24
|
-
delegate_parse @requester.send(what, *args, &block)
|
25
|
-
end
|
26
|
-
|
27
|
-
def delegate_parse(result)
|
28
|
-
(result == @requester) ? self : result
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
Dir["#{File.dirname(__FILE__)}/mikyung/*.rb"].each {|f| autoload File.basename(f)[0..-4].camelize.to_sym, f }
|
5
|
-
end
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
# Restfulie::Mikyung entry point is based on its core
|
10
|
-
# implementation.
|
11
|
-
module Restfulie
|
12
|
-
class Mikyung < Restfulie::Client::Mikyung::Core
|
13
|
-
Restfulie::Common::Logger.logger.level = Logger::INFO
|
14
|
-
end
|
15
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
# Concatenates pure text in order to build messages
|
5
|
-
# that are used as patterns.
|
6
|
-
# Usage:
|
7
|
-
# When there is a machine
|
8
|
-
#
|
9
|
-
# Will invoke concatenate 'machine' with 'a' with 'is' with 'there'
|
10
|
-
class Concatenator
|
11
|
-
attr_reader :content
|
12
|
-
def initialize(content, *args)
|
13
|
-
@content = args.inject(content) { |buf, arg| buf << " " << arg.content }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
# iterates following a series of steps provided a goal and a starting uri.
|
5
|
-
#
|
6
|
-
# Restfulie::Client::Mikyung.achieve(objective).at(uri).run
|
7
|
-
#
|
8
|
-
# In order to implement your own walker, supply an object that respond to the move method.
|
9
|
-
# Check the run method code.
|
10
|
-
class Core
|
11
|
-
attr_reader :start, :goal, :walker, :accepts, :follow
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@walker = Restfulie::Client::Mikyung::SteadyStateWalker.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def walks_with(walker)
|
18
|
-
@walker = walker
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
# initializes with a goal in mind
|
23
|
-
def achieve(goal)
|
24
|
-
@goal = goal
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
def at(start)
|
29
|
-
@start = start
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
def follow
|
34
|
-
@follow = true
|
35
|
-
self
|
36
|
-
end
|
37
|
-
|
38
|
-
def accepts(accepts)
|
39
|
-
@accepts = accepts
|
40
|
-
self
|
41
|
-
end
|
42
|
-
|
43
|
-
# keeps changing from a steady state to another until its goal has been achieved
|
44
|
-
def run
|
45
|
-
if @start.kind_of? String
|
46
|
-
client = Restfulie.at(@start)
|
47
|
-
client = client.follow if @follow
|
48
|
-
client = client.accepts(@accepts) if @accepts
|
49
|
-
@start = current = client.get
|
50
|
-
else
|
51
|
-
# probably configured thru the Rest Process Model class
|
52
|
-
@start = current = @goal.class.get_restfulie.get
|
53
|
-
end
|
54
|
-
|
55
|
-
# load the steps and scenario
|
56
|
-
@goal.steps
|
57
|
-
@goal.scenario
|
58
|
-
|
59
|
-
while(!@goal.completed?(current))
|
60
|
-
current = @walker.move(@goal, current, self)
|
61
|
-
end
|
62
|
-
current
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class UnableToAchieveGoalError < Restfulie::Common::Error::RestfulieError
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module Mikyung
|
4
|
-
module Languages
|
5
|
-
module German
|
6
|
-
def Wenn(concat, &block)
|
7
|
-
When(concat, &block)
|
8
|
-
end
|
9
|
-
def Und(concat, &block)
|
10
|
-
And(concat, &block)
|
11
|
-
end
|
12
|
-
def Aber(concat, &block)
|
13
|
-
But(concat, &block)
|
14
|
-
end
|
15
|
-
def Dann(concat, &block)
|
16
|
-
Then(concat, &block)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
|