freeform 1.0.11 → 2.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.
- checksums.yaml +8 -8
- data/Gemfile.lock +3 -3
- data/README.md +16 -17
- data/lib/freeform/form/date_params_filter.rb +34 -0
- data/lib/freeform/form/model.rb +56 -0
- data/lib/freeform/form/nested.rb +64 -39
- data/lib/freeform/form/property.rb +31 -75
- data/lib/freeform/form/validation.rb +48 -34
- data/lib/freeform/form.rb +31 -42
- data/lib/freeform/version.rb +1 -1
- data/spec/acceptance_spec.rb +140 -260
- data/spec/builder/builder_spec.rb +23 -41
- data/spec/builder/view_helper_spec.rb +7 -16
- data/spec/dummy/app/forms/project_form.rb +16 -2
- data/spec/dummy/app/models/company.rb +2 -2
- data/spec/dummy/app/models/milestone.rb +3 -3
- data/spec/dummy/app/models/project.rb +3 -3
- data/spec/dummy/app/models/task.rb +2 -2
- data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +5 -5
- data/spec/dummy/db/schema.rb +6 -4
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/form/date_params_filter_spec.rb +51 -0
- data/spec/form/form_input_key_spec.rb +9 -11
- data/spec/form/model_spec.rb +244 -0
- data/spec/form/nested_spec.rb +108 -138
- data/spec/form/persistence_spec.rb +304 -0
- data/spec/form/property_spec.rb +104 -256
- data/spec/form/validation_spec.rb +114 -127
- data/spec/spec_helper.rb +6 -0
- metadata +10 -10
- data/spec/dummy/app/forms/milestone_form.rb +0 -4
- data/spec/dummy/app/forms/task_form.rb +0 -11
- data/spec/dummy/log/test.log +0 -111133
- data/spec/persistence_spec.rb +0 -645
@@ -2,42 +2,6 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
[FreeForm::Builder, FreeForm::SimpleBuilder, defined?(FreeForm::FormtasticBuilder) ? FreeForm::FormtasticBuilder : nil].compact.each do |builder|
|
4
4
|
describe builder do
|
5
|
-
let!(:milestone_form_class) do
|
6
|
-
klass = Class.new(FreeForm::Form) do
|
7
|
-
form_input_key :milestone
|
8
|
-
form_models :milestone
|
9
|
-
allow_destroy_on_save
|
10
|
-
|
11
|
-
property :name, :on => :milestone
|
12
|
-
end
|
13
|
-
# This wrapper just avoids CONST warnings
|
14
|
-
v, $VERBOSE = $VERBOSE, nil
|
15
|
-
Module.const_set("MilestoneForm", klass)
|
16
|
-
$VERBOSE = v
|
17
|
-
klass
|
18
|
-
end
|
19
|
-
|
20
|
-
let!(:task_form_class) do
|
21
|
-
klass = Class.new(FreeForm::Form) do
|
22
|
-
form_input_key :task
|
23
|
-
form_models :task
|
24
|
-
allow_destroy_on_save
|
25
|
-
|
26
|
-
property :name, :on => :task
|
27
|
-
|
28
|
-
has_many :milestones, :class => Module::MilestoneForm, :default_initializer => :milestone_initializer
|
29
|
-
|
30
|
-
def milestone_initializer
|
31
|
-
{:milestone => Milestone.new}
|
32
|
-
end
|
33
|
-
end
|
34
|
-
# This wrapper just avoids CONST warnings
|
35
|
-
v, $VERBOSE = $VERBOSE, nil
|
36
|
-
Module.const_set("TaskForm", klass)
|
37
|
-
$VERBOSE = v
|
38
|
-
klass
|
39
|
-
end
|
40
|
-
|
41
5
|
let(:form_class) do
|
42
6
|
klass = Class.new(FreeForm::Form) do
|
43
7
|
form_input_key :project
|
@@ -46,7 +10,25 @@ require "spec_helper"
|
|
46
10
|
|
47
11
|
property :name, :on => :project
|
48
12
|
|
49
|
-
has_many :tasks
|
13
|
+
has_many :tasks do
|
14
|
+
form_input_key :task
|
15
|
+
form_models :task
|
16
|
+
allow_destroy_on_save
|
17
|
+
|
18
|
+
property :name, :on => :task
|
19
|
+
|
20
|
+
has_many :milestones do
|
21
|
+
form_input_key :milestone
|
22
|
+
form_models :milestone
|
23
|
+
allow_destroy_on_save
|
24
|
+
|
25
|
+
property :name, :on => :milestone
|
26
|
+
end
|
27
|
+
|
28
|
+
def milestone_initializer
|
29
|
+
{:milestone => Milestone.new}
|
30
|
+
end
|
31
|
+
end
|
50
32
|
|
51
33
|
def task_initializer
|
52
34
|
{:task => Task.new}
|
@@ -62,9 +44,9 @@ require "spec_helper"
|
|
62
44
|
let(:form) { form_class.new(:project => Project.new) }
|
63
45
|
|
64
46
|
let(:template) do
|
65
|
-
|
66
|
-
|
67
|
-
|
47
|
+
ActionView::Base.new.tap do |t|
|
48
|
+
t.output_buffer = ""
|
49
|
+
end
|
68
50
|
end
|
69
51
|
|
70
52
|
context "with no options", :no_options => true do
|
@@ -212,4 +194,4 @@ require "spec_helper"
|
|
212
194
|
end
|
213
195
|
end
|
214
196
|
end
|
215
|
-
end
|
197
|
+
end
|
@@ -9,21 +9,6 @@ describe FreeForm::ViewHelper do
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
let!(:task_form_class) do
|
13
|
-
klass = Class.new(FreeForm::Form) do
|
14
|
-
form_input_key :task
|
15
|
-
form_model :task
|
16
|
-
allow_destroy_on_save
|
17
|
-
|
18
|
-
property :name, :on => :task
|
19
|
-
end
|
20
|
-
# This wrapper just avoids CONST warnings
|
21
|
-
v, $VERBOSE = $VERBOSE, nil
|
22
|
-
Module.const_set("TaskForm", klass)
|
23
|
-
$VERBOSE = v
|
24
|
-
klass
|
25
|
-
end
|
26
|
-
|
27
12
|
let(:form_class) do
|
28
13
|
klass = Class.new(FreeForm::Form) do
|
29
14
|
form_input_key :project
|
@@ -32,7 +17,13 @@ describe FreeForm::ViewHelper do
|
|
32
17
|
|
33
18
|
property :name, :on => :project
|
34
19
|
|
35
|
-
has_many :tasks
|
20
|
+
has_many :tasks do
|
21
|
+
form_input_key :task
|
22
|
+
form_model :task
|
23
|
+
allow_destroy_on_save
|
24
|
+
|
25
|
+
property :name, :on => :task
|
26
|
+
end
|
36
27
|
|
37
28
|
def task_initializer
|
38
29
|
{:task => Task.new}
|
@@ -3,9 +3,23 @@ class ProjectForm < FreeForm::Form
|
|
3
3
|
form_models :project
|
4
4
|
property :name, :on => :project
|
5
5
|
|
6
|
-
has_many :tasks
|
6
|
+
has_many :tasks do
|
7
|
+
form_models :task
|
8
|
+
property :name, :on => :task
|
9
|
+
allow_destroy_on_save
|
10
|
+
|
11
|
+
has_many :milestones do
|
12
|
+
form_models :milestone
|
13
|
+
property :name, :on => :milestone
|
14
|
+
allow_destroy_on_save
|
15
|
+
end
|
16
|
+
|
17
|
+
def milestone_initializer
|
18
|
+
{ :milestone => task.milestones.build }
|
19
|
+
end
|
20
|
+
end
|
7
21
|
|
8
22
|
def task_initializer
|
9
|
-
{ :task =>
|
23
|
+
{ :task => project.tasks.build }
|
10
24
|
end
|
11
25
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class Project < ActiveRecord::Base
|
2
|
-
belongs_to :
|
2
|
+
belongs_to :owner, :polymorphic => true
|
3
3
|
has_many :tasks
|
4
4
|
has_many :assignments, :class_name => 'ProjectTask'
|
5
5
|
|
6
|
-
validates :
|
6
|
+
validates :owner, :presence => true
|
7
7
|
validates :name, :presence => true
|
8
8
|
validates :due_date, :presence => true
|
9
|
-
end
|
9
|
+
end
|
@@ -5,25 +5,25 @@ class InitialTables < ActiveRecord::Migration
|
|
5
5
|
end
|
6
6
|
|
7
7
|
create_table :projects do |t|
|
8
|
-
t.
|
8
|
+
t.references :owner, :polymorphic => true, :null => false
|
9
9
|
t.string :name
|
10
10
|
t.date :due_date
|
11
11
|
end
|
12
12
|
|
13
13
|
create_table :tasks do |t|
|
14
|
-
t.
|
14
|
+
t.references :project, :null => false
|
15
15
|
t.string :name
|
16
16
|
t.date :start_date
|
17
17
|
t.date :end_date
|
18
18
|
end
|
19
19
|
|
20
20
|
create_table :milestones do |t|
|
21
|
-
t.
|
21
|
+
t.references :trackable, :polymorphic => true, :null => false
|
22
22
|
t.string :name
|
23
23
|
end
|
24
24
|
|
25
25
|
create_table :project_tasks do |t|
|
26
|
-
t.
|
26
|
+
t.references :project, :null => false
|
27
27
|
t.string :name
|
28
28
|
end
|
29
29
|
end
|
@@ -35,4 +35,4 @@ class InitialTables < ActiveRecord::Migration
|
|
35
35
|
drop_table :milestones
|
36
36
|
drop_table :project_tasks
|
37
37
|
end
|
38
|
-
end
|
38
|
+
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -18,23 +18,25 @@ ActiveRecord::Schema.define(:version => 20110710143903) do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
create_table "milestones", :force => true do |t|
|
21
|
-
t.integer "
|
21
|
+
t.integer "trackable_id", :null => false
|
22
|
+
t.string "trackable_type", :null => false
|
22
23
|
t.string "name"
|
23
24
|
end
|
24
25
|
|
25
26
|
create_table "project_tasks", :force => true do |t|
|
26
|
-
t.integer "project_id"
|
27
|
+
t.integer "project_id", :null => false
|
27
28
|
t.string "name"
|
28
29
|
end
|
29
30
|
|
30
31
|
create_table "projects", :force => true do |t|
|
31
|
-
t.integer "
|
32
|
+
t.integer "owner_id", :null => false
|
33
|
+
t.string "owner_type", :null => false
|
32
34
|
t.string "name"
|
33
35
|
t.date "due_date"
|
34
36
|
end
|
35
37
|
|
36
38
|
create_table "tasks", :force => true do |t|
|
37
|
-
t.integer "project_id"
|
39
|
+
t.integer "project_id", :null => false
|
38
40
|
t.string "name"
|
39
41
|
t.date "start_date"
|
40
42
|
t.date "end_date"
|
data/spec/dummy/db/test.sqlite3
CHANGED
Binary file
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'freeform/form/date_params_filter'
|
3
|
+
|
4
|
+
describe FreeForm::DateParamsFilter do
|
5
|
+
describe "#call", :call => true do
|
6
|
+
let(:params) do
|
7
|
+
{
|
8
|
+
:company_name => "dummycorp",
|
9
|
+
:project_name => "railsapp",
|
10
|
+
"due_date(1i)" => "2014",
|
11
|
+
"due_date(2i)" => "10",
|
12
|
+
"due_date(3i)" => "30",
|
13
|
+
:tasks_attributes => {
|
14
|
+
"0" => {
|
15
|
+
:name => "task_1",
|
16
|
+
"start_date(1i)" => "2012",
|
17
|
+
"start_date(2i)" => "1",
|
18
|
+
"start_date(3i)" => "2",
|
19
|
+
},
|
20
|
+
"1" => {
|
21
|
+
:name => "task_2",
|
22
|
+
"end_date(1i)" => "2011",
|
23
|
+
"end_date(2i)" => "12",
|
24
|
+
},
|
25
|
+
},
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
subject { described_class.new.call(params) }
|
30
|
+
|
31
|
+
it "should have filtered all date params into Date objects" do
|
32
|
+
subject.should eq(
|
33
|
+
{
|
34
|
+
:company_name => "dummycorp",
|
35
|
+
:project_name => "railsapp",
|
36
|
+
"due_date" => Date.new(2014, 10, 30),
|
37
|
+
:tasks_attributes => {
|
38
|
+
"0" => {
|
39
|
+
:name => "task_1",
|
40
|
+
"start_date" => Date.new(2012, 1, 2),
|
41
|
+
},
|
42
|
+
"1" => {
|
43
|
+
:name => "task_2",
|
44
|
+
"end_date" => Date.new(2011, 12, 1),
|
45
|
+
},
|
46
|
+
},
|
47
|
+
}
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -2,18 +2,16 @@ require 'spec_helper'
|
|
2
2
|
require 'freeform/form/form_input_key'
|
3
3
|
|
4
4
|
describe FreeForm::FormInputKey do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
attr_accessor :my_accessor
|
12
|
-
end
|
5
|
+
let(:form_class) do
|
6
|
+
Class.new(Module) do
|
7
|
+
include FreeForm::FormInputKey
|
8
|
+
form_input_key :test_key
|
9
|
+
|
10
|
+
attr_accessor :my_accessor
|
13
11
|
end
|
12
|
+
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
14
|
+
it "sets form_input_key" do
|
15
|
+
form_class.model_name.should eq("TestKey")
|
18
16
|
end
|
19
17
|
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'freeform/form/model'
|
3
|
+
|
4
|
+
describe FreeForm::Model do
|
5
|
+
describe "class methods", :class_methods => true do
|
6
|
+
describe "declared model", :declared_model => true do
|
7
|
+
let(:form_class) do
|
8
|
+
Class.new(Module) do
|
9
|
+
include FreeForm::Model
|
10
|
+
declared_model :test_model_1
|
11
|
+
declared_model :test_model_2
|
12
|
+
|
13
|
+
def initialize(h={})
|
14
|
+
h.each {|k,v| send("#{k}=",v)}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:form) do
|
20
|
+
form_class.new(
|
21
|
+
:test_model_1 => OpenStruct.new(:dummy => "yes"),
|
22
|
+
:test_model_2 => OpenStruct.new(:test => "clearly")
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets declared models as accessor" do
|
27
|
+
form.test_model_1.should eq(OpenStruct.new(:dummy => "yes"))
|
28
|
+
form.test_model_2.should eq(OpenStruct.new(:test => "clearly"))
|
29
|
+
end
|
30
|
+
|
31
|
+
it "has writable set accessors" do
|
32
|
+
form.test_model_1 = "Something New"
|
33
|
+
form.test_model_1.should eq("Something New")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "sets @models in class to declared models" do
|
37
|
+
form_class.models.should eq([:test_model_1, :test_model_2])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "form model", :form_model => true do
|
42
|
+
let(:form_class) do
|
43
|
+
Class.new(Module) do
|
44
|
+
include FreeForm::Model
|
45
|
+
form_model :test_model_1
|
46
|
+
form_model :test_model_2
|
47
|
+
|
48
|
+
def initialize(h={})
|
49
|
+
h.each {|k,v| send("#{k}=",v)}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:form) do
|
55
|
+
form_class.new(
|
56
|
+
:test_model_1 => OpenStruct.new(:dummy => "yes"),
|
57
|
+
:test_model_2 => OpenStruct.new(:test => "clearly")
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "sets declared models as accessor" do
|
62
|
+
form.test_model_1.should eq(OpenStruct.new(:dummy => "yes"))
|
63
|
+
form.test_model_2.should eq(OpenStruct.new(:test => "clearly"))
|
64
|
+
end
|
65
|
+
|
66
|
+
it "has writable set accessors" do
|
67
|
+
form.test_model_1 = "Something New"
|
68
|
+
form.test_model_1.should eq("Something New")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "sets @models in class to declared models" do
|
72
|
+
form_class.models.should eq([:test_model_1, :test_model_2])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "declared models", :declared_models => true do
|
77
|
+
let(:form_class) do
|
78
|
+
Class.new(Module) do
|
79
|
+
include FreeForm::Model
|
80
|
+
declared_models :test_model_1, :test_model_2
|
81
|
+
|
82
|
+
def initialize(h={})
|
83
|
+
h.each {|k,v| send("#{k}=",v)}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:form) do
|
89
|
+
form_class.new(
|
90
|
+
:test_model_1 => OpenStruct.new(:dummy => "yes"),
|
91
|
+
:test_model_2 => OpenStruct.new(:test => "clearly")
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "sets declared models as accessor" do
|
96
|
+
form.test_model_1.should eq(OpenStruct.new(:dummy => "yes"))
|
97
|
+
form.test_model_2.should eq(OpenStruct.new(:test => "clearly"))
|
98
|
+
end
|
99
|
+
|
100
|
+
it "has writable set accessors" do
|
101
|
+
form.test_model_1 = "Something New"
|
102
|
+
form.test_model_1.should eq("Something New")
|
103
|
+
end
|
104
|
+
|
105
|
+
it "sets @models in class to declared models" do
|
106
|
+
form_class.models.should eq([:test_model_1, :test_model_2])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "form models", :form_models => true do
|
111
|
+
let(:form_class) do
|
112
|
+
Class.new(Module) do
|
113
|
+
include FreeForm::Model
|
114
|
+
form_models :test_model_1, :test_model_2
|
115
|
+
|
116
|
+
def initialize(h={})
|
117
|
+
h.each {|k,v| send("#{k}=",v)}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
let(:form) do
|
123
|
+
form_class.new(
|
124
|
+
:test_model_1 => OpenStruct.new(:dummy => "yes"),
|
125
|
+
:test_model_2 => OpenStruct.new(:test => "clearly")
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "sets declared models as accessor" do
|
130
|
+
form.test_model_1.should eq(OpenStruct.new(:dummy => "yes"))
|
131
|
+
form.test_model_2.should eq(OpenStruct.new(:test => "clearly"))
|
132
|
+
end
|
133
|
+
|
134
|
+
it "has writable set accessors" do
|
135
|
+
form.test_model_1 = "Something New"
|
136
|
+
form.test_model_1.should eq("Something New")
|
137
|
+
end
|
138
|
+
|
139
|
+
it "sets @models in class to declared models" do
|
140
|
+
form_class.models.should eq([:test_model_1, :test_model_2])
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "child models", :child_models => true do
|
145
|
+
let(:form_class) do
|
146
|
+
Class.new(Module) do
|
147
|
+
include FreeForm::Model
|
148
|
+
form_model :test_model_1
|
149
|
+
child_model :test_model_2 do
|
150
|
+
test_model_1.build_child
|
151
|
+
end
|
152
|
+
|
153
|
+
def initialize(h={})
|
154
|
+
h.each {|k,v| send("#{k}=",v)}
|
155
|
+
initialize_test_model_2
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
let(:form) do
|
161
|
+
form_class.new(
|
162
|
+
:test_model_1 => OpenStruct.new(:dummy => "yes",
|
163
|
+
:build_child => OpenStruct.new(:field => "child model"))
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "sets declared models as accessor" do
|
168
|
+
form.test_model_1.should eq(OpenStruct.new(:dummy => "yes", :build_child => OpenStruct.new(:field => "child model")))
|
169
|
+
form.test_model_2.should eq(OpenStruct.new(:field => "child model"))
|
170
|
+
end
|
171
|
+
|
172
|
+
it "sets @models in class to declared models" do
|
173
|
+
form_class.models.should eq([:test_model_1, :test_model_2])
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "instance methods", :instance_methods => true do
|
179
|
+
describe "models", :models => true do
|
180
|
+
let(:model_1) { OpenStruct.new(:name => "first") }
|
181
|
+
let(:model_2) { OpenStruct.new(:name => "second") }
|
182
|
+
let(:address_1) { OpenStruct.new(:name => "main st.") }
|
183
|
+
let(:address_2) { OpenStruct.new(:name => "oak ave.") }
|
184
|
+
|
185
|
+
let(:form_class) do
|
186
|
+
Class.new(Module) do
|
187
|
+
include FreeForm::Model
|
188
|
+
include FreeForm::Nested
|
189
|
+
declared_model :first_model
|
190
|
+
declared_model :second_model
|
191
|
+
|
192
|
+
has_many :addresses do
|
193
|
+
declared_model :address
|
194
|
+
end
|
195
|
+
|
196
|
+
def initialize(h)
|
197
|
+
h.each {|k,v| send("#{k}=",v)}
|
198
|
+
end
|
199
|
+
|
200
|
+
def address_initializer
|
201
|
+
{ :address => OpenStruct.new }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
let(:form) do
|
207
|
+
form_class.new(:first_model => model_1, :second_model => model_2)
|
208
|
+
end
|
209
|
+
|
210
|
+
context "without nested models" do
|
211
|
+
it "returns array of models " do
|
212
|
+
form.models.should eq([model_1, model_2])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context "without nested models" do
|
217
|
+
before(:each) do
|
218
|
+
form.build_address(:address => address_1)
|
219
|
+
form.build_address(:address => address_2)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "returns array of models" do
|
223
|
+
form.models.should be_a(Array)
|
224
|
+
end
|
225
|
+
|
226
|
+
it "has model_1 as its first model" do
|
227
|
+
form.models[0].should eq(model_1)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "has model_2 as its second model" do
|
231
|
+
form.models[1].should eq(model_2)
|
232
|
+
end
|
233
|
+
|
234
|
+
it "has nested model form for address_1 as its third model" do
|
235
|
+
form.models[2].address.should eq(address_1)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "has nested model form for address_2 as its fourth model" do
|
239
|
+
form.models[3].address.should eq(address_2)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|