aurora-geometry 0.0.2

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE +21 -0
  5. data/README.markdown +105 -0
  6. data/Rakefile +24 -0
  7. data/aurora-geometry.gemspec +23 -0
  8. data/lib/geometry.rb +22 -0
  9. data/lib/geometry/arc.rb +94 -0
  10. data/lib/geometry/circle.rb +122 -0
  11. data/lib/geometry/cluster_factory.rb +15 -0
  12. data/lib/geometry/edge.rb +140 -0
  13. data/lib/geometry/line.rb +154 -0
  14. data/lib/geometry/obround.rb +238 -0
  15. data/lib/geometry/path.rb +67 -0
  16. data/lib/geometry/point.rb +163 -0
  17. data/lib/geometry/point_zero.rb +107 -0
  18. data/lib/geometry/polygon.rb +368 -0
  19. data/lib/geometry/polyline.rb +318 -0
  20. data/lib/geometry/rectangle.rb +378 -0
  21. data/lib/geometry/regular_polygon.rb +136 -0
  22. data/lib/geometry/rotation.rb +190 -0
  23. data/lib/geometry/size.rb +75 -0
  24. data/lib/geometry/size_zero.rb +70 -0
  25. data/lib/geometry/square.rb +113 -0
  26. data/lib/geometry/text.rb +24 -0
  27. data/lib/geometry/transformation.rb +171 -0
  28. data/lib/geometry/transformation/composition.rb +39 -0
  29. data/lib/geometry/triangle.rb +78 -0
  30. data/lib/geometry/vector.rb +34 -0
  31. data/test/geometry.rb +5 -0
  32. data/test/geometry/arc.rb +25 -0
  33. data/test/geometry/circle.rb +112 -0
  34. data/test/geometry/edge.rb +132 -0
  35. data/test/geometry/line.rb +132 -0
  36. data/test/geometry/obround.rb +25 -0
  37. data/test/geometry/path.rb +66 -0
  38. data/test/geometry/point.rb +258 -0
  39. data/test/geometry/point_zero.rb +177 -0
  40. data/test/geometry/polygon.rb +214 -0
  41. data/test/geometry/polyline.rb +266 -0
  42. data/test/geometry/rectangle.rb +154 -0
  43. data/test/geometry/regular_polygon.rb +120 -0
  44. data/test/geometry/rotation.rb +108 -0
  45. data/test/geometry/size.rb +97 -0
  46. data/test/geometry/size_zero.rb +153 -0
  47. data/test/geometry/square.rb +66 -0
  48. data/test/geometry/transformation.rb +169 -0
  49. data/test/geometry/transformation/composition.rb +49 -0
  50. data/test/geometry/triangle.rb +32 -0
  51. data/test/geometry/vector.rb +41 -0
  52. metadata +115 -0
@@ -0,0 +1,108 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/rotation'
3
+
4
+ describe Geometry::Rotation do
5
+ Point = Geometry::Point
6
+ Rotation = Geometry::Rotation
7
+ RotationAngle = Geometry::RotationAngle
8
+
9
+ describe "when constructed" do
10
+ it "must accept a rotation angle" do
11
+ rotation = Rotation.new angle:Math::PI/2
12
+ rotation.must_be_instance_of(RotationAngle)
13
+ rotation.angle.must_equal Math::PI/2
14
+ rotation.x.x.must_be_close_to 0
15
+ rotation.x.y.must_be_close_to 1
16
+ rotation.y.x.must_be_close_to -1
17
+ rotation.y.y.must_be_close_to 0
18
+ end
19
+
20
+ it "must accept an X axis" do
21
+ rotation = Rotation.new x:[1,0]
22
+ rotation.must_be_instance_of(RotationAngle)
23
+ rotation.angle.must_equal 0
24
+ rotation.x.must_equal Point[1,0]
25
+ rotation.y.must_equal Point[0,1]
26
+ end
27
+ end
28
+
29
+ it "must accept x and y axes" do
30
+ rotation = Geometry::Rotation.new :x => [1,2,3], :y => [4,5,6]
31
+ rotation.x.must_equal [1,2,3]
32
+ rotation.y.must_equal [4,5,6]
33
+ end
34
+
35
+ it "must accept 3-element x and y axes and a dimensionality of 3" do
36
+ rotation = Geometry::Rotation.new(:dimensions => 3, :x => [1,2,3], :y => [4,5,6])
37
+ rotation.dimensions.must_equal 3
38
+ end
39
+
40
+ it "must reject 3-element x and y axes and a dimensionality of 2" do
41
+ lambda { Geometry::Rotation.new(:dimensions => 2, :x => [1,2,3], :y => [4,5,6]) }.must_raise ArgumentError
42
+ end
43
+
44
+ it "must promote 2-element Vectors to dimensionality of 3" do
45
+ rotation = Geometry::Rotation.new(:dimensions => 3, :x => [1,2], :y => [4,5])
46
+ rotation.dimensions.must_equal 3
47
+ rotation.x.must_equal [1,2,0]
48
+ rotation.y.must_equal [4,5,0]
49
+ end
50
+
51
+ it "must be the identity rotation if no axes are given" do
52
+ Geometry::Rotation.new.identity?.must_equal true
53
+ Geometry::Rotation.new(:dimensions => 3).identity?.must_equal true
54
+ end
55
+
56
+ it "must be the identity rotation when identity axes are given" do
57
+ Geometry::Rotation.new(:x => [1,0,0], :y => [0,1,0])
58
+ end
59
+
60
+ it "must have a matrix accessor" do
61
+ r = Geometry::Rotation.new(:x => [1,0,0], :y => [0,1,0])
62
+ r.matrix.must_equal Matrix[[1,0,0],[0,1,0],[0,0,1]]
63
+ end
64
+
65
+ describe "when comparing" do
66
+ it "must equate equal objects" do
67
+ Rotation.new(x:[1,2,3], y:[4,5,6]).must_equal Rotation.new(x:[1,2,3], y:[4,5,6])
68
+ end
69
+ end
70
+
71
+ describe "comparison" do
72
+ it "must equate equal angles" do
73
+ Rotation.new(angle:45).must_equal Rotation.new(angle:45)
74
+ end
75
+
76
+ it "must not equate unequal angles" do
77
+ Rotation.new(angle:10).wont_equal Rotation.new(angle:45)
78
+ end
79
+ end
80
+
81
+ describe "composition" do
82
+ it "must add angles" do
83
+ (Rotation.new(angle:45) + Rotation.new(angle:45)).must_equal Rotation.new(angle:90)
84
+ end
85
+
86
+ it "must subtract angles" do
87
+ (Rotation.new(angle:45) - Rotation.new(angle:45)).must_equal Rotation.new(angle:0)
88
+ end
89
+
90
+ it "must negate angles" do
91
+ (-Rotation.new(angle:45)).must_equal Rotation.new(angle:-45)
92
+ end
93
+ end
94
+
95
+ describe "when transforming a Point" do
96
+ describe "when no rotation is set" do
97
+ it "must return the Point" do
98
+ Rotation.new.transform(Point[1,0]).must_equal Point[1,0]
99
+ end
100
+ end
101
+
102
+ it "must rotate" do
103
+ rotated_point = Rotation.new(angle:Math::PI/2).transform(Point[1,0])
104
+ rotated_point.x.must_be_close_to 0
105
+ rotated_point.y.must_be_close_to 1
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,97 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/size'
3
+
4
+ describe Geometry::Size do
5
+ describe "when constructed" do
6
+ it "create a Size object using list syntax" do
7
+ size = Geometry::Size[2,1]
8
+ assert_equal(2, size.size)
9
+ assert_equal(2, size.x)
10
+ assert_equal(1, size.y)
11
+ end
12
+
13
+ it "create a Size object from an array" do
14
+ size = Geometry::Size[[3,4]]
15
+ assert_equal(2, size.size)
16
+ assert_equal(3, size.x)
17
+ assert_equal(4, size.y)
18
+ end
19
+
20
+ it "create a Size object from individual parameters" do
21
+ size = Geometry::Size[3,4]
22
+ assert_equal(2, size.size)
23
+ assert_equal(3, size.x)
24
+ assert_equal(4, size.y)
25
+ end
26
+
27
+ it "create a Size object from a Size" do
28
+ size = Geometry::Size[Geometry::Size[3,4]]
29
+ assert_equal(2, size.size)
30
+ assert_equal(3, size.x)
31
+ assert_equal(4, size.y)
32
+ end
33
+
34
+ it "create a Size object from a Vector" do
35
+ size = Geometry::Size[Vector[3,4]]
36
+ assert_equal(2, size.size)
37
+ assert_equal(3, size.x)
38
+ assert_equal(4, size.y)
39
+ end
40
+ end
41
+
42
+ it "allow indexed element access" do
43
+ size = Geometry::Size[5,6]
44
+ assert_equal(2, size.size)
45
+ assert_equal(5, size[0])
46
+ assert_equal(6, size[1])
47
+ end
48
+ it "allow named element access" do
49
+ size = Geometry::Size[5,6,7]
50
+ assert_equal(3, size.size)
51
+ assert_equal(5, size.x)
52
+ assert_equal(6, size.y)
53
+ assert_equal(7, size.z)
54
+ end
55
+
56
+ it "have a width accessor" do
57
+ size = Geometry::Size[5,6,7]
58
+ assert_equal(5, size.width)
59
+ end
60
+
61
+ it "have a height accessor" do
62
+ size = Geometry::Size[5,6,7]
63
+ assert_equal(6, size.height)
64
+ end
65
+
66
+ it "have a depth accessor" do
67
+ size = Geometry::Size[5,6,7]
68
+ assert_equal(7, size.depth)
69
+ end
70
+
71
+ it "compare equal" do
72
+ size1 = Geometry::Size[1,2]
73
+ size2 = Geometry::Size[1,2]
74
+ size3 = Geometry::Size[3,4]
75
+ assert_equal(size1, size2)
76
+ size2.wont_equal size3
77
+ end
78
+
79
+ it "compare equal to an array with equal elements" do
80
+ size1 = Size[1,2]
81
+ assert_equal(size1, [1,2])
82
+ end
83
+
84
+ it "not compare equal to an array with unequal elements" do
85
+ size1 = Size[1,2]
86
+ size1.wont_equal [3,2]
87
+ end
88
+
89
+ it "implement inspect" do
90
+ size = Geometry::Size[8,9]
91
+ assert_equal('Size[8, 9]', size.inspect)
92
+ end
93
+ it "implement to_s" do
94
+ size = Geometry::Size[10,11]
95
+ assert_equal('Size[10, 11]', size.to_s)
96
+ end
97
+ end
@@ -0,0 +1,153 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/size_zero'
3
+
4
+ describe Geometry::SizeZero do
5
+ Size = Geometry::Size
6
+
7
+ let(:zero) { Geometry::SizeZero.new }
8
+
9
+ describe "arithmetic" do
10
+ let(:left) { Size[1,2] }
11
+ let(:right) { Size[3,4] }
12
+
13
+ it "must have +@" do
14
+ (+zero).must_be :eql?, 0
15
+ (+zero).must_be_instance_of(Geometry::SizeZero)
16
+ end
17
+
18
+ it "must have unary negation" do
19
+ (-zero).must_be :eql?, 0
20
+ (-zero).must_be_instance_of(Geometry::SizeZero)
21
+ end
22
+
23
+ describe "when adding" do
24
+ it "must return a number" do
25
+ (zero + 3).must_equal 3
26
+ (3 + zero).must_equal 3
27
+ end
28
+
29
+ it "return a Size when adding two Sizes" do
30
+ (zero + right).must_be_kind_of Size
31
+ # (left + zero).must_be_kind_of Size
32
+ end
33
+
34
+ it "must return a Size when adding an array" do
35
+ (zero + [5,6]).must_equal [5,6]
36
+ # ([5,6] + zero).must_equal [5,6]
37
+ end
38
+ end
39
+
40
+ describe "when subtracting" do
41
+ it "must return a number" do
42
+ (zero - 3).must_equal -3
43
+ (3 - zero).must_equal 3
44
+ end
45
+
46
+ it "return a Size when subtracting two Size" do
47
+ (zero - right).must_equal Size[-3,-4]
48
+ (left - zero).must_equal Size[1,2]
49
+ end
50
+
51
+ it "must return a Size when subtracting an array" do
52
+ (zero - [5,6]).must_equal [-5, -6]
53
+ # ([5,6] - zero).must_equal [5,6]
54
+ end
55
+ end
56
+
57
+ describe "multiplication" do
58
+ it "must return 0 for scalars" do
59
+ (zero * 3).must_equal 0
60
+ (zero * 3.0).must_equal 0.0
61
+ end
62
+
63
+ it "must return 0 for Sizes" do
64
+ (zero * Size[1,2]).must_equal 0
65
+ end
66
+
67
+ it "must return 0 for Vectors" do
68
+ (zero * Vector[2,3]).must_equal 0
69
+ end
70
+ end
71
+
72
+ describe "division" do
73
+ it "must return 0 for non-zero scalars" do
74
+ (zero / 3).must_equal 0
75
+ (zero / 4.0).must_equal 0
76
+ end
77
+
78
+ it "must raise an exception when divided by 0" do
79
+ lambda { zero / 0 }.must_raise ZeroDivisionError
80
+ end
81
+
82
+ it "must raise an exception for Sizes" do
83
+ lambda { zero / Size[1,2] }.must_raise Geometry::OperationNotDefined
84
+ end
85
+
86
+ it "must raise an exception for Vectors" do
87
+ lambda { zero / Vector[1,2] }.must_raise Geometry::OperationNotDefined
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ describe "coercion" do
95
+ it "must coerce Arrays into Sizes" do
96
+ zero.coerce([3,4]).must_equal [Size[3,4], Size[0,0]]
97
+ end
98
+
99
+ it "must coerce Vectors into Vectors" do
100
+ zero.coerce(Vector[3,4]).must_equal [Vector[3,4], Vector[0,0]]
101
+ end
102
+
103
+ it "must coerce Size into Size" do
104
+ zero.coerce(Size[5,6]).must_equal [Size[5,6], Size[0,0]]
105
+ end
106
+ end
107
+
108
+ describe "comparison" do
109
+ let(:zero) { Geometry::PointZero.new }
110
+
111
+ it "must be equal to 0 and 0.0" do
112
+ zero.must_be :eql?, 0
113
+ zero.must_be :eql?, 0.0
114
+ end
115
+
116
+ it "must not be equal to a non-zero number" do
117
+ 1.wont_equal zero
118
+ 3.14.wont_equal zero
119
+ end
120
+
121
+ it "must be equal to an Array of zeros" do
122
+ zero.must_be :==, [0,0]
123
+ zero.must_be :eql?, [0,0]
124
+ [0,0].must_equal zero
125
+ end
126
+
127
+ it "must not be equal to a non-zero Array" do
128
+ zero.wont_equal [3,2]
129
+ [3,2].wont_equal zero
130
+ end
131
+
132
+ it "must be equal to a zero Size" do
133
+ zero.must_be :==, Size[0,0]
134
+ zero.must_be :eql?, Size[0,0]
135
+ Size[0,0].must_equal zero
136
+ end
137
+
138
+ it "must not be equal to a non-zero Size" do
139
+ zero.wont_equal Size[3,2]
140
+ Size[3,2].wont_equal zero
141
+ end
142
+
143
+ it "must be equal to an Vector of zeroes" do
144
+ zero.must_be :eql?, Vector[0,0]
145
+ Vector[0,0].must_equal zero
146
+ end
147
+
148
+ it "must not be equal to a non-zero Vector" do
149
+ zero.wont_equal Vector[3,2]
150
+ Vector[3,2].wont_equal zero
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,66 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/square'
3
+
4
+ describe Geometry::Square do
5
+ Square = Geometry::Square
6
+
7
+ describe "when constructed" do
8
+ it "must create a Square from two Points" do
9
+ square = Square.new from:[1,2], to:[3,4]
10
+ square.must_be_kind_of Geometry::Square
11
+ end
12
+
13
+ it "must reorder swapped points when constructed from two Points" do
14
+ square = Geometry::Square.new from:[3,4], to:[1,2]
15
+ square.must_be_kind_of Geometry::Square
16
+ square.instance_eval('@points[0]').must_equal Point[1,2]
17
+ square.instance_eval('@points[1]').must_equal Point[3,4]
18
+ end
19
+
20
+ it "must accept an origin Point and a size" do
21
+ square = Square.new origin:[1,2], size:5
22
+ square.must_be_kind_of Geometry::Square
23
+ square.origin.must_equal Point[1,2]
24
+ square.height.must_equal 5
25
+ square.width.must_equal 5
26
+ end
27
+ end
28
+
29
+ describe "properties" do
30
+ subject { Square.new from:[2,3], to:[3,4] }
31
+
32
+ it "must have an origin accessor" do
33
+ subject.origin.must_equal Point[2,3]
34
+ end
35
+ end
36
+ end
37
+
38
+ describe Geometry::CenteredSquare do
39
+ describe "when constructed" do
40
+ it "must create a CenteredSquare from a center point and a size" do
41
+ square = Geometry::CenteredSquare.new [2,3], 5
42
+ square.must_be_instance_of Geometry::CenteredSquare
43
+ square.must_be_kind_of Geometry::Square
44
+ end
45
+ end
46
+
47
+ describe "properties" do
48
+ let(:square) { Geometry::CenteredSquare.new [2,3], 4 }
49
+
50
+ it "must have a center property" do
51
+ square.center.must_equal Point[2,3]
52
+ end
53
+
54
+ it "must have a points property" do
55
+ square.points.must_equal [Point[0,1], Point[4,1], Point[4,5], Point[0,5]]
56
+ end
57
+
58
+ it "must have a height property" do
59
+ square.height.must_equal 4
60
+ end
61
+
62
+ it "must have a width property" do
63
+ square.width.must_equal 4
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,169 @@
1
+ require 'minitest/autorun'
2
+ require 'geometry/point'
3
+ require 'geometry/transformation'
4
+
5
+ describe Geometry::Transformation do
6
+ Transformation = Geometry::Transformation
7
+
8
+ describe "when constructed" do
9
+ it "must accept nothing and become an identity transformation" do
10
+ Transformation.new.identity?.must_equal true
11
+ end
12
+
13
+ it "must accept a translate parameter" do
14
+ Transformation.new([4,2]).translation.must_equal Point[4,2]
15
+ end
16
+
17
+ it "must accept a translate Array" do
18
+ translate = Transformation.new(:translate => [4,2])
19
+ translate.translation.must_equal Point[4,2]
20
+ end
21
+
22
+ it "must accept a translate Point" do
23
+ translate = Transformation.new(:translate => Point[4,2])
24
+ translate.translation.must_equal Point[4,2]
25
+ end
26
+
27
+ it "must accept a translate Point equal to zero" do
28
+ translate = Transformation.new(:translate => [0,0])
29
+ translate.translation.must_equal nil
30
+ end
31
+
32
+ it "must accept a translate Vector" do
33
+ translate = Transformation.new(:translate => Vector[4,2])
34
+ translate.translation.must_equal Point[4,2]
35
+ end
36
+
37
+ it "must accept an origin option" do
38
+ translate = Transformation.new(:origin => [4,2])
39
+ translate.translation.must_equal Point[4,2]
40
+ end
41
+
42
+ it "must raise an exception when given too many translation options" do
43
+ lambda { Transformation.new :translate => [1,2], :origin => [3,4] }.must_raise ArgumentError
44
+ end
45
+
46
+ describe "when given a dimensions option" do
47
+ it "must raise an exception if the other arguments are too big" do
48
+ lambda { Transformation.new :dimensions => 2, :origin => [1,2,3] }.must_raise ArgumentError
49
+ end
50
+
51
+ it "must raise an exception if the other arguments are too small" do
52
+ lambda { Transformation.new :dimensions => 3, :origin => [1,2] }.must_raise ArgumentError
53
+ end
54
+
55
+ it "must not complain when given only a dimensions option" do
56
+ Transformation.new(:dimensions => 3).dimensions.must_equal 3
57
+ end
58
+ end
59
+
60
+ describe "rotation" do
61
+ it "must accept a y axis option" do
62
+ t = Transformation.new :y => [1,0]
63
+ t.rotation.y.must_equal [1,0]
64
+ t.identity?.wont_equal true
65
+ end
66
+
67
+ it "must accept a rotation angle" do
68
+ transformation = Transformation.new angle:90
69
+ transformation.identity?.wont_equal true
70
+ transformation.rotation.wont_be_nil
71
+ transformation.rotation.angle.must_equal 90
72
+ end
73
+
74
+ it "must accept a rotation angle specified by an X-axis" do
75
+ transformation = Transformation.new x:[0,1]
76
+ rotation = transformation.rotation
77
+ rotation.must_be_instance_of(RotationAngle)
78
+ rotation.angle.must_equal Math::PI/2
79
+ rotation.x.x.must_be_close_to 0
80
+ rotation.x.y.must_be_close_to 1
81
+ rotation.y.x.must_be_close_to -1
82
+ rotation.y.y.must_be_close_to 0
83
+ end
84
+ end
85
+ end
86
+
87
+ describe "comparison" do
88
+ subject { Transformation.new(origin:[1,2]) }
89
+
90
+ it "must equate equal transformations" do
91
+ subject.must_equal Transformation.new(origin:[1,2])
92
+ end
93
+
94
+ it "must not equal nil" do
95
+ subject.eql?(nil).wont_equal true
96
+ end
97
+
98
+ it "must not equate a translation with a rotation" do
99
+ subject.wont_equal Transformation.new(x:[0,1,0], y:[1,0,0])
100
+ end
101
+
102
+ it "must equate empty transformations" do
103
+ Transformation.new.must_equal Transformation.new
104
+ end
105
+ end
106
+
107
+ describe "attributes" do
108
+ describe "has_rotation?" do
109
+ it "must properly be true" do
110
+ Transformation.new(angle:90).has_rotation?.must_equal true
111
+ end
112
+
113
+ it "must properly be false" do
114
+ Transformation.new.has_rotation?.must_equal false
115
+ end
116
+ end
117
+ end
118
+
119
+ describe "composition" do
120
+ let(:translate_left) { Geometry::Transformation.new origin:[-2,-2] }
121
+ let(:translate_right) { Geometry::Transformation.new origin:[1,1] }
122
+ let(:transformation) { Geometry::Transformation.new }
123
+
124
+ it "must add pure translation" do
125
+ (translate_left + translate_right).must_equal Geometry::Transformation.new origin:[-1,-1]
126
+ end
127
+
128
+ it "must add translation and no translation" do
129
+ (transformation + translate_left).must_equal translate_left
130
+ (translate_left + transformation).must_equal translate_left
131
+ end
132
+
133
+ it "array addition" do
134
+ (transformation + [1,2]).translation.must_equal Point[1,2]
135
+ ((transformation + [1,2]) + [2,3]).translation.must_equal Point[3,5]
136
+ (transformation + [1,2]).rotation.must_be_nil
137
+ end
138
+
139
+ it "must update the translation when an array is subtracted" do
140
+ (transformation - [1,2]).translation.must_equal Point[-1,-2]
141
+ ((transformation - [1,2]) - [2,3]).translation.must_equal Point[-3,-5]
142
+ (transformation - [1,2,3]).rotation.must_be_nil
143
+ end
144
+
145
+ it "must subtract translation and no translation" do
146
+ (transformation - translate_left).must_equal translate_left
147
+ (translate_left - transformation).must_equal translate_left
148
+ end
149
+ end
150
+
151
+ describe "when transforming a Point" do
152
+ describe "when no transformation is set" do
153
+ it "must return the Point" do
154
+ Transformation.new.transform(Point[1,2]).must_equal Point[1,2];
155
+ end
156
+ end
157
+
158
+ it "must translate" do
159
+ Geometry::Transformation.new(origin:[0,1]).transform([1,0]).must_equal Point[1,1]
160
+ end
161
+
162
+ it "must rotate" do
163
+ rotated_point = Transformation.new(angle:Math::PI/2).transform([1,0])
164
+ rotated_point.x.must_be_close_to 0
165
+ rotated_point.y.must_be_close_to 1
166
+ end
167
+
168
+ end
169
+ end