erubis 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. data/ChangeLog +150 -2
  2. data/LGPL +504 -0
  3. data/README.txt +14 -8
  4. data/benchmark/erubybench.rb +1 -1
  5. data/benchmark/erubybench.rhtml +3 -3
  6. data/bin/erubis +1 -1
  7. data/bin/notext +154 -0
  8. data/contrib/erubis +1036 -374
  9. data/contrib/inline-require +5 -3
  10. data/doc-api/classes/Erubis.html +43 -1
  11. data/doc-api/classes/Erubis/ArrayBufferEnhancer.html +14 -14
  12. data/doc-api/classes/Erubis/ArrayEnhancer.html +14 -14
  13. data/doc-api/classes/Erubis/Basic.html +112 -0
  14. data/doc-api/classes/Erubis/Basic/Converter.html +318 -0
  15. data/doc-api/classes/Erubis/Basic/Engine.html +130 -0
  16. data/doc-api/classes/Erubis/BiPatternEnhancer.html +14 -14
  17. data/doc-api/classes/Erubis/CGenerator.html +386 -0
  18. data/doc-api/classes/Erubis/Context.html +31 -32
  19. data/doc-api/classes/Erubis/Converter.html +231 -0
  20. data/doc-api/classes/Erubis/Ec.html +9 -283
  21. data/doc-api/classes/Erubis/Ejava.html +9 -274
  22. data/doc-api/classes/Erubis/Ejavascript.html +9 -298
  23. data/doc-api/classes/Erubis/Engine.html +68 -508
  24. data/doc-api/classes/Erubis/Eperl.html +9 -259
  25. data/doc-api/classes/Erubis/Ephp.html +9 -239
  26. data/doc-api/classes/Erubis/ErubisError.html +2 -2
  27. data/doc-api/classes/Erubis/Eruby.html +4 -187
  28. data/doc-api/classes/Erubis/EscapeEnhancer.html +9 -11
  29. data/doc-api/classes/Erubis/Escheme.html +9 -272
  30. data/doc-api/classes/Erubis/Evaluator.html +212 -0
  31. data/doc-api/classes/Erubis/Generator.html +410 -0
  32. data/doc-api/classes/Erubis/HeaderFooterEnhancer.html +16 -16
  33. data/doc-api/classes/Erubis/Helper.html +112 -0
  34. data/doc-api/classes/Erubis/Helper/CachedRailsTemplate.html +198 -0
  35. data/doc-api/classes/Erubis/Helper/RailsTemplate.html +366 -0
  36. data/doc-api/classes/Erubis/JavaGenerator.html +359 -0
  37. data/doc-api/classes/Erubis/JavascriptGenerator.html +381 -0
  38. data/doc-api/classes/Erubis/Main.html +27 -25
  39. data/doc-api/classes/Erubis/NoCodeEnhancer.html +249 -0
  40. data/doc-api/classes/Erubis/NoCodeEruby.html +120 -0
  41. data/doc-api/classes/Erubis/NoTextEnhancer.html +8 -8
  42. data/doc-api/classes/Erubis/NotSupportedError.html +119 -0
  43. data/doc-api/classes/Erubis/OptimizedEruby.html +22 -304
  44. data/doc-api/classes/Erubis/OptimizedGenerator.html +439 -0
  45. data/doc-api/classes/Erubis/OptimizedXmlEruby.html +7 -7
  46. data/doc-api/classes/Erubis/PI.html +124 -0
  47. data/doc-api/classes/Erubis/PI/Converter.html +318 -0
  48. data/doc-api/classes/Erubis/PI/Ec.html +166 -0
  49. data/doc-api/classes/Erubis/PI/Ejava.html +166 -0
  50. data/doc-api/classes/Erubis/PI/Ejavascript.html +166 -0
  51. data/doc-api/classes/Erubis/PI/Engine.html +122 -0
  52. data/doc-api/classes/Erubis/PI/Eperl.html +166 -0
  53. data/doc-api/classes/Erubis/PI/Ephp.html +166 -0
  54. data/doc-api/classes/Erubis/PI/Eruby.html +155 -0
  55. data/doc-api/classes/Erubis/PI/Escheme.html +166 -0
  56. data/doc-api/classes/Erubis/PI/TinyEruby.html +305 -0
  57. data/doc-api/classes/Erubis/PercentLineEnhancer.html +7 -7
  58. data/doc-api/classes/Erubis/PerlGenerator.html +344 -0
  59. data/doc-api/classes/Erubis/PhpGenerator.html +350 -0
  60. data/doc-api/classes/Erubis/PrintEnabledEnhancer.html +24 -24
  61. data/doc-api/classes/Erubis/PrintOutEnhancer.html +35 -35
  62. data/doc-api/classes/Erubis/RubyEvaluator.html +190 -0
  63. data/doc-api/classes/Erubis/RubyGenerator.html +327 -0
  64. data/doc-api/classes/Erubis/SchemeGenerator.html +382 -0
  65. data/doc-api/classes/Erubis/SimplifyEnhancer.html +17 -13
  66. data/doc-api/classes/Erubis/StdoutEnhancer.html +14 -14
  67. data/doc-api/classes/Erubis/StringBufferEnhancer.html +14 -14
  68. data/doc-api/classes/Erubis/TinyEruby.html +45 -40
  69. data/doc-api/classes/Erubis/XmlHelper.html +14 -14
  70. data/doc-api/created.rid +1 -1
  71. data/doc-api/files/__/README_txt.html +27 -9
  72. data/doc-api/files/erubis/context_rb.html +107 -0
  73. data/doc-api/files/erubis/converter_rb.html +114 -0
  74. data/doc-api/files/erubis/engine/ec_rb.html +2 -2
  75. data/doc-api/files/erubis/engine/ejava_rb.html +2 -2
  76. data/doc-api/files/erubis/engine/ejavascript_rb.html +2 -2
  77. data/doc-api/files/erubis/engine/enhanced_rb.html +2 -2
  78. data/doc-api/files/erubis/engine/eperl_rb.html +2 -2
  79. data/doc-api/files/erubis/engine/ephp_rb.html +2 -2
  80. data/doc-api/files/erubis/engine/eruby_rb.html +3 -2
  81. data/doc-api/files/erubis/engine/escheme_rb.html +2 -2
  82. data/doc-api/files/erubis/engine/optimized_rb.html +2 -2
  83. data/doc-api/files/erubis/engine_rb.html +6 -3
  84. data/doc-api/files/erubis/enhancer_rb.html +2 -9
  85. data/doc-api/files/erubis/error_rb.html +107 -0
  86. data/doc-api/files/erubis/evaluator_rb.html +115 -0
  87. data/doc-api/files/erubis/generator_rb.html +114 -0
  88. data/doc-api/files/erubis/helper/rails_rb.html +140 -0
  89. data/doc-api/files/erubis/helper_rb.html +1 -1
  90. data/doc-api/files/erubis/local-setting_rb.html +1 -1
  91. data/doc-api/files/erubis/main_rb.html +2 -2
  92. data/doc-api/files/erubis/tiny_rb.html +2 -2
  93. data/doc-api/files/erubis_rb.html +2 -2
  94. data/doc-api/fr_class_index.html +32 -0
  95. data/doc-api/fr_file_index.html +6 -0
  96. data/doc-api/fr_method_index.html +178 -136
  97. data/doc/users-guide.html +538 -199
  98. data/examples/{Makefile → basic/Makefile} +11 -11
  99. data/examples/basic/example.ec +42 -0
  100. data/examples/{example.ejava → basic/example.ejava} +5 -1
  101. data/examples/{example.ejavascript → basic/example.ejs} +0 -0
  102. data/examples/{example.eperl → basic/example.eperl} +2 -2
  103. data/examples/{example.ephp → basic/example.ephp} +0 -0
  104. data/examples/{example.eruby → basic/example.eruby} +0 -0
  105. data/examples/{example.escheme → basic/example.escheme} +0 -0
  106. data/examples/pi/Makefile +54 -0
  107. data/examples/pi/example.ec +42 -0
  108. data/examples/pi/example.ejava +45 -0
  109. data/examples/pi/example.ejs +16 -0
  110. data/examples/pi/example.eperl +16 -0
  111. data/examples/pi/example.ephp +17 -0
  112. data/examples/pi/example.eruby +15 -0
  113. data/examples/pi/example.escheme +26 -0
  114. data/lib/erubis.rb +15 -8
  115. data/lib/erubis/context.rb +54 -0
  116. data/lib/erubis/converter.rb +307 -0
  117. data/lib/erubis/engine.rb +57 -227
  118. data/lib/erubis/engine/ec.rb +31 -20
  119. data/lib/erubis/engine/ejava.rb +33 -21
  120. data/lib/erubis/engine/ejavascript.rb +30 -18
  121. data/lib/erubis/engine/enhanced.rb +7 -2
  122. data/lib/erubis/engine/eperl.rb +33 -19
  123. data/lib/erubis/engine/ephp.rb +32 -14
  124. data/lib/erubis/engine/eruby.rb +34 -7
  125. data/lib/erubis/engine/escheme.rb +34 -15
  126. data/lib/erubis/engine/optimized.rb +25 -11
  127. data/lib/erubis/enhancer.rb +53 -19
  128. data/lib/erubis/error.rb +24 -0
  129. data/lib/erubis/evaluator.rb +71 -0
  130. data/lib/erubis/generator.rb +83 -0
  131. data/lib/erubis/helper.rb +1 -1
  132. data/lib/erubis/helper/rails.rb +159 -0
  133. data/lib/erubis/local-setting.rb +1 -1
  134. data/lib/erubis/main.rb +87 -46
  135. data/lib/erubis/tiny.rb +81 -7
  136. data/test/assert-text-equal.rb +1 -1
  137. data/test/test-engines.rb +8 -9
  138. data/test/test-erubis.rb +196 -18
  139. data/test/{test-bin.rb → test-main.rb} +123 -21
  140. data/test/test-notext.rb +27 -0
  141. data/test/test.rb +5 -3
  142. data/test/testutil.rb +25 -36
  143. metadata +75 -13
  144. data/COPYING +0 -340
  145. data/examples/example.ec +0 -24
@@ -1,25 +1,32 @@
1
1
  ##
2
- ## $Rev: 21 $
3
- ## $Release: 2.0.1 $
2
+ ## $Rev: 33 $
3
+ ## $Release: 2.1.0 $
4
4
  ## copyright(c) 2006 kuwata-lab all rights reserved.
5
5
  ##
6
6
 
7
7
  require 'erubis/engine'
8
8
  require 'erubis/enhancer'
9
+ require 'abstract'
9
10
 
10
11
 
11
12
  module Erubis
12
13
 
13
14
 
14
15
  ##
15
- ## engine for Ruby
16
+ ## code generator for Ruby
16
17
  ##
17
- class Eruby < Engine
18
+ module RubyGenerator
19
+ include Generator
18
20
  #include StringBufferEnhancer
19
21
  include ArrayBufferEnhancer
20
22
 
23
+ def init_generator(properties={})
24
+ super
25
+ @escapefunc ||= "Erubis::XmlHelper.escape_xml"
26
+ end
27
+
21
28
  def self.supported_properties() # :nodoc:
22
- return super
29
+ return []
23
30
  end
24
31
 
25
32
  def escape_text(text)
@@ -27,8 +34,7 @@ module Erubis
27
34
  end
28
35
 
29
36
  def escaped_expr(code)
30
- @escape ||= "Erubis::XmlHelper.escape_xml"
31
- return "#{@escape}(#{code})"
37
+ return "#{@escapefunc}(#{code})"
32
38
  end
33
39
 
34
40
  #--
@@ -70,6 +76,15 @@ module Erubis
70
76
  end
71
77
 
72
78
 
79
+ ##
80
+ ## engine for Ruby
81
+ ##
82
+ class Eruby < Basic::Engine
83
+ include RubyEvaluator
84
+ include RubyGenerator
85
+ end
86
+
87
+
73
88
  ##
74
89
  ## swtich '<%= %>' to escaped and '<%== %>' to not escaped
75
90
  ##
@@ -88,4 +103,16 @@ module Erubis
88
103
  end
89
104
 
90
105
 
106
+ class PI::Eruby < PI::Engine
107
+ include RubyEvaluator
108
+ include RubyGenerator
109
+
110
+ def init_converter(properties={})
111
+ @pi = 'rb'
112
+ super(properties)
113
+ end
114
+
115
+ end
116
+
117
+
91
118
  end
@@ -1,6 +1,6 @@
1
1
  ##
2
- ## $Rev: 21 $
3
- ## $Release: 2.0.1 $
2
+ ## $Rev: 33 $
3
+ ## $Release: 2.1.0 $
4
4
  ## copyright(c) 2006 kuwata-lab all rights reserved.
5
5
  ##
6
6
 
@@ -11,20 +11,19 @@ require 'erubis/enhancer'
11
11
  module Erubis
12
12
 
13
13
 
14
- ##
15
- ## engine for Scheme
16
- ##
17
- class Escheme < Engine
14
+ module SchemeGenerator
15
+ include Generator
18
16
 
19
17
  def self.supported_properties() # :nodoc:
20
- list = super
21
- list << [:func, '_add', "function name (ex. 'display')"]
22
- return list
18
+ return [
19
+ [:func, '_add', "function name (ex. 'display')"],
20
+ ]
23
21
  end
24
22
 
25
- def initialize(input, properties={})
26
- @func = properties[:func] || '_add' # or 'display'
23
+ def init_generator(properties={})
27
24
  super
25
+ @escapefunc ||= 'escape'
26
+ @func = properties[:func] || '_add' # or 'display'
28
27
  end
29
28
 
30
29
  def add_preamble(src)
@@ -42,8 +41,8 @@ module Erubis
42
41
  end
43
42
 
44
43
  def escaped_expr(code)
45
- @escape ||= 'escape'
46
- return "(#{@escape} #{code.strip})"
44
+ code.strip!
45
+ return "(#{@escapefunc} #{code})"
47
46
  end
48
47
 
49
48
  def add_text(src, text)
@@ -62,11 +61,12 @@ module Erubis
62
61
  end
63
62
 
64
63
  def add_expr_literal(src, code)
65
- src << "(#{@func} " << code.strip << ')'
64
+ code.strip!
65
+ src << "(#{@func} #{code})"
66
66
  end
67
67
 
68
68
  def add_expr_escaped(src, code)
69
- src << "(#{@func} " << escaped_expr(code) << ')'
69
+ add_expr_literal(src, escaped_expr(code))
70
70
  end
71
71
 
72
72
  def add_expr_debug(src, code)
@@ -83,6 +83,14 @@ module Erubis
83
83
  end
84
84
 
85
85
 
86
+ ##
87
+ ## engine for Scheme
88
+ ##
89
+ class Escheme < Basic::Engine
90
+ include SchemeGenerator
91
+ end
92
+
93
+
86
94
  class EscapedEscheme < Escheme
87
95
  include EscapeEnhancer
88
96
  end
@@ -93,4 +101,15 @@ module Erubis
93
101
  #end
94
102
 
95
103
 
104
+ class PI::Escheme < PI::Engine
105
+ include SchemeGenerator
106
+
107
+ def init_converter(properties={})
108
+ @pi = 'scheme'
109
+ super(properties)
110
+ end
111
+
112
+ end
113
+
114
+
96
115
  end
@@ -1,6 +1,6 @@
1
1
  ##
2
- ## $Rev: 21 $
3
- ## $Release: 2.0.1 $
2
+ ## $Rev: 31 $
3
+ ## $Release: 2.1.0 $
4
4
  ## copyright(c) 2006 kuwata-lab all rights reserved.
5
5
  ##
6
6
 
@@ -11,19 +11,18 @@ require 'erubis/engine/eruby'
11
11
  module Erubis
12
12
 
13
13
 
14
- ##
15
- ## Eruby class which generates optimized ruby code
16
- ##
17
- class OptimizedEruby < Engine # Eruby
14
+ module OptimizedGenerator
15
+ include Generator
18
16
 
19
17
  def self.supported_properties() # :nodoc:
20
- return super
18
+ return []
21
19
  end
22
20
 
23
- def initialize(input, properties={})
21
+ def init_generator(properties={})
22
+ super
23
+ @escapefunc ||= "Erubis::XmlHelper.escape_xml"
24
24
  @initialized = false
25
25
  @prev_is_expr = false
26
- super
27
26
  end
28
27
 
29
28
  protected
@@ -33,8 +32,8 @@ module Erubis
33
32
  end
34
33
 
35
34
  def escaped_expr(code)
36
- @escape ||= 'Erubis::XmlHelper.escape_xml'
37
- return "#{@escape}(#{code})"
35
+ @escapefunc ||= 'Erubis::XmlHelper.escape_xml'
36
+ return "#{@escapefunc}(#{code})"
38
37
  end
39
38
 
40
39
  def switch_to_expr(src)
@@ -98,6 +97,21 @@ module Erubis
98
97
  end # end of class OptimizedEruby
99
98
 
100
99
 
100
+ ##
101
+ ## Eruby class which generates optimized ruby code
102
+ ##
103
+ class OptimizedEruby < Basic::Engine # Eruby
104
+ include RubyEvaluator
105
+ include OptimizedGenerator
106
+
107
+ def init_converter(properties={})
108
+ @pi = 'rb'
109
+ super(properties)
110
+ end
111
+
112
+ end
113
+
114
+
101
115
  ##
102
116
  ## XmlEruby class which generates optimized ruby code
103
117
  ##
@@ -1,13 +1,10 @@
1
1
  ##
2
- ## $Rev: 21 $
3
- ## $Release: 2.0.1 $
2
+ ## $Rev: 32 $
3
+ ## $Release: 2.1.0 $
4
4
  ## copyright(c) 2006 kuwata-lab all rights reserved.
5
5
  ##
6
6
 
7
7
 
8
- require 'erubis/engine'
9
-
10
-
11
8
  module Erubis
12
9
 
13
10
 
@@ -41,11 +38,9 @@ module Erubis
41
38
  def add_expr(src, code, indicator)
42
39
  case indicator
43
40
  when '='
44
- add_expr_escaped(src, code)
45
- #add_expr_literal(src, code)
41
+ @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
46
42
  when '=='
47
- add_expr_literal(src, code)
48
- #add_expr_escaped(src, code)
43
+ @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
49
44
  when '==='
50
45
  add_expr_debug(src, code)
51
46
  end
@@ -141,11 +136,11 @@ module Erubis
141
136
  end
142
137
  end
143
138
 
144
- def evaluate(context=Context.new)
139
+ def evaluate(context=nil)
145
140
  _src = @src
146
141
  if context.is_a?(Hash)
147
142
  context.each do |key, val| instance_variable_set("@#{key}", val) end
148
- else
143
+ elsif context
149
144
  context.instance_variables.each do |name|
150
145
  instance_variable_set(name, context.instance_variable_get(name))
151
146
  end
@@ -252,7 +247,7 @@ module Erubis
252
247
  ## remove text and leave code, especially useful when debugging.
253
248
  ##
254
249
  ## ex.
255
- ## $ erubis -s -e NoText file.eruby | more
250
+ ## $ erubis -s -E NoText file.eruby | more
256
251
  ##
257
252
  ## this is language independent.
258
253
  ##
@@ -274,24 +269,63 @@ module Erubis
274
269
 
275
270
 
276
271
  ##
277
- ## get compile faster, but spaces around '<%...%>' are not trimmed.
272
+ ## remove code and leave text, especially useful when validating HTML tags.
273
+ ##
274
+ ## ex.
275
+ ## $ erubis -s -E NoCode file.eruby | tidy -errors
276
+ ##
277
+ ## this is language independent.
278
+ ##
279
+ module NoCodeEnhancer
280
+
281
+ def self.desc # :nodoc:
282
+ "remove code and leave text (useful when validating HTML)"
283
+ end
284
+
285
+ def add_preamble(src)
286
+ end
287
+
288
+ def add_postamble(src)
289
+ end
290
+
291
+ def add_text(src, text)
292
+ src << text
293
+ end
294
+
295
+ def add_expr(src, code, indicator)
296
+ src << "\n" * code.count("\n")
297
+ end
298
+
299
+ def add_stmt(src, code)
300
+ src << "\n" * code.count("\n")
301
+ end
302
+
303
+ end
304
+
305
+
306
+ ##
307
+ ## get convert faster, but spaces around '<%...%>' are not trimmed.
278
308
  ##
279
309
  ## this is language-independent.
280
310
  ##
281
311
  module SimplifyEnhancer
282
312
 
283
313
  def self.desc # :nodoc:
284
- "get compile faster but leave spaces around '<% %>'"
314
+ "get convert faster but leave spaces around '<% %>'"
285
315
  end
286
316
 
287
- #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
288
- SIMPLE_REGEXP = /(.*?)<%(=+|\#)?(.*?)-?%>/m
317
+ #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
318
+ SIMPLE_REGEXP = /<%(=+|\#)?(.*?)-?%>/m
289
319
 
290
- def compile(input)
320
+ def convert(input)
291
321
  src = ""
292
322
  add_preamble(src)
293
323
  #regexp = pattern_regexp(@pattern)
294
- input.scan(SIMPLE_REGEXP) do |text, indicator, code|
324
+ pos = 0
325
+ input.scan(SIMPLE_REGEXP) do |indicator, code|
326
+ index = Regexp.last_match.begin(0)
327
+ text = input[pos, index - pos]
328
+ pos = index + $&.length()
295
329
  add_text(src, text)
296
330
  if !indicator # <% %>
297
331
  add_stmt(src, code)
@@ -476,7 +510,7 @@ module Erubis
476
510
 
477
511
  attr_accessor :header, :footer
478
512
 
479
- def compile(input)
513
+ def convert(input)
480
514
  source = super
481
515
  return @src = "#{@header}#{source}#{@footer}"
482
516
  end
@@ -0,0 +1,24 @@
1
+ ##
2
+ ## $Rev: 32 $
3
+ ## $Release: 2.1.0 $
4
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
5
+ ##
6
+
7
+ module Erubis
8
+
9
+
10
+ ##
11
+ ## base error class
12
+ ##
13
+ class ErubisError < StandardError
14
+ end
15
+
16
+
17
+ ##
18
+ ## raised when method or function is not supported
19
+ ##
20
+ class NotSupportedError < ErubisError
21
+ end
22
+
23
+
24
+ end
@@ -0,0 +1,71 @@
1
+ ##
2
+ ## $Rev: 32 $
3
+ ## $Release: 2.1.0 $
4
+ ## copyright(c) 2006 kuwata-lab all rights reserved.
5
+ ##
6
+
7
+ require 'erubis/error'
8
+ require 'erubis/context'
9
+
10
+
11
+ module Erubis
12
+
13
+
14
+ ##
15
+ ## evaluate code
16
+ ##
17
+ module Evaluator
18
+
19
+ def self.supported_properties # :nodoc:
20
+ return []
21
+ end
22
+
23
+ attr_accessor :src, :filename
24
+
25
+ def init_evaluator(properties)
26
+ @filename = properties[:filename]
27
+ end
28
+
29
+ def result(*args)
30
+ raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
31
+ end
32
+
33
+ def evaluate(*args)
34
+ raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
35
+ end
36
+
37
+ end
38
+
39
+
40
+ ##
41
+ ## evaluator for Ruby
42
+ ##
43
+ module RubyEvaluator
44
+ include Evaluator
45
+
46
+ def self.supported_properties # :nodoc:
47
+ list = Evaluator.supported_properties
48
+ return list
49
+ end
50
+
51
+ ## eval(@src) with binding object
52
+ def result(_binding_or_hash=TOPLEVEL_BINDING)
53
+ _arg = _binding_or_hash
54
+ if _arg.is_a?(Hash)
55
+ ## load _context data as local variables by eval
56
+ eval _arg.keys.inject("") { |s, k| s << "#{k.to_s} = _arg[#{k.inspect}];" }
57
+ _arg = binding()
58
+ end
59
+ return eval(@src, _arg, (@filename || '(erubis)'))
60
+ end
61
+
62
+ ## invoke context.instance_eval(@src)
63
+ def evaluate(context=Context.new)
64
+ context = Context.new(context) if context.is_a?(Hash)
65
+ return context.instance_eval(@src, (@filename || '(erubis)'))
66
+ end
67
+
68
+ end
69
+
70
+
71
+ end