interview 0.1.0 → 0.3.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.
- checksums.yaml +4 -4
- data/interview.gemspec +1 -0
- data/lib/{generators/interview/install/templates → assets/javascripts}/interview.js.coffee +17 -25
- data/lib/{generators/interview/install/templates/bootstrap_interview.css.scss → assets/stylesheets/interview.css.scss} +3 -2
- data/lib/generators/interview/install/install_generator.rb +0 -2
- data/lib/generators/interview/install/templates/interview.rb +1 -1
- data/lib/interview.rb +65 -51
- data/lib/interview/association_methods.rb +2 -0
- data/lib/interview/builder.rb +32 -24
- data/lib/interview/control.rb +25 -7
- data/lib/interview/controls/actionbar.rb +41 -0
- data/lib/interview/controls/alert.rb +15 -0
- data/lib/interview/{association_attribute.rb → controls/association_attribute.rb} +8 -8
- data/lib/interview/{association_list_attribute.rb → controls/association_list_attribute.rb} +10 -9
- data/lib/interview/controls/attribute.rb +80 -0
- data/lib/interview/controls/auto_attribute.rb +16 -0
- data/lib/interview/controls/boolean_attribute.rb +20 -0
- data/lib/interview/controls/breadcrumbs.rb +15 -0
- data/lib/interview/controls/button.rb +25 -0
- data/lib/interview/controls/caret.rb +9 -0
- data/lib/interview/controls/collapse_container.rb +16 -0
- data/lib/interview/controls/container.rb +5 -0
- data/lib/interview/controls/container_attribute.rb +28 -0
- data/lib/interview/controls/date_attribute.rb +23 -0
- data/lib/interview/controls/datetime_attribute.rb +22 -0
- data/lib/interview/controls/decimal_attribute.rb +12 -0
- data/lib/interview/controls/dropdown.rb +35 -0
- data/lib/interview/controls/form.rb +35 -0
- data/lib/interview/controls/form_errors.rb +20 -0
- data/lib/interview/controls/glyphicon.rb +19 -0
- data/lib/interview/controls/grid.rb +62 -0
- data/lib/interview/controls/hidden_attribute.rb +11 -0
- data/lib/interview/controls/horizontal_form_container.rb +13 -0
- data/lib/interview/controls/html_control.rb +13 -0
- data/lib/interview/controls/html_doctype.rb +9 -0
- data/lib/interview/controls/html_headers.rb +12 -0
- data/lib/interview/{html_text_attribute.rb → controls/html_text_attribute.rb} +9 -5
- data/lib/interview/controls/image_attribute.rb +61 -0
- data/lib/interview/controls/image_gallery_attribute.rb +72 -0
- data/lib/interview/controls/image_light_box.rb +17 -0
- data/lib/interview/{integer_attribute.rb → controls/integer_attribute.rb} +0 -0
- data/lib/interview/controls/link.rb +90 -0
- data/lib/interview/controls/list.rb +20 -0
- data/lib/interview/controls/media_object.rb +37 -0
- data/lib/interview/controls/navigation.rb +11 -0
- data/lib/interview/controls/navigation_item.rb +33 -0
- data/lib/interview/controls/nested_form.rb +45 -0
- data/lib/interview/controls/nested_form_add_images.rb +15 -0
- data/lib/interview/controls/nested_form_add_link.rb +29 -0
- data/lib/interview/controls/nested_form_remove_link.rb +12 -0
- data/lib/interview/{option_attribute.rb → controls/option_attribute.rb} +19 -19
- data/lib/interview/controls/pagination.rb +12 -0
- data/lib/interview/controls/panel.rb +13 -0
- data/lib/interview/{polymorphic_add_link.rb → controls/polymorphic_add_link.rb} +1 -1
- data/lib/interview/controls/polymorphic_nested_form.rb +17 -0
- data/lib/interview/{nested_form_add_link.rb → controls/polymorphic_nested_form_add_link.rb} +12 -28
- data/lib/interview/controls/progress_bar.rb +18 -0
- data/lib/interview/controls/scaffold_card.rb +27 -0
- data/lib/interview/controls/scaffold_form.rb +108 -0
- data/lib/interview/controls/search_form.rb +25 -0
- data/lib/interview/controls/section.rb +16 -0
- data/lib/interview/{space.rb → controls/space.rb} +5 -6
- data/lib/interview/{string_attribute.rb → controls/string_attribute.rb} +0 -0
- data/lib/interview/controls/submit.rb +14 -0
- data/lib/interview/controls/tab.rb +27 -0
- data/lib/interview/controls/tab_box.rb +21 -0
- data/lib/interview/controls/text.rb +33 -0
- data/lib/interview/{text_attribute.rb → controls/text_attribute.rb} +7 -5
- data/lib/interview/controls/tooltip.rb +21 -0
- data/lib/interview/{tree.rb → controls/tree.rb} +2 -3
- data/lib/interview/{view.rb → controls/view.rb} +4 -6
- data/lib/interview/engine.rb +4 -0
- data/lib/interview/handler.rb +15 -0
- data/lib/interview/has_html_options.rb +29 -0
- data/lib/interview/meta_control.rb +18 -0
- data/lib/interview/nested_buildable.rb +17 -0
- data/lib/interview/version.rb +1 -1
- metadata +84 -54
- data/lib/interview/actionbar.rb +0 -39
- data/lib/interview/attribute.rb +0 -166
- data/lib/interview/boolean_attribute.rb +0 -59
- data/lib/interview/breadcrumbs.rb +0 -21
- data/lib/interview/button.rb +0 -29
- data/lib/interview/collapse_container.rb +0 -31
- data/lib/interview/condition_container.rb +0 -19
- data/lib/interview/container.rb +0 -13
- data/lib/interview/container_attribute.rb +0 -30
- data/lib/interview/date_attribute.rb +0 -20
- data/lib/interview/datetime_attribute.rb +0 -20
- data/lib/interview/decimal_attribute.rb +0 -10
- data/lib/interview/dropdown.rb +0 -39
- data/lib/interview/form.rb +0 -64
- data/lib/interview/form_errors.rb +0 -22
- data/lib/interview/grid.rb +0 -54
- data/lib/interview/has_controls.rb +0 -40
- data/lib/interview/hidden_attribute.rb +0 -15
- data/lib/interview/html_control.rb +0 -21
- data/lib/interview/image_attribute.rb +0 -59
- data/lib/interview/image_gallery_attribute.rb +0 -79
- data/lib/interview/image_light_box.rb +0 -19
- data/lib/interview/link.rb +0 -134
- data/lib/interview/list.rb +0 -26
- data/lib/interview/media_object.rb +0 -27
- data/lib/interview/navigation.rb +0 -55
- data/lib/interview/navigation_item.rb +0 -41
- data/lib/interview/navigation_item_old.rb +0 -26
- data/lib/interview/nested_form.rb +0 -66
- data/lib/interview/nested_form_add_images.rb +0 -33
- data/lib/interview/nested_form_remove_link.rb +0 -28
- data/lib/interview/panel.rb +0 -18
- data/lib/interview/progress_bar.rb +0 -25
- data/lib/interview/search_form.rb +0 -21
- data/lib/interview/tab.rb +0 -21
- data/lib/interview/tab_box.rb +0 -30
- data/lib/interview/text.rb +0 -45
- data/lib/interview/tooltip.rb +0 -38
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class Alert < Text
|
|
3
|
+
|
|
4
|
+
def build(b)
|
|
5
|
+
html_class = @html_class.dup
|
|
6
|
+
html_class << 'alert'
|
|
7
|
+
html_class << "alert-#{@style}" if @style
|
|
8
|
+
b.section html_class: html_class, html_options: @html_options do
|
|
9
|
+
build_text(b)
|
|
10
|
+
yield if block_given?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -3,17 +3,17 @@ module Interview
|
|
|
3
3
|
|
|
4
4
|
attr_accessor :association_class
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def build_read(b)
|
|
9
|
+
return if value.nil?
|
|
8
10
|
assoc_object = value
|
|
9
11
|
# todo: Link nicht anzeigen, wenn Route für Objekt nicht existiert
|
|
10
|
-
|
|
11
|
-
caption: "#{assoc_object.human_id}",
|
|
12
|
-
object: assoc_object).render
|
|
12
|
+
b.link parent: self, caption: "#{assoc_object.human_id}", object: assoc_object
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def
|
|
16
|
-
object = find_attribute!(:object)
|
|
15
|
+
def build_write(b)
|
|
16
|
+
object = @object || find_attribute!(:object)
|
|
17
17
|
if object.respond_to? "#{method}_pool"
|
|
18
18
|
pool = object.send "#{method}_pool"
|
|
19
19
|
elsif @association_class
|
|
@@ -23,7 +23,7 @@ module Interview
|
|
|
23
23
|
assoc_class = object.class.new.send("build_#{@method}").class
|
|
24
24
|
pool = assoc_class.all
|
|
25
25
|
end
|
|
26
|
-
form_builder.collection_select
|
|
26
|
+
b << form_builder.collection_select("#{@method}_id", pool, :id, :human_id, {include_blank: true}, {class: 'form-control'})
|
|
27
27
|
# todo: prompt einbauen
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -3,23 +3,24 @@ module Interview
|
|
|
3
3
|
|
|
4
4
|
attr_accessor :use, :size
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def build_read(b)
|
|
9
|
+
return if value.nil?
|
|
8
10
|
assoc_objects = value
|
|
9
11
|
assoc_count = assoc_objects.count
|
|
10
12
|
if @use == 'link'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
filter: assoc_objects.where_values_hash).render # todo: Überarbeiten
|
|
13
|
+
b.link caption: "#{@method.humanize} (#{assoc_count})", object: "#{assoc_objects.klass}",
|
|
14
|
+
filter: assoc_objects.where_values_hash # todo: Überarbeiten
|
|
14
15
|
else
|
|
15
|
-
|
|
16
|
+
b.text text: assoc_objects.human_ids.join(', ')
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
|
|
19
|
-
def
|
|
20
|
+
def build_write(b)
|
|
20
21
|
size = @size || 8
|
|
21
22
|
if @use == 'multi_select'
|
|
22
|
-
object = find_attribute!(:object)
|
|
23
|
+
object = @object || find_attribute!(:object)
|
|
23
24
|
if object.respond_to? "#{method.singularize}_pool"
|
|
24
25
|
pool = object.send "#{method.singularize}_pool"
|
|
25
26
|
else
|
|
@@ -29,7 +30,7 @@ module Interview
|
|
|
29
30
|
form_builder.collection_select "#{@method.singularize}_ids", pool, :id, :human_id, {prompt: true}, {class: 'form-control', multiple: true, size: size}
|
|
30
31
|
# form_builder.collection_select "#{@method.singularize}_ids", Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true
|
|
31
32
|
else
|
|
32
|
-
|
|
33
|
+
b << form_builder.text_field("#{@method}_human_ids_string", class: 'form-control')
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class Attribute < Control
|
|
3
|
+
|
|
4
|
+
include HasHtmlOptions # todo: delete?
|
|
5
|
+
|
|
6
|
+
# todo: Idee lookup_object methoden einbauen
|
|
7
|
+
|
|
8
|
+
attr_accessor :object, :method, :caption, :value, :style, :link,
|
|
9
|
+
:tooltip, :nil_value, :caption_as_placeholder
|
|
10
|
+
|
|
11
|
+
def value
|
|
12
|
+
return @value if @value
|
|
13
|
+
|
|
14
|
+
object = @object || find_attribute!(:object)
|
|
15
|
+
if object.respond_to? @method
|
|
16
|
+
val = object.send @method
|
|
17
|
+
end
|
|
18
|
+
val = @nil_value if val.nil?
|
|
19
|
+
return val
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def build_caption(b)
|
|
23
|
+
@parent ||= b.curr_parent
|
|
24
|
+
b.text text: caption
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def caption
|
|
28
|
+
return @caption if @caption
|
|
29
|
+
|
|
30
|
+
object = @object || find_attribute!(:object)
|
|
31
|
+
return object.class.human_attribute_name(@method)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def tooltip
|
|
35
|
+
return @tooltip if @tooltip
|
|
36
|
+
|
|
37
|
+
object = @object || find_attribute!(:object)
|
|
38
|
+
tooltip = h.t("activerecord.attribute_tooltips.#{object.class.model_name.i18n_key}.#{@method}", default: '')
|
|
39
|
+
tooltip = :hide if tooltip == ''
|
|
40
|
+
return tooltip
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def build(b, &block)
|
|
44
|
+
if @style == 'write'
|
|
45
|
+
build_write(b, &block)
|
|
46
|
+
else
|
|
47
|
+
build_read(b, &block)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
protected
|
|
52
|
+
|
|
53
|
+
def build_read(b)
|
|
54
|
+
add_link(b) do
|
|
55
|
+
b.text text: value.to_s
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def build_write(b)
|
|
60
|
+
opts = { class: 'form-control' }
|
|
61
|
+
opts[:placeholder] = caption if @caption_as_placeholder
|
|
62
|
+
b << form_builder.text_field(@method, opts)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def form_builder
|
|
66
|
+
return find_attribute! :form_builder
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def add_link(b)
|
|
70
|
+
if @link
|
|
71
|
+
b.link do
|
|
72
|
+
yield
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
yield
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class AutoAttribute < Attribute
|
|
3
|
+
|
|
4
|
+
def build(b)
|
|
5
|
+
object = @object || find_attribute!(:object)
|
|
6
|
+
if object.class.column_types[@method]
|
|
7
|
+
attribute_type = object.class.column_types[@method].type
|
|
8
|
+
attribute_class = "#{type.to_s.camelcase}Attribute"
|
|
9
|
+
if Object.const_defined?(attribute_class)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class BooleanAttribute < Attribute
|
|
3
|
+
|
|
4
|
+
protected
|
|
5
|
+
|
|
6
|
+
def build_read(b)
|
|
7
|
+
return if value.nil?
|
|
8
|
+
if value
|
|
9
|
+
b.glyphicon image: 'ok'
|
|
10
|
+
else
|
|
11
|
+
b.text text: ''
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def build_write(b)
|
|
16
|
+
b << form_builder.check_box(@method)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class Button < Control
|
|
3
|
+
|
|
4
|
+
include HasHtmlOptions
|
|
5
|
+
|
|
6
|
+
attr_accessor :caption, :name, :style, :submit
|
|
7
|
+
|
|
8
|
+
def build(b)
|
|
9
|
+
html_class = @html_class.dup
|
|
10
|
+
if @style.to_s == 'primary'
|
|
11
|
+
html_class += %w(btn btn-primary)
|
|
12
|
+
else
|
|
13
|
+
html_class += %w(btn btn-default)
|
|
14
|
+
end
|
|
15
|
+
@html_options[:name] = @name
|
|
16
|
+
|
|
17
|
+
if @submit
|
|
18
|
+
b << h.submit_tag(@caption, options_to_html(@html_options, html_class))
|
|
19
|
+
else
|
|
20
|
+
b << h.button_tag(@caption, options_to_html(@html_options, html_class))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class CollapseContainer < Control
|
|
3
|
+
|
|
4
|
+
attr_accessor :image, :caption
|
|
5
|
+
|
|
6
|
+
def build(b)
|
|
7
|
+
new_id = Time.now.to_f.to_s.delete('.')
|
|
8
|
+
b.link image: @image, caption: @caption, url: '#', html_class: 'collapse_link',
|
|
9
|
+
html_options: { data: { toogle: 'collapse', target: "##{new_id}" } }
|
|
10
|
+
b.section html_class: 'panel-collapse collapse', html_options: { id: new_id } do
|
|
11
|
+
yield if block_given?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class ContainerAttribute < Attribute
|
|
3
|
+
|
|
4
|
+
def initialize(params={})
|
|
5
|
+
@tooltip = :hide
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def value
|
|
10
|
+
return nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def caption
|
|
14
|
+
return @caption.to_s
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
protected
|
|
18
|
+
|
|
19
|
+
def build_read(b)
|
|
20
|
+
yield if block_given?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def build_write(b)
|
|
24
|
+
build_read(b)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class DateAttribute < Attribute
|
|
3
|
+
|
|
4
|
+
attr_accessor :format
|
|
5
|
+
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def build_read(b)
|
|
9
|
+
return if value.nil?
|
|
10
|
+
if @format
|
|
11
|
+
b.text text: value.strftime(@format)
|
|
12
|
+
else
|
|
13
|
+
b << h.l(value)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def build_write(b)
|
|
18
|
+
# todo: Date auswahl einbauen
|
|
19
|
+
b << form_builder.date_select(@method) # todo: , {}, {class: 'form-control'}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class DatetimeAttribute < Attribute
|
|
3
|
+
|
|
4
|
+
attr_accessor :format
|
|
5
|
+
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def build_read(b)
|
|
9
|
+
return if value.nil?
|
|
10
|
+
if @format
|
|
11
|
+
b.text text: value.strftime(@format)
|
|
12
|
+
else
|
|
13
|
+
b << h.l(value)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def build_write(b)
|
|
18
|
+
b << form_builder.date_select(@method) # todo: , {}, {class: 'form-control'}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class Dropdown < Control
|
|
3
|
+
|
|
4
|
+
include HasHtmlOptions
|
|
5
|
+
|
|
6
|
+
attr_accessor :image, :caption, :style, :container_tag
|
|
7
|
+
|
|
8
|
+
def build(b)
|
|
9
|
+
container_tag = @container_tag || 'div'
|
|
10
|
+
html_class = @html_class.dup
|
|
11
|
+
html_class << 'dropdown'
|
|
12
|
+
b.section style: container_tag, html_class: html_class, html_options: @html_options do
|
|
13
|
+
html_class = %w(dropdown-toggle)
|
|
14
|
+
html_class += %w(btn btn-default) if @style == 'button'
|
|
15
|
+
b.link image: @image, caption: @caption, url: '#', html_class: html_class,
|
|
16
|
+
html_options: { data: { toggle: 'dropdown' } } do
|
|
17
|
+
b.space if @image or @caption
|
|
18
|
+
b.glyphicon image: 'caret'
|
|
19
|
+
end
|
|
20
|
+
b.section style: 'ul', html_class: 'dropdown-menu' do
|
|
21
|
+
b.meta_control pointer: self do
|
|
22
|
+
yield if block_given?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def build_child(b, control, &block)
|
|
29
|
+
b.section style: 'li' do
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Interview
|
|
2
|
+
class Form < Control
|
|
3
|
+
|
|
4
|
+
include HasHtmlOptions, NestedBuildable
|
|
5
|
+
|
|
6
|
+
attr_accessor :object, :redirect_to
|
|
7
|
+
attr_reader :form_builder
|
|
8
|
+
|
|
9
|
+
def build(b)
|
|
10
|
+
object = @object || find_attribute!(:object)
|
|
11
|
+
b << h.form_for(object, role: 'form', html: options_to_html) do |form_builder|
|
|
12
|
+
@form_builder = form_builder
|
|
13
|
+
create_nested_builder(b)
|
|
14
|
+
|
|
15
|
+
b.form_errors
|
|
16
|
+
build_default_controls(b)
|
|
17
|
+
|
|
18
|
+
yield if block_given?
|
|
19
|
+
|
|
20
|
+
render_nested_builder(b)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
protected
|
|
25
|
+
|
|
26
|
+
def build_default_controls(b) # todo: auslagern?
|
|
27
|
+
if @redirect_to == :parent and Object.const_defined? 'Gretel'
|
|
28
|
+
b << h.hidden_field_tag('redirect_to', h.parent_breadcrumb.url)
|
|
29
|
+
elsif @redirect_to == :current
|
|
30
|
+
b << h.hidden_field_tag('redirect_to', h.request.original_url)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|