waves 0.7.3 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/app/Rakefile +11 -19
- data/app/bin/waves-console +3 -5
- data/app/bin/waves-server +3 -5
- data/app/configurations/development.rb.erb +19 -11
- data/app/configurations/mapping.rb.erb +4 -5
- data/app/configurations/production.rb.erb +18 -13
- data/app/{doc/EMTPY → controllers/.gitignore} +0 -0
- data/app/{public/css/EMPTY → doc/.gitignore} +0 -0
- data/app/{public/flash/EMPTY → helpers/.gitignore} +0 -0
- data/app/lib/application.rb.erb +4 -51
- data/app/{public/images/EMPTY → lib/tasks/.gitignore} +0 -0
- data/app/{public/javascript/EMPTY → log/.gitignore} +0 -0
- data/app/{tmp/sessions/EMPTY → models/.gitignore} +0 -0
- data/app/public/css/.gitignore +0 -0
- data/app/public/flash/.gitignore +0 -0
- data/app/public/images/.gitignore +0 -0
- data/app/public/javascript/.gitignore +0 -0
- data/app/schema/migrations/.gitignore +0 -0
- data/app/startup.rb +5 -0
- data/app/templates/layouts/default.mab +2 -2
- data/app/tmp/sessions/.gitignore +0 -0
- data/app/views/.gitignore +0 -0
- data/bin/waves +38 -27
- data/bin/waves-console +3 -25
- data/bin/waves-server +4 -45
- data/lib/commands/waves-console.rb +21 -0
- data/lib/commands/waves-server.rb +55 -0
- data/lib/controllers/base.rb +11 -0
- data/lib/controllers/mixin.rb +130 -102
- data/lib/dispatchers/base.rb +65 -50
- data/lib/dispatchers/default.rb +79 -52
- data/lib/foundations/default.rb +26 -0
- data/lib/foundations/simple.rb +30 -0
- data/lib/helpers/common.rb +60 -56
- data/lib/helpers/default.rb +13 -0
- data/lib/helpers/form.rb +39 -38
- data/lib/helpers/formatting.rb +11 -11
- data/lib/helpers/model.rb +12 -12
- data/lib/helpers/view.rb +13 -13
- data/lib/layers/default_errors.rb +29 -0
- data/lib/layers/mvc.rb +58 -0
- data/lib/layers/orm/active_record.rb +41 -0
- data/lib/layers/orm/active_record/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/active_record/tasks/schema.rb +30 -0
- data/lib/layers/orm/data_mapper.rb +42 -0
- data/lib/layers/orm/filebase.rb +22 -0
- data/lib/layers/orm/migration.rb +70 -0
- data/lib/layers/orm/sequel.rb +82 -0
- data/lib/layers/orm/sequel/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/sequel/tasks/schema.rb +24 -0
- data/lib/layers/simple.rb +39 -0
- data/lib/layers/simple_errors.rb +26 -0
- data/lib/mapping/mapping.rb +222 -120
- data/lib/mapping/pretty_urls.rb +42 -41
- data/lib/renderers/erubis.rb +54 -31
- data/lib/renderers/markaby.rb +28 -28
- data/lib/renderers/mixin.rb +49 -52
- data/lib/runtime/application.rb +66 -48
- data/lib/runtime/blackboard.rb +57 -0
- data/lib/runtime/configuration.rb +117 -101
- data/lib/runtime/console.rb +19 -20
- data/lib/runtime/debugger.rb +9 -0
- data/lib/runtime/logger.rb +43 -37
- data/lib/runtime/mime_types.rb +19 -19
- data/lib/runtime/request.rb +72 -46
- data/lib/runtime/response.rb +37 -37
- data/lib/runtime/response_mixin.rb +26 -23
- data/lib/runtime/response_proxy.rb +25 -24
- data/lib/runtime/server.rb +99 -80
- data/lib/runtime/session.rb +63 -53
- data/lib/tasks/cluster.rb +26 -0
- data/lib/tasks/gem.rb +31 -0
- data/lib/tasks/generate.rb +80 -0
- data/lib/utilities/hash.rb +22 -0
- data/lib/utilities/inflect.rb +194 -0
- data/lib/utilities/integer.rb +15 -12
- data/lib/utilities/kernel.rb +32 -32
- data/lib/utilities/module.rb +11 -4
- data/lib/utilities/object.rb +5 -5
- data/lib/utilities/proc.rb +10 -0
- data/lib/utilities/string.rb +44 -38
- data/lib/utilities/symbol.rb +4 -4
- data/lib/views/base.rb +9 -0
- data/lib/views/mixin.rb +91 -89
- data/lib/waves.rb +29 -9
- metadata +52 -26
- data/app/configurations/default.rb.erb +0 -8
- data/app/controllers/default.rb.erb +0 -29
- data/app/helpers/default.rb.erb +0 -13
- data/app/lib/startup.rb.erb +0 -3
- data/app/lib/tasks/cluster.rb +0 -24
- data/app/lib/tasks/generate.rb +0 -15
- data/app/lib/tasks/schema.rb +0 -29
- data/app/models/default.rb.erb +0 -13
- data/app/schema/migrations/templates/empty.rb.erb +0 -9
- data/app/views/default.rb.erb +0 -13
@@ -0,0 +1,26 @@
|
|
1
|
+
module Waves
|
2
|
+
module Foundations
|
3
|
+
# The Default foundation supports the common MVC development pattern, a la Rails and Merb. Models, controllers, views, templates, and helpers live in the corresponding directories. When your code calls for a specific M, V, C, or H, Waves tries to load it from a file matching the snake-case of the constant name. If the file does not exist, Waves creates the constant from a sensible (and customizable) default.
|
4
|
+
#
|
5
|
+
# This foundation does not include any ORM configuration. You can include Waves::Layers::ORM::Sequel or custom configure your model.
|
6
|
+
|
7
|
+
|
8
|
+
module Default
|
9
|
+
|
10
|
+
def self.included( app )
|
11
|
+
|
12
|
+
app.instance_eval do
|
13
|
+
|
14
|
+
include Waves::Layers::Simple
|
15
|
+
include Waves::Layers::MVC
|
16
|
+
include Waves::Layers::DefaultErrors
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
Waves << app
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
# A Waves Foundation provides enough functionality to allow a Waves application
|
4
|
+
# to run. At the bare minimum, this means creating configuration classes in the Configurations
|
5
|
+
# namespace, as is done in the Simple foundation
|
6
|
+
#
|
7
|
+
# Typically, a Foundation will include several Layers, perform any necessary
|
8
|
+
# configuration, and register the application with the Waves module
|
9
|
+
module Foundations
|
10
|
+
|
11
|
+
# The Simple foundation provides the bare minimum needed to run a Waves application.
|
12
|
+
# It is intended for use as the basis of more fully-featured foundations, but you can
|
13
|
+
# use it as a standalone where all the request processing is done directly in a
|
14
|
+
# mapping lambda.
|
15
|
+
module Simple
|
16
|
+
|
17
|
+
# On inclusion in a module, the Simple foundation includes Waves::Layers::Simple and
|
18
|
+
# registers the module as a Waves application.
|
19
|
+
def self.included( app )
|
20
|
+
|
21
|
+
app.instance_eval do
|
22
|
+
include Waves::Layers::Simple
|
23
|
+
end
|
24
|
+
|
25
|
+
Waves << app
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/lib/helpers/common.rb
CHANGED
@@ -1,62 +1,66 @@
|
|
1
1
|
module Waves
|
2
|
+
|
3
|
+
# Helper methods can be defined for any view template by simply defining them within the default Helper module in <tt>helpers/default.rb</tt> of the generated application. Helpers specific to a particular View class can be explicitly defined by creating a helper module that corresponds to the View class. For examples, for the +User+ View class, you would define a helper module in <tt>user.rb</tt> named +User+.
|
4
|
+
#
|
5
|
+
# The default helper class initially includes a wide-variety of helpers, including helpers for layouts, Textile formatting, rendering forms, and nested views, as well as helpers for accessing the request and response objects. More helpers will be added in future releases, but in many cases, there is no need to include all of them in your application.
|
2
6
|
module Helpers
|
3
|
-
|
7
|
+
|
4
8
|
# Common helpers are helpers that are needed for just about any Web page. For example,
|
5
9
|
# each page will likely have a layout and a doctype.
|
6
|
-
|
10
|
+
|
7
11
|
module Common
|
8
|
-
|
12
|
+
|
9
13
|
DOCTYPES = {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
14
|
+
:html3 => "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n",
|
15
|
+
:html4_transitional =>
|
16
|
+
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" " <<
|
17
|
+
"\"http://www.w3.org/TR/html4/loose.dtd\">\n",
|
18
|
+
:html4_strict =>
|
19
|
+
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " <<
|
20
|
+
"\"http://www.w3.org/TR/html4/strict.dtd\">\n",
|
21
|
+
:html4_frameset =>
|
22
|
+
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" " <<
|
23
|
+
"\"http://www.w3.org/TR/html4/frameset.dtd\">\n",
|
24
|
+
:xhtml1_transitional =>
|
25
|
+
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " <<
|
26
|
+
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n",
|
27
|
+
:xhtml1_strict =>
|
28
|
+
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " <<
|
29
|
+
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n",
|
30
|
+
:xhtml1_frameset =>
|
31
|
+
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" " <<
|
32
|
+
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">\n",
|
33
|
+
:xhtml2 => "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
|
34
|
+
}
|
35
|
+
|
36
|
+
# Invokes a layout view (i.e., a view from the layouts template directory), using
|
37
|
+
# the assigns parameter to define instance variables for the view. The block is
|
38
|
+
# evaluated and also passed into the view as the +layout_content+ instance variable.
|
39
|
+
#
|
40
|
+
# You can define a layout just by creating a template and then calling the
|
41
|
+
# +layout_content+ accessor when you want to embed the caller's content.
|
42
|
+
#
|
43
|
+
# == Example
|
44
|
+
#
|
45
|
+
# doctype :html4_transitional
|
46
|
+
# html do
|
47
|
+
# title @title # passed as an assigns parameter
|
48
|
+
# end
|
49
|
+
# body do
|
50
|
+
# layout_content
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
def layout( name, assigns = {}, &block )
|
54
|
+
assigns[ :layout_content ] = capture(&block)
|
55
|
+
self << Waves.application.views[:layouts].process( request ) do
|
56
|
+
send( name, assigns )
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# The doctype method simply generates a valid DOCTYPE declaration for your page.
|
61
|
+
# Valid options are defined in the +DOCTYPES+ constant.
|
62
|
+
def doctype(type) ; self << DOCTYPES[type||:html4_strict] ; end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Waves
|
2
|
+
module Helpers
|
3
|
+
module Default
|
4
|
+
attr_reader :request, :content
|
5
|
+
include Waves::ResponseMixin
|
6
|
+
include Waves::Helpers::Common
|
7
|
+
include Waves::Helpers::Formatting
|
8
|
+
include Waves::Helpers::Model
|
9
|
+
include Waves::Helpers::View
|
10
|
+
include Waves::Helpers::Form
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/helpers/form.rb
CHANGED
@@ -1,39 +1,40 @@
|
|
1
1
|
module Waves
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
2
|
+
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
# Form helpers are used in generating forms. Since Markaby already provides Ruby
|
6
|
+
# methods for basic form generation, the focus of this helper is on providing templates
|
7
|
+
# to handle things that go beyond the basics. You must define a form template
|
8
|
+
# directory with templates for each type of form element you wish to use. The names
|
9
|
+
# of the template should match the +type+ option provided in the property method.
|
10
|
+
#
|
11
|
+
# For example, this code:
|
12
|
+
#
|
13
|
+
# property :name => 'blog.title', :type => :text, :value => @blog.title
|
14
|
+
#
|
15
|
+
# will invoke the +text+ form view (the template in +templates/form/text.mab+),
|
16
|
+
# passing in the name ('blog.title') and the value (@blog.title) as instance variables.
|
17
|
+
#
|
18
|
+
# These helpers are Markaby only.
|
19
|
+
module Form
|
20
|
+
|
21
|
+
# This method really is a place-holder for common wrappers around groups of
|
22
|
+
# properties. You will usually want to override this. As is, it simply places
|
23
|
+
# a DIV element with class 'properties' around the block.
|
24
|
+
def properties(&block)
|
25
|
+
div.properties do
|
26
|
+
yield
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Invokes the form view for the +type+ given in the option.
|
31
|
+
def property( options )
|
32
|
+
self << view( :form, options[:type], options )
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/helpers/formatting.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
require 'redcloth'
|
2
2
|
module Waves
|
3
3
|
module Helpers
|
4
|
-
|
5
|
-
# Formatting helpers are used to convert specialized content, like Markaby or
|
4
|
+
|
5
|
+
# Formatting helpers are used to convert specialized content, like Markaby or
|
6
6
|
# Textile, into valid HTML. It also provides common escaping functions.
|
7
7
|
module Formatting
|
8
|
-
|
8
|
+
|
9
9
|
# Escape a string as HTML content.
|
10
10
|
def escape_html(s); Rack::Utils.escape_html(s); end
|
11
|
-
|
11
|
+
|
12
12
|
# Escape a URI, converting quotes and spaces and so on.
|
13
13
|
def escape_uri(s); Rack::Utils.escape(s); end
|
14
|
-
|
14
|
+
|
15
15
|
# Treat content as Markaby and evaluate (only works within a Markaby template).
|
16
16
|
# Used to pull Markaby content from a file or database into a Markaby template.
|
17
17
|
def markaby( content ); self << eval( content ); end
|
@@ -20,11 +20,11 @@ module Waves
|
|
20
20
|
def textile( content )
|
21
21
|
return if content.nil? or content.empty?
|
22
22
|
( ::RedCloth::TEXTILE_TAGS << [ 96.chr, '&8216;'] ).each do |pat,ent|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
content.gsub!( pat, ent.gsub('&','&#') )
|
24
|
+
end
|
25
|
+
self << ::RedCloth.new( content ).to_html
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/helpers/model.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Waves
|
2
2
|
module Helpers
|
3
|
-
|
3
|
+
|
4
4
|
# Model helpers allow you to directly access a model from within a view.
|
5
5
|
# This is useful when creating things like select boxes that need data
|
6
6
|
# from anther model. For example, a Markaby select box for authors might look like:
|
@@ -17,17 +17,17 @@ module Waves
|
|
17
17
|
# then be called from the template instead of the model helper.
|
18
18
|
#
|
19
19
|
module Model
|
20
|
-
|
20
|
+
|
21
21
|
# Just like model.all. Returns all the instances of that model.
|
22
|
-
|
23
|
-
|
22
|
+
def all( model )
|
23
|
+
Waves.application.models[ model ].all( domain )
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Finds a specific instance using the name field
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
27
|
+
def find( model, name )
|
28
|
+
Waves.application.models[ model ][ :name => name ] rescue nil
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/helpers/view.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
1
|
module Waves
|
2
2
|
module Helpers
|
3
|
-
|
3
|
+
|
4
4
|
# View helpers are intended to help reuse views from within other views.
|
5
5
|
# Both the +layout+ method in the common helpers and the +property+ method
|
6
|
-
# of the form helpers are specialized instance of this.
|
7
|
-
#
|
6
|
+
# of the form helpers are specialized instance of this.
|
7
|
+
#
|
8
8
|
# The star of our show here is the +view+ method. This takes a model, view,
|
9
9
|
# and assigns hash (which are converted into instance variables in the target
|
10
10
|
# view) and returns the result of evaluating the view as content in the current
|
11
11
|
# template.
|
12
12
|
module View
|
13
|
-
|
13
|
+
|
14
14
|
# Invokes the view for the given model, passing the assigns as instance variables.
|
15
|
-
|
15
|
+
def view( model, view, assigns = {} )
|
16
16
|
self << Waves.application.views[ model ].process( request ) do
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
17
|
+
send( view, assigns )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Waves
|
2
|
+
module Layers
|
3
|
+
|
4
|
+
# Configures Waves to use the templates in app/templates/errors for exception handling
|
5
|
+
module DefaultErrors
|
6
|
+
|
7
|
+
def self.included( app )
|
8
|
+
|
9
|
+
app.instance_eval do
|
10
|
+
|
11
|
+
auto_eval :Configurations do
|
12
|
+
auto_eval :Mapping do
|
13
|
+
extend Waves::Mapping
|
14
|
+
handle(Waves::Dispatchers::NotFoundError) do
|
15
|
+
html = Waves.application.views[:errors].process( request ) do
|
16
|
+
not_found_404( :error => Waves::Dispatchers::NotFoundError )
|
17
|
+
end
|
18
|
+
response.status = '404'
|
19
|
+
response.content_type = 'text/html'
|
20
|
+
response.body = html
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/layers/mvc.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Waves
|
2
|
+
module Layers
|
3
|
+
# The MVC layer establishes the Models, Views, Controllers, and Helpers namespaces inside
|
4
|
+
# a Waves application. In each namespace, undefined constants are handled by AutoCode, which
|
5
|
+
# loads the constant from the correct file in the appropriate directory if it exists, or creates
|
6
|
+
# from default otherwise.
|
7
|
+
module MVC
|
8
|
+
|
9
|
+
def self.included( app )
|
10
|
+
|
11
|
+
def app.models ; self::Models ; end
|
12
|
+
def app.views ; self::Views ; end
|
13
|
+
def app.controllers ; self::Controllers ; end
|
14
|
+
def app.helpers ; self::Helpers ; end
|
15
|
+
|
16
|
+
|
17
|
+
app.instance_eval do
|
18
|
+
|
19
|
+
auto_create_module( :Models ) do
|
20
|
+
include AutoCode
|
21
|
+
auto_create_class :Default
|
22
|
+
auto_load :Default, :directories => [:models]
|
23
|
+
end
|
24
|
+
|
25
|
+
auto_eval( :Models ) do
|
26
|
+
auto_create_class true, app::Models::Default
|
27
|
+
auto_load true, :directories => [ :models ]
|
28
|
+
end
|
29
|
+
|
30
|
+
auto_create_module( :Views ) { include AutoCode }
|
31
|
+
|
32
|
+
auto_eval( :Views ) do
|
33
|
+
auto_create_class :Default, Waves::Views::Base
|
34
|
+
auto_load :Default, :directories => [:views]
|
35
|
+
auto_create_class true, app::Views::Default
|
36
|
+
auto_load true, :directories => [ :views ]
|
37
|
+
end
|
38
|
+
|
39
|
+
auto_create_module( :Controllers ) { include AutoCode }
|
40
|
+
|
41
|
+
auto_eval( :Controllers ) do
|
42
|
+
auto_create_class :Default, Waves::Controllers::Base
|
43
|
+
auto_load :Default, :directories => [:controllers]
|
44
|
+
auto_create_class true, app::Controllers::Default
|
45
|
+
auto_load true, :directories => [ :controllers ]
|
46
|
+
end
|
47
|
+
|
48
|
+
auto_create_module( :Helpers ) do
|
49
|
+
include AutoCode
|
50
|
+
auto_create_module { include Waves::Helpers::Default }
|
51
|
+
auto_load true, :directories => [ :helpers ]
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|