bootstrap-shoehorn 1.0.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.
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/README.md +336 -0
- data/Rakefile +32 -0
- data/lib/shoehorn.rb +15 -0
- data/lib/shoehorn/components.rb +17 -0
- data/lib/shoehorn/components/alert.rb +69 -0
- data/lib/shoehorn/components/badge.rb +38 -0
- data/lib/shoehorn/components/base.rb +18 -0
- data/lib/shoehorn/components/button.rb +72 -0
- data/lib/shoehorn/components/dropdown.rb +55 -0
- data/lib/shoehorn/components/form.rb +14 -0
- data/lib/shoehorn/components/form/input_field.rb +53 -0
- data/lib/shoehorn/components/form/label.rb +8 -0
- data/lib/shoehorn/components/form_builder.rb +13 -0
- data/lib/shoehorn/components/icon.rb +40 -0
- data/lib/shoehorn/components/label.rb +39 -0
- data/lib/shoehorn/components/modal.rb +62 -0
- data/lib/shoehorn/components/navigation.rb +47 -0
- data/lib/shoehorn/components/progress_bar.rb +51 -0
- data/lib/shoehorn/engine.rb +19 -0
- data/lib/shoehorn/helper_collection.rb +58 -0
- data/lib/shoehorn/helper_collection_set.rb +18 -0
- data/lib/shoehorn/helpers.rb +14 -0
- data/lib/shoehorn/helpers/alert_helpers.rb +37 -0
- data/lib/shoehorn/helpers/badge_helpers.rb +38 -0
- data/lib/shoehorn/helpers/button_helpers.rb +122 -0
- data/lib/shoehorn/helpers/form_helpers.rb +11 -0
- data/lib/shoehorn/helpers/icon_helpers.rb +34 -0
- data/lib/shoehorn/helpers/label_helpers.rb +37 -0
- data/lib/shoehorn/helpers/modal_helpers.rb +43 -0
- data/lib/shoehorn/helpers/navigation_helpers.rb +32 -0
- data/lib/shoehorn/helpers/progress_bar_helpers.rb +25 -0
- data/lib/shoehorn/plugins.rb +6 -0
- data/lib/shoehorn/plugins/simple_navigation/renderer/bootstrap_topbar_list.rb +72 -0
- data/lib/shoehorn/version.rb +3 -0
- data/log/development.log +0 -0
- data/shoehorn.gemspec +33 -0
- data/spec/helpers/alert_helpers_spec.rb +138 -0
- data/spec/helpers/button_helpers_spec.rb +102 -0
- data/spec/helpers/form_helpers_spec.rb +136 -0
- data/spec/helpers/inline_label_helpers_spec.rb +50 -0
- data/spec/helpers/modal_helpers_spec.rb +60 -0
- data/spec/helpers/navigation_helpers_spec.rb +61 -0
- data/spec/helpers/progress_bar_helpers_spec.rb +34 -0
- data/spec/integration/action_view_spec.rb +23 -0
- data/spec/integration/readme_spec.rb +14 -0
- data/spec/plugins/bootstrap_topbar_list_spec.rb +11 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/bootstrap_button_macros.rb +8 -0
- data/spec/support/bootstrap_form_macros.rb +8 -0
- data/spec/support/bootstrap_modal_macros.rb +8 -0
- data/spec/support/bootstrap_navigation_macros.rb +8 -0
- data/spec/support/bootstrap_spec_helper.rb +50 -0
- data/spec/support/test_environment.rb +23 -0
- metadata +265 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module Shoehorn::Components
|
2
|
+
class ProgressBar < Base
|
3
|
+
attr_accessor :width
|
4
|
+
|
5
|
+
def initialize(width, options = {})
|
6
|
+
super
|
7
|
+
@width = width
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
output_buffer << content_tag(:div, build_div_options) do
|
12
|
+
build_bar_tag.html_safe
|
13
|
+
end.html_safe
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def default_options
|
20
|
+
{
|
21
|
+
:class => nil,
|
22
|
+
:bootstrap_class_prefix => "progress",
|
23
|
+
:striped => false,
|
24
|
+
:animated => false,
|
25
|
+
:type => nil,
|
26
|
+
:html_options => {}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_class
|
31
|
+
classes = [ options[:class] ]
|
32
|
+
classes << options[:bootstrap_class_prefix]
|
33
|
+
classes << "#{options[:bootstrap_class_prefix]}-#{options[:type]}" if options[:type]
|
34
|
+
classes << "#{options[:bootstrap_class_prefix]}-striped" if options[:striped]
|
35
|
+
classes << "active" if options[:animated]
|
36
|
+
classes.join(" ")
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_bar_tag
|
40
|
+
ops = { :class => 'bar', :style => "width: #{@width}%;" }
|
41
|
+
content_tag(:div, nil, ops)
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_div_options
|
45
|
+
ops = { :class => build_class }
|
46
|
+
ops.reverse_merge(options[:html_options])
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module Shoehorn
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
initializer 'shoehorn.initialize' do
|
6
|
+
ActiveSupport.on_load(:action_view) do
|
7
|
+
include Shoehorn::Helpers::AlertHelpers
|
8
|
+
include Shoehorn::Helpers::LabelHelpers
|
9
|
+
include Shoehorn::Helpers::IconHelpers
|
10
|
+
include Shoehorn::Helpers::BadgeHelpers
|
11
|
+
#include Shoehors::Helpers::FormHelpers
|
12
|
+
include Shoehorn::Helpers::ButtonHelpers
|
13
|
+
include Shoehorn::Helpers::NavigationHelpers
|
14
|
+
include Shoehorn::Helpers::ModalHelpers
|
15
|
+
include Shoehorn::Helpers::ProgressBarHelpers
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Shoehorn
|
2
|
+
class HelperCollection
|
3
|
+
attr_accessor :calls, :view
|
4
|
+
|
5
|
+
def initialize(view)
|
6
|
+
@view = view
|
7
|
+
@calls = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(symbol, *args, &block)
|
11
|
+
@calls << HelperMethodCall.new(@view, symbol, args, block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
@calls.each do |c|
|
16
|
+
yield c
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](x)
|
21
|
+
@calls[x]
|
22
|
+
end
|
23
|
+
|
24
|
+
def size
|
25
|
+
@calls.size
|
26
|
+
end
|
27
|
+
|
28
|
+
def shift
|
29
|
+
@calls.shift
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class HelperMethodCall
|
34
|
+
attr_accessor :method, :options, :args
|
35
|
+
|
36
|
+
def initialize(view, symbol, args, block)
|
37
|
+
@view = view
|
38
|
+
@method = symbol
|
39
|
+
@options = args.extract_options!
|
40
|
+
@args = args
|
41
|
+
@block = block
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
args = @args
|
46
|
+
args << @options
|
47
|
+
|
48
|
+
if @block
|
49
|
+
output = @view.send(@method, *args, &@block)
|
50
|
+
else
|
51
|
+
output = @view.send(@method, *args)
|
52
|
+
end
|
53
|
+
|
54
|
+
output.blank? ? nil : output.html_safe
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Shoehorn
|
2
|
+
class HelperCollectionSet
|
3
|
+
attr_accessor :collections
|
4
|
+
|
5
|
+
def initialize(view, items)
|
6
|
+
@collections = {}
|
7
|
+
items.each do |item|
|
8
|
+
@collections[item] = Shoehorn::HelperCollection.new(view)
|
9
|
+
instance_eval <<-EOF
|
10
|
+
def#{item}
|
11
|
+
yield @collections[#{item.inspect} ]
|
12
|
+
end
|
13
|
+
EOF
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Shoehorn
|
2
|
+
module Helpers
|
3
|
+
autoload :AlertHelpers, 'shoehorn/helpers/alert_helpers'
|
4
|
+
autoload :LabelHelpers, 'shoehorn/helpers/label_helpers'
|
5
|
+
autoload :BadgeHelpers, 'shoehorn/helpers/badge_helpers'
|
6
|
+
autoload :IconHelpers, 'shoehorn/helpers/icon_helpers'
|
7
|
+
#autoload :FormHelpers, 'shoehorn/helpers/form_helpers'
|
8
|
+
autoload :ButtonHelpers, 'shoehorn/helpers/button_helpers'
|
9
|
+
autoload :NavigationHelpers, 'shoehorn/helpers/navigation_helpers'
|
10
|
+
autoload :ModalHelpers, 'shoehorn/helpers/modal_helpers'
|
11
|
+
autoload :ProgressBarHelpers, 'shoehorn/helpers/progress_bar_helpers'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Shoehorn::Helpers
|
4
|
+
module AlertHelpers
|
5
|
+
# Renders alert message
|
6
|
+
#
|
7
|
+
# @param [String] message message to be displayed
|
8
|
+
# @param [Hash] options hash containing options (default: {}):
|
9
|
+
# :block - The Boolean whether to display as a block (optional)
|
10
|
+
# :close - The Boolean whether to render close button
|
11
|
+
# :heading - The String heading message to render
|
12
|
+
# :dismiss - The Boolean whether to add dismiss attribute
|
13
|
+
# :type - The String type of alert to display: error, success or info
|
14
|
+
# :html_options - Any additional HTML options desired on the alert DIV.
|
15
|
+
#
|
16
|
+
# Examples
|
17
|
+
#
|
18
|
+
# bootstrap_alert("Hello!")
|
19
|
+
# # => '<div class="alert"><a class="close">×</a>Hello!</div>'
|
20
|
+
#
|
21
|
+
# bootstrap_alert("Hello!", type: 'error', close: false)
|
22
|
+
# # => '<div class="alert alert-error">Hello!</div>'
|
23
|
+
#
|
24
|
+
# bootstrap_alert("Content of alert", heading: "WARNING!", type: 'info')
|
25
|
+
# # => '<div class="alert alert-info"><a class="close">×</a>
|
26
|
+
# <h4 class="alert-heading">WARNING!</h4>Content of alert</div>'
|
27
|
+
#
|
28
|
+
# Returns HTML String for the alert
|
29
|
+
def bootstrap_alert(message, options = {})
|
30
|
+
Shoehorn::Components::Alert.new(
|
31
|
+
message,
|
32
|
+
options
|
33
|
+
).to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Shoehorn::Helpers
|
3
|
+
module BadgeHelpers
|
4
|
+
# Renders badge
|
5
|
+
#
|
6
|
+
# @param [String] message message to be displayed
|
7
|
+
# @param [Hash] options hash containing options (default: {}):
|
8
|
+
# :type - The String type of alert to display: info, success, warning, important or inverse
|
9
|
+
# :class - The String additional CSS classes of the object
|
10
|
+
# :bootstrap_class_prefix - The String CSS class prefix from Twitter Bootstrap for the object
|
11
|
+
# :html_options - Any additional options you'd like to pass to the span tag that will be created
|
12
|
+
# for this label (for instance :"data-whatever" can be specified in :html_options).
|
13
|
+
#
|
14
|
+
# Examples
|
15
|
+
#
|
16
|
+
# bootstrap_badge("Hello!")
|
17
|
+
# # => '<span class="badge">Hello!</span>'
|
18
|
+
#
|
19
|
+
# bootstrap_badge("Hello!", type: 'success')
|
20
|
+
# # => '<span class="badge badge-success">Hello!</span>'
|
21
|
+
#
|
22
|
+
# bootstrap_badge("Hello!", type: 'warning', class: "my_awesome_class")
|
23
|
+
# # => '<span class="my_awesome_class badge badge-warning">Hello!</span>'
|
24
|
+
#
|
25
|
+
# bootstrap_badge("Hello!", type: 'info', bootstrap_class_prefix: "my_badge")
|
26
|
+
# # => '<span class="my_badge my_badge-warning">Hello!</span>'
|
27
|
+
#
|
28
|
+
# Returns HTML String for the badge
|
29
|
+
def bootstrap_badge(message, options = {})
|
30
|
+
Shoehorn::Components::Badge.new(
|
31
|
+
message,
|
32
|
+
options
|
33
|
+
).to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Shoehorn::Helpers
|
3
|
+
module ButtonHelpers
|
4
|
+
# Render a bootstrap button
|
5
|
+
#
|
6
|
+
# @param [String] text for the button face
|
7
|
+
# @param [String] link for the button href
|
8
|
+
# @param [Hash] options hash containing options (default: {}):
|
9
|
+
# :type - The String type of button to display: primary, info, success, warning, danger or inverse
|
10
|
+
# :size - The String size of button to display: large, small or mini
|
11
|
+
# :disabled - Will disable the button if set to true
|
12
|
+
# :class - The String additional CSS classes of the object
|
13
|
+
# :bootstrap_class_prefix - The String CSS class prefix from Twitter Bootstrap for the object
|
14
|
+
# :icon_name - Specify an icon name from bootstrap to prepend
|
15
|
+
# :icon_white - Specify true if you want the icon to be white
|
16
|
+
# :id - Assign an ID to the button
|
17
|
+
# :html_options - Any additional options you'd like to pass to the content_tag that will be created
|
18
|
+
# for this button's a tag (for instance :target can be specified in :html_options).
|
19
|
+
#
|
20
|
+
# NOTE: If you have to create a link to a resource#show you have to specify the full path as second param.
|
21
|
+
# Example: to create an anchor to the user#show path you have to write:
|
22
|
+
# bootstrap_button "Show", user_path(@user)
|
23
|
+
# instead of:
|
24
|
+
# bootstrap_button "Show", @user
|
25
|
+
#
|
26
|
+
# Examples
|
27
|
+
#
|
28
|
+
# bootstrap_button "Show", user_path(@user)
|
29
|
+
#
|
30
|
+
# bootstrap_button t('commons.search'), user_path(@user)
|
31
|
+
#
|
32
|
+
# bootstrap_button 'Search', search_path, type: 'primary', icon_name: 'search'
|
33
|
+
#
|
34
|
+
# bootstrap_button 'Show details', user_path(@user), icon_name: 'user', size: 'large'
|
35
|
+
#
|
36
|
+
# bootstrap_button 'Edit request', edit_request_path(@request), :type => 'primary', class: 'foo', id: 'bar'
|
37
|
+
#
|
38
|
+
# bootstrap_button 'Show details', user_path(@user), disabled: true
|
39
|
+
#
|
40
|
+
def bootstrap_button(text, link, options = {})
|
41
|
+
Shoehorn::Components::Button.new(
|
42
|
+
text,
|
43
|
+
link,
|
44
|
+
options
|
45
|
+
).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
# Render a dropdown button
|
49
|
+
#
|
50
|
+
# @param [Hash] options hash containing options (default: {}):
|
51
|
+
#
|
52
|
+
# Examples
|
53
|
+
#
|
54
|
+
# bootstrap_button_dropdown do |b|
|
55
|
+
# b.bootstrap_button "Actions', "#", type: 'primary'
|
56
|
+
# b.bootstrap_link_to "Show", request_path(@request), icon_name: 'zoom-in'
|
57
|
+
# b.bootstrap_link_to_if(can?(:reject, @request), t('.refuse'),
|
58
|
+
# reject_request_path(@request), icon_name: 'remove',
|
59
|
+
# html_options: { method: :put, data: { confirm: "Are you sure?" } }) { nil }
|
60
|
+
# b.bootstrap_link_to_if(can?(:accept, @request), "Accept",
|
61
|
+
# "#acceptModal_#{@request.id}", icon_name: 'ok',
|
62
|
+
# html_options: { data: { toggle: "modal" } }) { nil }
|
63
|
+
# b.link_to "Help", help_path
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# Returns HTML String for the dropdown
|
67
|
+
def bootstrap_dropdown(options = {})
|
68
|
+
# Elements will hold every call made to this block. Self is passed in so the
|
69
|
+
# elements can be sent to it in order to be evaluated
|
70
|
+
elements = Shoehorn::HelperCollection.new(self)
|
71
|
+
|
72
|
+
yield elements
|
73
|
+
|
74
|
+
Shoehorn::Components::Dropdown.new(
|
75
|
+
elements,
|
76
|
+
options
|
77
|
+
).to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
# Render a bootstrap link_to.
|
81
|
+
#
|
82
|
+
# They are a shortcut to bootstrap_button with bootstrap_class_prefix => nil .
|
83
|
+
# In this way they are rendered as normal links, without being styled.
|
84
|
+
#
|
85
|
+
def bootstrap_link_to(text, link, options = {})
|
86
|
+
options[:bootstrap_class_prefix] = nil
|
87
|
+
Shoehorn::Components::Button.new(
|
88
|
+
text,
|
89
|
+
link,
|
90
|
+
options
|
91
|
+
).to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
# Render a bootstrap link_to_unless.
|
95
|
+
#
|
96
|
+
# They are a shortcut to conditional bootstrap_button_link_to.
|
97
|
+
# In this way they are rendered as normal links, without being styled.
|
98
|
+
#
|
99
|
+
def bootstrap_link_to_unless(condition, text, link, options = {}, &block)
|
100
|
+
if condition
|
101
|
+
if block_given?
|
102
|
+
block.arity <= 1 ? capture(text, &block) : capture(text, link, options, &block)
|
103
|
+
else
|
104
|
+
text
|
105
|
+
end
|
106
|
+
else
|
107
|
+
bootstrap_link_to(text, link, options)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Render a bootstrap link_to_unless.
|
112
|
+
#
|
113
|
+
# They are a shortcut to conditional bootstrap_button_link_to.
|
114
|
+
# In this way they are rendered as normal links, without being styled.
|
115
|
+
#
|
116
|
+
def bootstrap_link_to_if(condition, text, link, options = {}, &block)
|
117
|
+
bootstrap_link_to_unless !condition, text, link, options, &block
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Shoehorn::Helpers
|
2
|
+
module FormHelpers
|
3
|
+
# Form builder
|
4
|
+
# TODO add documentation
|
5
|
+
def bootstrap_form_for(*args, &block)
|
6
|
+
options = args.extract_options!
|
7
|
+
options.reverse_merge!(:builder => Shoehorn::Components::FormBuilder)
|
8
|
+
form_for(*(args + [options]), &block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Shoehorn::Helpers
|
3
|
+
module IconHelpers
|
4
|
+
# Renders icons
|
5
|
+
#
|
6
|
+
# @param [Hash] options hash containing options (default: {}):
|
7
|
+
# :name - The String type of alert to display: success warning important notice
|
8
|
+
# :text - The String of a text to show inline with the icon
|
9
|
+
# :class - The String additional CSS classes of the object
|
10
|
+
# :bootstrap_class_prefix - The String CSS class prefix from Twitter Bootstrap for the object
|
11
|
+
# :html_options - Any additional options you'd like to pass to the span tag that will be created
|
12
|
+
# for this label (for instance :"data-whatever" can be specified in :html_options).
|
13
|
+
#
|
14
|
+
# Examples
|
15
|
+
#
|
16
|
+
# bootstrap_icon(name: 'user', icon_white: true)
|
17
|
+
# # => '<i class="icon-user icon-white"></i>'
|
18
|
+
#
|
19
|
+
# bootstrap_icon(text: "Current time", name: 'time')
|
20
|
+
# # => '<i class="icon-time"></i> Current time'
|
21
|
+
#
|
22
|
+
# bootstrap_icon(class: "my_awesome_class", name: 'glass')
|
23
|
+
# # => '<i class="icon-glass my_awesome_class"></i>'
|
24
|
+
#
|
25
|
+
# Returns HTML String for the icons
|
26
|
+
def bootstrap_icon(options = {})
|
27
|
+
Shoehorn::Components::Icon.new(
|
28
|
+
options
|
29
|
+
).to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Shoehorn::Helpers
|
3
|
+
module LabelHelpers
|
4
|
+
# Renders inline label
|
5
|
+
#
|
6
|
+
# @param [String] message message to be displayed
|
7
|
+
# @param [Hash] options hash containing options (default: {}):
|
8
|
+
# :type - The String type of alert to display: info, success, warning, important or inverse
|
9
|
+
# :class - The String additional CSS classes of the object
|
10
|
+
# :bootstrap_class_prefix - The String CSS class prefix from Twitter Bootstrap for the object
|
11
|
+
# :html_options - Any additional options you'd like to pass to the span tag that will be created
|
12
|
+
# for this label (for instance :"data-whatever" can be specified in :html_options).
|
13
|
+
#
|
14
|
+
# Examples
|
15
|
+
#
|
16
|
+
# bootstrap_label("Hello!")
|
17
|
+
# # => '<span class="label">Hello!</span>'
|
18
|
+
#
|
19
|
+
# bootstrap_label("Hello!", type: 'warning')
|
20
|
+
# # => '<span class="label label-warning">Hello!</span>'
|
21
|
+
#
|
22
|
+
# bootstrap_label("Hello!", type: 'important', class: "my_awesome_class")
|
23
|
+
# # => '<span class="my_awesome_class label label-important">Hello!</span>'
|
24
|
+
#
|
25
|
+
# bootstrap_label("Hello!", type: 'info', bootstrap_class_prefix: "my_label")
|
26
|
+
# # => '<span class="my_label my_label-info">Hello!</span>'
|
27
|
+
#
|
28
|
+
# Returns HTML String for the label
|
29
|
+
def bootstrap_label(message, options = {})
|
30
|
+
Shoehorn::Components::Label.new(
|
31
|
+
message,
|
32
|
+
options
|
33
|
+
).to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|