openxml-docx 0.8.0 → 0.9.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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/{example → examples/base} +1 -1
  4. data/examples/table +68 -0
  5. data/lib/openxml/docx/elements/grid_column.rb +12 -0
  6. data/lib/openxml/docx/elements/table.rb +30 -0
  7. data/lib/openxml/docx/elements/table_cell.rb +26 -0
  8. data/lib/openxml/docx/elements/table_grid.rb +10 -0
  9. data/lib/openxml/docx/elements/table_row.rb +36 -0
  10. data/lib/openxml/docx/package.rb +3 -0
  11. data/lib/openxml/docx/properties.rb +2 -0
  12. data/lib/openxml/docx/properties/base_property.rb +14 -0
  13. data/lib/openxml/docx/properties/cant_split.rb +8 -0
  14. data/lib/openxml/docx/properties/columns.rb +2 -0
  15. data/lib/openxml/docx/properties/grid_after.rb +8 -0
  16. data/lib/openxml/docx/properties/grid_before.rb +8 -0
  17. data/lib/openxml/docx/properties/grid_span.rb +8 -0
  18. data/lib/openxml/docx/properties/header.rb +8 -0
  19. data/lib/openxml/docx/properties/headers.rb +12 -0
  20. data/lib/openxml/docx/properties/hidden.rb +8 -0
  21. data/lib/openxml/docx/properties/hide_mark.rb +8 -0
  22. data/lib/openxml/docx/properties/no_wrap.rb +8 -0
  23. data/lib/openxml/docx/properties/table_border.rb +25 -0
  24. data/lib/openxml/docx/properties/table_borders.rb +13 -0
  25. data/lib/openxml/docx/properties/table_caption.rb +10 -0
  26. data/lib/openxml/docx/properties/table_cell_border.rb +25 -0
  27. data/lib/openxml/docx/properties/table_cell_borders.rb +13 -0
  28. data/lib/openxml/docx/properties/table_cell_cell_margin.rb +13 -0
  29. data/lib/openxml/docx/properties/table_cell_fit_text.rb +9 -0
  30. data/lib/openxml/docx/properties/table_cell_margin.rb +13 -0
  31. data/lib/openxml/docx/properties/table_cell_margins.rb +13 -0
  32. data/lib/openxml/docx/properties/table_cell_spacing.rb +13 -0
  33. data/lib/openxml/docx/properties/table_cell_width.rb +13 -0
  34. data/lib/openxml/docx/properties/table_description.rb +10 -0
  35. data/lib/openxml/docx/properties/table_header.rb +10 -0
  36. data/lib/openxml/docx/properties/table_indent.rb +13 -0
  37. data/lib/openxml/docx/properties/table_layout.rb +14 -0
  38. data/lib/openxml/docx/properties/table_look.rb +17 -0
  39. data/lib/openxml/docx/properties/table_overlap.rb +14 -0
  40. data/lib/openxml/docx/properties/table_p_pr.rb +41 -0
  41. data/lib/openxml/docx/properties/table_style.rb +10 -0
  42. data/lib/openxml/docx/properties/table_width.rb +13 -0
  43. data/lib/openxml/docx/properties/tr_height.rb +19 -0
  44. data/lib/openxml/docx/properties/valign.rb +13 -0
  45. data/lib/openxml/docx/properties/wafter.rb +12 -0
  46. data/lib/openxml/docx/properties/wbefore.rb +12 -0
  47. data/lib/openxml/docx/properties/width_property.rb +17 -0
  48. data/lib/openxml/docx/style.rb +17 -7
  49. data/lib/openxml/docx/version.rb +1 -1
  50. data/spec/elements/grid_column_spec.rb +15 -0
  51. data/spec/elements/table_cell_spec.rb +15 -0
  52. data/spec/elements/table_grid_spec.rb +17 -0
  53. data/spec/elements/table_row_spec.rb +18 -0
  54. data/spec/elements/table_spec.rb +21 -0
  55. data/spec/properties/border_spec.rb +21 -95
  56. data/spec/properties/cant_split_spec.rb +23 -0
  57. data/spec/properties/color_spec.rb +9 -29
  58. data/spec/properties/column_spec.rb +6 -22
  59. data/spec/properties/columns_spec.rb +4 -14
  60. data/spec/properties/conditional_formatting_spec.rb +12 -108
  61. data/spec/properties/document_grid_spec.rb +12 -53
  62. data/spec/properties/east_asian_layout_spec.rb +14 -74
  63. data/spec/properties/font_spec.rb +35 -238
  64. data/spec/properties/frame_spec.rb +48 -285
  65. data/spec/properties/grid_after_spec.rb +26 -0
  66. data/spec/properties/grid_before_spec.rb +26 -0
  67. data/spec/properties/grid_span_spec.rb +24 -0
  68. data/spec/properties/header_spec.rb +17 -0
  69. data/spec/properties/headers_spec.rb +39 -0
  70. data/spec/properties/hidden_spec.rb +23 -0
  71. data/spec/properties/hide_mark_spec.rb +23 -0
  72. data/spec/properties/indentation_spec.rb +32 -136
  73. data/spec/properties/language_spec.rb +3 -12
  74. data/spec/properties/latent_styles_exception_spec.rb +7 -22
  75. data/spec/properties/latent_styles_spec.rb +5 -18
  76. data/spec/properties/line_numbering_spec.rb +15 -68
  77. data/spec/properties/manual_width_spec.rb +8 -33
  78. data/spec/properties/no_wrap_spec.rb +23 -0
  79. data/spec/properties/numbering_spec.rb +4 -13
  80. data/spec/properties/page_margins_spec.rb +28 -114
  81. data/spec/properties/page_numbering_spec.rb +26 -367
  82. data/spec/properties/page_size_spec.rb +15 -62
  83. data/spec/properties/paper_source_spec.rb +8 -34
  84. data/spec/properties/shading_spec.rb +21 -92
  85. data/spec/properties/spacing_spec.rb +27 -119
  86. data/spec/properties/table_border_spec.rb +119 -0
  87. data/spec/properties/table_borders_spec.rb +41 -0
  88. data/spec/properties/table_caption_spec.rb +17 -0
  89. data/spec/properties/table_cell_border_spec.rb +119 -0
  90. data/spec/properties/table_cell_borders_spec.rb +40 -0
  91. data/spec/properties/table_cell_cell_margin_spec.rb +46 -0
  92. data/spec/properties/table_cell_fit_text.rb +23 -0
  93. data/spec/properties/table_cell_margin_spec.rb +40 -0
  94. data/spec/properties/table_cell_margins_spec.rb +46 -0
  95. data/spec/properties/table_cell_spacing_spec.rb +21 -0
  96. data/spec/properties/table_cell_width.rb +21 -0
  97. data/spec/properties/table_description_spec.rb +17 -0
  98. data/spec/properties/table_header_spec.rb +23 -0
  99. data/spec/properties/table_indent_spec.rb +43 -0
  100. data/spec/properties/table_layout_spec.rb +22 -0
  101. data/spec/properties/table_look_spec.rb +38 -0
  102. data/spec/properties/table_overlap_spec.rb +22 -0
  103. data/spec/properties/table_p_pr_spec.rb +68 -0
  104. data/spec/properties/table_row_height.rb +20 -0
  105. data/spec/properties/table_style_spec.rb +17 -0
  106. data/spec/properties/table_width_spec.rb +21 -0
  107. data/spec/properties/underline_spec.rb +14 -130
  108. data/spec/properties/valign_spec.rb +19 -0
  109. data/spec/properties/wafter_spec.rb +21 -0
  110. data/spec/properties/wbefore_spec.rb +21 -0
  111. data/spec/support/data/elements/grid_column_element.xml +4 -0
  112. data/spec/support/data/elements/table_cell_element.xml +8 -0
  113. data/spec/support/data/elements/table_element.xml +18 -0
  114. data/spec/support/data/elements/table_grid_element.xml +6 -0
  115. data/spec/support/data/elements/table_row_element.xml +13 -0
  116. data/spec/support/property_test_macros.rb +61 -0
  117. metadata +86 -3
@@ -0,0 +1,119 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableBorder do
4
+ include PropertyTestMacros
5
+
6
+ context "always" do
7
+ before(:each) do
8
+ @instance = described_class.new(:bottom, :babyPacifier)
9
+ end
10
+
11
+ it "should have the right name" do
12
+ expect(instance.name).to eq("table_border")
13
+ end
14
+
15
+ it "should have its tag be equal to the argument passed on initialize" do
16
+ expect(instance.tag).to eq(:bottom)
17
+ end
18
+ end
19
+
20
+ for_attribute(:color) do
21
+ with_value("4F81BD") do
22
+ it_should_assign_successfully :bottom, :babyPacifier
23
+ it_should_output "<w:bottom w:color=\"4F81BD\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
24
+ end
25
+
26
+ with_value(:auto) do
27
+ it_should_assign_successfully :bottom, :babyPacifier
28
+ it_should_output "<w:bottom w:color=\"auto\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
29
+ end
30
+
31
+ it_should_not_allow_invalid_value
32
+ end
33
+
34
+ for_attribute(:frame) do
35
+ with_value(true) do
36
+ it_should_assign_successfully :bottom, :babyPacifier
37
+ it_should_output "<w:bottom w:frame=\"true\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
38
+ end
39
+
40
+ with_value(false) do
41
+ it_should_assign_successfully :bottom, :babyPacifier
42
+ it_should_output "<w:bottom w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
43
+ end
44
+
45
+ it_should_not_allow_invalid_value
46
+ end
47
+
48
+ for_attribute(:shadow) do
49
+ with_value(true) do
50
+ it_should_assign_successfully :bottom, :babyPacifier
51
+ it_should_output "<w:bottom w:shadow=\"true\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
52
+ end
53
+
54
+ with_value(false) do
55
+ it_should_assign_successfully :bottom, :babyPacifier
56
+ it_should_output "<w:bottom w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
57
+ end
58
+
59
+ it_should_not_allow_invalid_value
60
+ end
61
+
62
+ for_attribute(:width) do
63
+ with_value(24) do
64
+ it_should_assign_successfully :bottom, :babyPacifier
65
+ it_should_output "<w:bottom w:val=\"babyPacifier\" w:sz=\"24\"/>", :bottom, :babyPacifier
66
+ end
67
+
68
+ it_should_not_allow_negative_numbers
69
+ it_should_not_allow_invalid_value
70
+ end
71
+
72
+ for_attribute(:space) do
73
+ with_value(24) do
74
+ it_should_assign_successfully :bottom, :babyPacifier
75
+ it_should_output "<w:bottom w:space=\"24\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
76
+ end
77
+
78
+ it_should_not_allow_negative_numbers
79
+ it_should_not_allow_invalid_value
80
+ end
81
+
82
+ for_attribute(:theme_color) do
83
+ with_value(:hyperlink) do
84
+ it_should_assign_successfully :bottom, :babyPacifier
85
+ it_should_output "<w:bottom w:themeColor=\"hyperlink\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
86
+ end
87
+
88
+ it_should_not_allow_invalid_value
89
+ end
90
+
91
+ for_attribute(:theme_shade) do
92
+ with_value("BF") do
93
+ it_should_assign_successfully :bottom, :babyPacifier
94
+ it_should_output "<w:bottom w:themeShade=\"BF\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
95
+ end
96
+
97
+ it_should_not_allow_invalid_value
98
+ end
99
+
100
+ for_attribute(:theme_tint) do
101
+ with_value("BF") do
102
+ it_should_assign_successfully :bottom, :babyPacifier
103
+ it_should_output "<w:bottom w:themeTint=\"BF\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
104
+ end
105
+
106
+ it_should_not_allow_invalid_value
107
+ end
108
+
109
+ for_attribute(:value) do
110
+ with_value(:single) do
111
+ it_should_assign_successfully :bottom, :babyPacifier
112
+ it_should_output "<w:bottom w:val=\"single\"/>", :bottom, :babyPacifier
113
+ end
114
+
115
+ it_should_not_allow_invalid_value
116
+ end
117
+
118
+
119
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableBorders do
4
+ include PropertyTestMacros
5
+
6
+ it_should_use tag: :tblBorders, name: "table_borders"
7
+
8
+ context "when trying to add borders, it" do
9
+ before(:each) do
10
+ @instance = described_class.new
11
+ end
12
+
13
+ it "should raise an exception if the border to be added isn't a border at all" do
14
+ expect { instance << [] }.to raise_error(ArgumentError)
15
+ end
16
+ end
17
+
18
+ context "when there are no borders" do
19
+ before(:each) do
20
+ @instance = described_class.new
21
+ end
22
+
23
+ it "should not output any XML" do
24
+ expect(xml(instance)).to eq("")
25
+ end
26
+ end
27
+
28
+ context "when there are borders" do
29
+ before(:each) do
30
+ @instance = described_class.new
31
+ instance << OpenXml::Docx::Properties::TableBorder.new(:start, :babyPacifier)
32
+ instance << OpenXml::Docx::Properties::TableBorder.new(:end, :babyPacifier)
33
+ end
34
+
35
+ it "should output the correct XML" do
36
+ expect(xml(instance)).to eq("<w:tblBorders>\n <w:start w:val=\"babyPacifier\"/>\n <w:end w:val=\"babyPacifier\"/>\n </w:tblBorders>")
37
+ end
38
+ end
39
+
40
+ end
41
+
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableCaption do
4
+ include ValuePropertyTestMacros
5
+
6
+ it_should_use tag: :tblCaption, name: "table_caption", value: "Something"
7
+
8
+ with_value("Something Else") do
9
+ it_should_work
10
+ it_should_output "<w:tblCaption w:val=\"Something Else\"/>"
11
+ end
12
+
13
+ with_value("") do
14
+ it_should_not_work
15
+ end
16
+
17
+ end
@@ -0,0 +1,119 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableCellBorder do
4
+ include PropertyTestMacros
5
+
6
+ context "always" do
7
+ before(:each) do
8
+ @instance = described_class.new(:bottom, :babyPacifier)
9
+ end
10
+
11
+ it "should have the right name" do
12
+ expect(instance.name).to eq("table_cell_border")
13
+ end
14
+
15
+ it "should have its tag be equal to the argument passed on initialize" do
16
+ expect(instance.tag).to eq(:bottom)
17
+ end
18
+ end
19
+
20
+ for_attribute(:color) do
21
+ with_value("4F81BD") do
22
+ it_should_assign_successfully :bottom, :babyPacifier
23
+ it_should_output "<w:bottom w:color=\"4F81BD\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
24
+ end
25
+
26
+ with_value(:auto) do
27
+ it_should_assign_successfully :bottom, :babyPacifier
28
+ it_should_output "<w:bottom w:color=\"auto\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
29
+ end
30
+
31
+ it_should_not_allow_invalid_value
32
+ end
33
+
34
+ for_attribute(:frame) do
35
+ with_value(true) do
36
+ it_should_assign_successfully :bottom, :babyPacifier
37
+ it_should_output "<w:bottom w:frame=\"true\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
38
+ end
39
+
40
+ with_value(false) do
41
+ it_should_assign_successfully :bottom, :babyPacifier
42
+ it_should_output "<w:bottom w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
43
+ end
44
+
45
+ it_should_not_allow_invalid_value
46
+ end
47
+
48
+ for_attribute(:shadow) do
49
+ with_value(true) do
50
+ it_should_assign_successfully :bottom, :babyPacifier
51
+ it_should_output "<w:bottom w:shadow=\"true\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
52
+ end
53
+
54
+ with_value(false) do
55
+ it_should_assign_successfully :bottom, :babyPacifier
56
+ it_should_output "<w:bottom w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
57
+ end
58
+
59
+ it_should_not_allow_invalid_value
60
+ end
61
+
62
+ for_attribute(:width) do
63
+ with_value(24) do
64
+ it_should_assign_successfully :bottom, :babyPacifier
65
+ it_should_output "<w:bottom w:val=\"babyPacifier\" w:sz=\"24\"/>", :bottom, :babyPacifier
66
+ end
67
+
68
+ it_should_not_allow_negative_numbers
69
+ it_should_not_allow_invalid_value
70
+ end
71
+
72
+ for_attribute(:space) do
73
+ with_value(24) do
74
+ it_should_assign_successfully :bottom, :babyPacifier
75
+ it_should_output "<w:bottom w:space=\"24\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
76
+ end
77
+
78
+ it_should_not_allow_negative_numbers
79
+ it_should_not_allow_invalid_value
80
+ end
81
+
82
+ for_attribute(:theme_color) do
83
+ with_value(:hyperlink) do
84
+ it_should_assign_successfully :bottom, :babyPacifier
85
+ it_should_output "<w:bottom w:themeColor=\"hyperlink\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
86
+ end
87
+
88
+ it_should_not_allow_invalid_value
89
+ end
90
+
91
+ for_attribute(:theme_shade) do
92
+ with_value("BF") do
93
+ it_should_assign_successfully :bottom, :babyPacifier
94
+ it_should_output "<w:bottom w:themeShade=\"BF\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
95
+ end
96
+
97
+ it_should_not_allow_invalid_value
98
+ end
99
+
100
+ for_attribute(:theme_tint) do
101
+ with_value("BF") do
102
+ it_should_assign_successfully :bottom, :babyPacifier
103
+ it_should_output "<w:bottom w:themeTint=\"BF\" w:val=\"babyPacifier\"/>", :bottom, :babyPacifier
104
+ end
105
+
106
+ it_should_not_allow_invalid_value
107
+ end
108
+
109
+ for_attribute(:value) do
110
+ with_value(:single) do
111
+ it_should_assign_successfully :bottom, :babyPacifier
112
+ it_should_output "<w:bottom w:val=\"single\"/>", :bottom, :babyPacifier
113
+ end
114
+
115
+ it_should_not_allow_invalid_value
116
+ end
117
+
118
+
119
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableCellBorders do
4
+ include PropertyTestMacros
5
+
6
+ it_should_use tag: :tcBorders, name: "table_cell_borders"
7
+
8
+ context "when trying to add cell borders, it" do
9
+ before(:each) do
10
+ @instance = described_class.new
11
+ end
12
+
13
+ it "should raise an exception if the cell border to be added isn't a cell border at all" do
14
+ expect { instance << [] }.to raise_error(ArgumentError)
15
+ end
16
+ end
17
+
18
+ context "when there are no cell borders" do
19
+ before(:each) do
20
+ @instance = described_class.new
21
+ end
22
+
23
+ it "should not output any XML" do
24
+ expect(xml(instance)).to eq("")
25
+ end
26
+ end
27
+
28
+ context "when there are borders" do
29
+ before(:each) do
30
+ @instance = described_class.new
31
+ instance << OpenXml::Docx::Properties::TableCellBorder.new(:start, :babyPacifier)
32
+ instance << OpenXml::Docx::Properties::TableCellBorder.new(:end, :babyPacifier)
33
+ end
34
+
35
+ it "should output the correct XML" do
36
+ expect(xml(instance)).to eq("<w:tcBorders>\n <w:start w:val=\"babyPacifier\"/>\n <w:end w:val=\"babyPacifier\"/>\n </w:tcBorders>")
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableCellCellMargin do
4
+ include PropertyTestMacros
5
+
6
+ it_should_use tag: :tcMar, name: "table_cell_cell_margin"
7
+
8
+ context "when trying to add table cell margins, it" do
9
+ before(:each) do
10
+ @instance = described_class.new
11
+ end
12
+
13
+ it "should raise an exception if the margin to be added isn't a margin at all" do
14
+ expect { instance << [] }.to raise_error(ArgumentError)
15
+ end
16
+ end
17
+
18
+ context "when there are no margins" do
19
+ before(:each) do
20
+ @instance = described_class.new
21
+ end
22
+
23
+ it "should not output any XML" do
24
+ expect(xml(instance)).to eq("")
25
+ end
26
+ end
27
+
28
+ context "when there are margins" do
29
+ before(:each) do
30
+ @instance = described_class.new
31
+ start_margin = OpenXml::Docx::Properties::TableCellMargin.new(:start)
32
+ end_margin = OpenXml::Docx::Properties::TableCellMargin.new(:end)
33
+ start_margin.type = :dxa
34
+ start_margin.width = 1
35
+ end_margin.type = :dxa
36
+ end_margin.width = 1
37
+ instance << start_margin
38
+ instance << end_margin
39
+ end
40
+
41
+ it "should output the correct XML" do
42
+ expect(xml(instance)).to eq("<w:tcMar>\n <w:start w:type=\"dxa\" w:w=\"1\"/>\n <w:end w:type=\"dxa\" w:w=\"1\"/>\n </w:tcMar>")
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableCellFitText do
4
+ include ValuePropertyTestMacros
5
+
6
+ it_should_use tag: :tcFitText, name: "table_cell_fit_text"
7
+
8
+ with_value(true) do
9
+ it_should_work
10
+ it_should_output "<w:tcFitText w:val=\"true\"/>"
11
+ end
12
+
13
+ with_value(false) do
14
+ it_should_work
15
+ it_should_output ""
16
+ end
17
+
18
+ with_value(nil) do
19
+ it_should_work
20
+ it_should_output ""
21
+ end
22
+
23
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe OpenXml::Docx::Properties::TableCellMargin do
4
+ include PropertyTestMacros
5
+
6
+ context "with an invalid tag provided" do
7
+ it "should raise an exception" do
8
+ expect do
9
+ described_class.new :overthetop
10
+ end.to raise_error(ArgumentError)
11
+ end
12
+ end
13
+
14
+ for_attribute(:type) do
15
+ with_value(:dxa) do
16
+ it_should_assign_successfully :bottom
17
+ it_should_output "<w:bottom w:type=\"dxa\"/>", :bottom
18
+ end
19
+
20
+ with_value(:pct) do
21
+ it_should_assign_successfully :bottom
22
+ it_should_output "<w:bottom w:type=\"pct\"/>", :bottom
23
+ end
24
+
25
+ it_should_not_allow_invalid_value
26
+ it_should_not_allow_integers
27
+ end
28
+
29
+ for_attribute(:width) do
30
+ with_value(2) do
31
+ it_should_assign_successfully :bottom
32
+ it_should_output "<w:bottom w:w=\"2\"/>", :bottom
33
+ end
34
+
35
+ it_should_not_allow_negative_numbers
36
+ it_should_not_allow_floats
37
+ it_should_not_allow_invalid_value
38
+ end
39
+
40
+ end