slim 0.9.2 → 0.9.3
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.
- data/.gitignore +18 -0
- data/.yardopts +2 -0
- data/CHANGES +147 -0
- data/Gemfile +16 -0
- data/LICENSE +21 -0
- data/README.md +31 -36
- data/benchmarks/run.rb +114 -0
- data/benchmarks/src/complex.erb +23 -0
- data/benchmarks/src/complex.haml +18 -0
- data/benchmarks/src/complex.slim +17 -0
- data/benchmarks/src/complex_view.rb +15 -0
- data/extra/slim-mode.el +409 -0
- data/extra/test.slim +49 -0
- data/lib/slim/command.rb +0 -6
- data/lib/slim/compiler.rb +40 -51
- data/lib/slim/embedded_engine.rb +69 -41
- data/lib/slim/end_inserter.rb +5 -3
- data/lib/slim/engine.rb +9 -11
- data/lib/slim/filter.rb +10 -13
- data/lib/slim/grammar.rb +19 -0
- data/lib/slim/interpolation.rb +7 -5
- data/lib/slim/parser.rb +48 -33
- data/lib/slim/sections.rb +22 -26
- data/lib/slim/template.rb +7 -7
- data/lib/slim/version.rb +3 -1
- data/lib/slim/wrapper.rb +1 -0
- data/slim.gemspec +34 -0
- data/test/helper.rb +5 -1
- data/test/slim/test_code_escaping.rb +3 -3
- data/test/slim/test_code_evaluation.rb +49 -2
- data/test/slim/test_embedded_engines.rb +3 -1
- data/test/slim/test_html_escaping.rb +8 -0
- data/test/slim/test_html_structure.rb +18 -0
- data/test/slim/test_pretty.rb +8 -3
- data/test/slim/test_ruby_errors.rb +27 -2
- metadata +38 -46
data/.gitignore
ADDED
data/.yardopts
ADDED
data/CHANGES
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
master
|
2
|
+
|
3
|
+
0.9.3
|
4
|
+
|
5
|
+
* Allow for bypassing escaping in attributes
|
6
|
+
* check if string encoding is valid
|
7
|
+
* support for html conditional comments
|
8
|
+
* Use new Temple html attribute expression [:html, :attrs, [:html, :attr, ...], ...]
|
9
|
+
* Use new slim html attribute expression (similiar to Temple)
|
10
|
+
* Option :id_delimiter replaced with :attr_delimiter
|
11
|
+
* Attribute value merging improved (nil/empty values are ignored now)
|
12
|
+
* Arrays attribute values are joined
|
13
|
+
* Boolean attributes (e.g. selected=true is converted to selected="selected")
|
14
|
+
* Option :debug removed
|
15
|
+
* Slim expression grammar provided, Temple validator used in tests
|
16
|
+
* Option :auto_escape replaced with inverse option :disable_escape
|
17
|
+
* Require temple 0.3.0
|
18
|
+
|
19
|
+
0.9.2
|
20
|
+
|
21
|
+
* add SassEngine which respects :pretty
|
22
|
+
* embedded engine code refactored
|
23
|
+
* temple supports denser template registration
|
24
|
+
* deprecate slim/rails (just require 'slim')
|
25
|
+
* use temple rails and tilt templates
|
26
|
+
* add encoding option to Slim::Parser/Slim::Engine to enforce template encoding
|
27
|
+
* vim support is now an external project
|
28
|
+
|
29
|
+
0.9.1
|
30
|
+
|
31
|
+
* add new doctype syntax without !
|
32
|
+
* slim directive expression has type and args
|
33
|
+
|
34
|
+
0.9.0
|
35
|
+
|
36
|
+
* slim should not be registered as the default template handler.
|
37
|
+
* add support for unescaped text interpolation
|
38
|
+
|
39
|
+
0.8.4
|
40
|
+
|
41
|
+
* Added the option to turn off automatic HTML escaping.
|
42
|
+
* update to tilt 1.2.2
|
43
|
+
* allow call to yield in logic less mode
|
44
|
+
* allow doctype declaration to be capitalized
|
45
|
+
|
46
|
+
0.8.3
|
47
|
+
|
48
|
+
* Added support for html comments. The parser uses the :static filter instead of the :comment filter due to the way the parser is constructed.
|
49
|
+
|
50
|
+
0.8.2
|
51
|
+
|
52
|
+
* fix issue #96
|
53
|
+
* Added the Temple Debugger filter.
|
54
|
+
* Rails problems fixed
|
55
|
+
|
56
|
+
0.8.1
|
57
|
+
|
58
|
+
* remove backtick slim syntax -- no longer supported
|
59
|
+
* slim executable conflict. issue #91
|
60
|
+
* vim syntax support improved
|
61
|
+
|
62
|
+
0.8.0
|
63
|
+
|
64
|
+
* rails logic less support
|
65
|
+
|
66
|
+
0.7.4
|
67
|
+
|
68
|
+
* use ' for text block with trailing whitespace
|
69
|
+
* allow to disable/enable embedded engines
|
70
|
+
|
71
|
+
0.7.3
|
72
|
+
|
73
|
+
* fix #82
|
74
|
+
* basic rails test added
|
75
|
+
|
76
|
+
0.7.2
|
77
|
+
|
78
|
+
* get rid of rails deprecation warning
|
79
|
+
* use_html_safe is activated automatically by temple
|
80
|
+
|
81
|
+
0.7.1
|
82
|
+
|
83
|
+
* logic less mode
|
84
|
+
* add syntax for explicitly closed tags
|
85
|
+
|
86
|
+
0.7.0
|
87
|
+
|
88
|
+
* slim-mode.el for emacs added (modified haml-mode.el, needs some work to be fully functional for slim)
|
89
|
+
* embedded engines
|
90
|
+
* escape interpolated strings/attributes
|
91
|
+
* Slim#Filter now uses optional configuration hash
|
92
|
+
* Initial implementation for Rail's `html_safe`. Closes #25
|
93
|
+
* fallback to escape_html stolen from cgi.rb if escape_utils is unavailable, use normal requires because slim is on the load path
|
94
|
+
* Limit the allowed characters used for attributes delimiters (now only allows parentheses, square brackets and curly braces). See #16 for more info.
|
95
|
+
* Default to HTML5-mode
|
96
|
+
* Slim now uses Temple and Tilt.
|
97
|
+
* Choose your own attribute delimiter!
|
98
|
+
|
99
|
+
0.6.1
|
100
|
+
|
101
|
+
* can wrap parens around attributes if you so desire
|
102
|
+
* added erubis to the benchmarks
|
103
|
+
|
104
|
+
0.6.0
|
105
|
+
|
106
|
+
* Added slim itself, haml and mustache to the development env for easier benchmarking.
|
107
|
+
* added escape_html functionality. need to tweak for speed
|
108
|
+
|
109
|
+
0.5.1
|
110
|
+
|
111
|
+
* Consecutive condition statements now working as expected.
|
112
|
+
|
113
|
+
0.5.0
|
114
|
+
|
115
|
+
* Added 'unless' to the list of control words.
|
116
|
+
* Fixes for inline conditions. There must be a better way of doing this??
|
117
|
+
* '-' is a valid character in HTML attributes, so let's allow that.
|
118
|
+
* Improved the regex so that control code now supports code blocks.
|
119
|
+
* Output code (start with '=') can now accept code blocks.
|
120
|
+
* Method calls no longer need parenthesis. We need more tests to ensure the implementation's robustness.
|
121
|
+
|
122
|
+
0.4.1
|
123
|
+
|
124
|
+
* Added '|' as an alias of '`' for parsing plain text. This simulates the syntax of the Jade template engine.
|
125
|
+
* Added instructions of how to use the gem.
|
126
|
+
|
127
|
+
0.4.0
|
128
|
+
|
129
|
+
* support for nesting lines under backtick
|
130
|
+
* make it so that one space is the left margin. any additional spaces will be copied over
|
131
|
+
* support for using indentation after backtick to denote paragraphs. useful for script tags and paragraphs
|
132
|
+
|
133
|
+
0.3.1
|
134
|
+
|
135
|
+
* fix bug with adding end to nesting ruby code
|
136
|
+
|
137
|
+
0.3.0
|
138
|
+
|
139
|
+
* Optimize compiled string to reduce number of concatentations to the buffer
|
140
|
+
|
141
|
+
0.2.0
|
142
|
+
|
143
|
+
* can now make code call on same line as tag
|
144
|
+
|
145
|
+
0.1.0
|
146
|
+
|
147
|
+
* Initial release
|
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
if path = ENV['SLIM_USE_TEMPLE']
|
6
|
+
if path == 'edge'
|
7
|
+
gem 'temple', :git => 'git://github.com/judofyr/temple.git'
|
8
|
+
else
|
9
|
+
gem 'temple', :path => path
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
group :integration do
|
14
|
+
gem 'rails', '~> 3.0.3'
|
15
|
+
gem 'sqlite3-ruby'
|
16
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Slim Team
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ Install Slim as a gem:
|
|
29
29
|
|
30
30
|
Include Slim in your Gemfile:
|
31
31
|
|
32
|
-
gem 'slim'
|
32
|
+
gem 'slim'
|
33
33
|
|
34
34
|
That's it! Now, just use the .slim extension and you're good to go.
|
35
35
|
|
@@ -215,10 +215,11 @@ Here's a quick example to demonstrate what a Slim template looks like:
|
|
215
215
|
|
216
216
|
### Evaluate ruby code in text
|
217
217
|
|
218
|
-
Use standard Ruby interpolation. The text will
|
218
|
+
Use standard Ruby interpolation. The text will be html escaped by default.
|
219
219
|
|
220
220
|
body
|
221
221
|
h1 Welcome #{current_user.name} to the show.
|
222
|
+
| Unescaped #{{content}} is also possible.
|
222
223
|
|
223
224
|
To escape the interpolation (i.e. render as is)
|
224
225
|
|
@@ -233,9 +234,9 @@ Here's a quick example to demonstrate what a Slim template looks like:
|
|
233
234
|
h1 id="headline"
|
234
235
|
== page_headline
|
235
236
|
|
236
|
-
Alternatively, if you prefer to use single equal sign, you may do so by setting the `
|
237
|
+
Alternatively, if you prefer to use single equal sign, you may do so by setting the `disable_escape` option to true.
|
237
238
|
|
238
|
-
Slim::Engine.default_options[:
|
239
|
+
Slim::Engine.default_options[:disable_escape] = true
|
239
240
|
|
240
241
|
### Treat multiple lines of code as text that should bypass parsing
|
241
242
|
|
@@ -276,41 +277,34 @@ Here's a quick example to demonstrate what a Slim template looks like:
|
|
276
277
|
|
277
278
|
<body><p><!--This will get displayed as html comments.--></p></body>
|
278
279
|
|
279
|
-
### Validate Slim syntax
|
280
|
-
|
281
|
-
There are two helpers you could use to validate your Slim syntax:
|
282
|
-
|
283
|
-
Slim::Validator.valid?(source) # -> true or false
|
284
|
-
Slim::Validator.validate!(source) # -> true or exception
|
285
|
-
|
286
280
|
## Benchmarks
|
287
281
|
|
288
|
-
#
|
282
|
+
# Linux + Ruby 1.9.2, 1000 iterations
|
289
283
|
|
290
284
|
user system total real
|
291
|
-
(1) erb 0.
|
292
|
-
(1) erubis 0.
|
293
|
-
(1) fast erubis 0.
|
294
|
-
(1) slim
|
295
|
-
(1) haml
|
296
|
-
(1) haml ugly
|
297
|
-
(2) erb 0.
|
298
|
-
(2) erubis 0.
|
299
|
-
(2) fast erubis 0.
|
300
|
-
(2) slim 0.
|
301
|
-
(2) haml 0.
|
302
|
-
(2) haml ugly 0.
|
303
|
-
(3) erb 0.
|
304
|
-
(3) erubis 0.
|
305
|
-
(3) fast erubis 0.
|
306
|
-
(3) slim 0.
|
307
|
-
(3) haml 0.
|
308
|
-
(3) haml ugly 0.
|
309
|
-
(4) erb 0.
|
310
|
-
(4) erubis 0.
|
311
|
-
(4) slim 0.
|
312
|
-
(4) haml 0.
|
313
|
-
(4) haml ugly 0.
|
285
|
+
(1) erb 0.680000 0.000000 0.680000 ( 0.810375)
|
286
|
+
(1) erubis 0.510000 0.000000 0.510000 ( 0.547548)
|
287
|
+
(1) fast erubis 0.530000 0.000000 0.530000 ( 0.583134)
|
288
|
+
(1) slim 4.330000 0.020000 4.350000 ( 4.495633)
|
289
|
+
(1) haml 4.680000 0.020000 4.700000 ( 4.747019)
|
290
|
+
(1) haml ugly 4.530000 0.020000 4.550000 ( 4.592425)
|
291
|
+
(2) erb 0.240000 0.000000 0.240000 ( 0.235896)
|
292
|
+
(2) erubis 0.180000 0.000000 0.180000 ( 0.185349)
|
293
|
+
(2) fast erubis 0.150000 0.000000 0.150000 ( 0.154970)
|
294
|
+
(2) slim 0.050000 0.000000 0.050000 ( 0.046685)
|
295
|
+
(2) haml 0.490000 0.000000 0.490000 ( 0.497864)
|
296
|
+
(2) haml ugly 0.420000 0.000000 0.420000 ( 0.428596)
|
297
|
+
(3) erb 0.030000 0.000000 0.030000 ( 0.033979)
|
298
|
+
(3) erubis 0.030000 0.000000 0.030000 ( 0.030705)
|
299
|
+
(3) fast erubis 0.040000 0.000000 0.040000 ( 0.035229)
|
300
|
+
(3) slim 0.040000 0.000000 0.040000 ( 0.036249)
|
301
|
+
(3) haml 0.160000 0.000000 0.160000 ( 0.165024)
|
302
|
+
(3) haml ugly 0.150000 0.000000 0.150000 ( 0.146130)
|
303
|
+
(4) erb 0.060000 0.000000 0.060000 ( 0.059847)
|
304
|
+
(4) erubis 0.040000 0.000000 0.040000 ( 0.040770)
|
305
|
+
(4) slim 0.040000 0.000000 0.040000 ( 0.047389)
|
306
|
+
(4) haml 0.190000 0.000000 0.190000 ( 0.188837)
|
307
|
+
(4) haml ugly 0.170000 0.000000 0.170000 ( 0.175378)
|
314
308
|
|
315
309
|
1. Uncached benchmark. Template is parsed every time.
|
316
310
|
Activate this benchmark with slow=1.
|
@@ -341,7 +335,8 @@ This project is released under the MIT license.
|
|
341
335
|
|
342
336
|
## Discuss
|
343
337
|
|
344
|
-
[Google Group](http://groups.google.com/group/slim-template)
|
338
|
+
* [Google Group](http://groups.google.com/group/slim-template)
|
339
|
+
* IRC Channel #slim-lang on freenode.net
|
345
340
|
|
346
341
|
## Slim related projects
|
347
342
|
|
data/benchmarks/run.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'), File.join(File.dirname(__FILE__), 'src'))
|
4
|
+
|
5
|
+
require 'slim'
|
6
|
+
require 'complex_view'
|
7
|
+
|
8
|
+
require 'benchmark'
|
9
|
+
require 'ostruct'
|
10
|
+
require 'erubis'
|
11
|
+
require 'erb'
|
12
|
+
require 'haml'
|
13
|
+
require 'tilt'
|
14
|
+
|
15
|
+
class SlimBenchmarks
|
16
|
+
def initialize(slow, iterations)
|
17
|
+
@iterations = (iterations || 1000).to_i
|
18
|
+
@benches = []
|
19
|
+
|
20
|
+
tpl_erb = File.read(File.dirname(__FILE__) + '/src/complex.erb')
|
21
|
+
tpl_haml = File.read(File.dirname(__FILE__) + '/src/complex.haml')
|
22
|
+
tpl_slim = File.read(File.dirname(__FILE__) + '/src/complex.slim')
|
23
|
+
|
24
|
+
view = ComplexView.new
|
25
|
+
eview = OpenStruct.new(:header => view.header, :item => view.item).instance_eval{ binding }
|
26
|
+
|
27
|
+
erb = ERB.new(tpl_erb)
|
28
|
+
erubis = Erubis::Eruby.new(tpl_erb)
|
29
|
+
fast_erubis = Erubis::FastEruby.new(tpl_erb)
|
30
|
+
haml = Haml::Engine.new(tpl_haml, :format => :html5)
|
31
|
+
haml_ugly = Haml::Engine.new(tpl_haml, :format => :html5, :ugly => true)
|
32
|
+
slim = Slim::Template.new { tpl_slim }
|
33
|
+
|
34
|
+
tilt_erb = Tilt::ERBTemplate.new { tpl_erb }
|
35
|
+
tilt_erubis = Tilt::ErubisTemplate.new { tpl_erb }
|
36
|
+
tilt_haml = Tilt::HamlTemplate.new(:format => :html5){ tpl_haml }
|
37
|
+
tilt_haml_ugly = Tilt::HamlTemplate.new(:format => :html5, :ugly => true){ tpl_haml }
|
38
|
+
tilt_slim = Slim::Template.new { tpl_slim }
|
39
|
+
|
40
|
+
haml.def_method(view, :run_haml)
|
41
|
+
haml_ugly.def_method(view, :run_haml_ugly)
|
42
|
+
view.instance_eval %{
|
43
|
+
def run_erb; #{erb.src}; end
|
44
|
+
def run_erubis; #{erubis.src}; end
|
45
|
+
def run_fast_erubis; #{fast_erubis.src}; end
|
46
|
+
def run_slim; #{slim.precompiled_template}; end
|
47
|
+
}
|
48
|
+
|
49
|
+
if slow
|
50
|
+
bench('(1) erb') { ERB.new(tpl_erb).result(eview) }
|
51
|
+
bench('(1) erubis') { Erubis::Eruby.new(tpl_erb).result(eview) }
|
52
|
+
bench('(1) fast erubis') { Erubis::Eruby.new(tpl_erb).result(eview) }
|
53
|
+
bench('(1) slim') { Slim::Template.new { tpl_slim }.render(view) }
|
54
|
+
bench('(1) haml') { Haml::Engine.new(tpl_haml, :format => :html5).render(view) }
|
55
|
+
bench('(1) haml ugly') { Haml::Engine.new(tpl_haml, :format => :html5, :ugly => true).render(view) }
|
56
|
+
end
|
57
|
+
|
58
|
+
bench('(2) erb') { erb.result(eview) }
|
59
|
+
bench('(2) erubis') { erubis.result(eview) }
|
60
|
+
bench('(2) fast erubis') { fast_erubis.result(eview) }
|
61
|
+
bench('(2) slim') { slim.render(view) }
|
62
|
+
bench('(2) haml') { haml.render(view) }
|
63
|
+
bench('(2) haml ugly') { haml_ugly.render(view) }
|
64
|
+
|
65
|
+
bench('(3) erb') { view.run_erb }
|
66
|
+
bench('(3) erubis') { view.run_erubis }
|
67
|
+
bench('(3) fast erubis') { view.run_fast_erubis }
|
68
|
+
bench('(3) slim') { view.run_slim }
|
69
|
+
bench('(3) haml') { view.run_haml }
|
70
|
+
bench('(3) haml ugly') { view.run_haml_ugly }
|
71
|
+
|
72
|
+
bench('(4) erb') { tilt_erb.render(view) }
|
73
|
+
bench('(4) erubis') { tilt_erubis.render(view) }
|
74
|
+
bench('(4) slim') { tilt_slim.render(view) }
|
75
|
+
bench('(4) haml') { tilt_haml.render(view) }
|
76
|
+
bench('(4) haml ugly') { tilt_haml_ugly.render(view) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def run
|
80
|
+
puts "#{@iterations} Iterations"
|
81
|
+
Benchmark.bmbm do |x|
|
82
|
+
@benches.each do |name, block|
|
83
|
+
x.report name.to_s do
|
84
|
+
@iterations.to_i.times { block.call }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
puts "
|
89
|
+
1. Uncached benchmark. Template is parsed every time.
|
90
|
+
Activate this benchmark with slow=1.
|
91
|
+
|
92
|
+
2. Cached benchmark. Template is parsed before the benchmark.
|
93
|
+
The ruby code generated by the template engine might be evaluated every time.
|
94
|
+
This benchmark uses the standard API of the template engine.
|
95
|
+
|
96
|
+
3. Compiled benchmark. Template is parsed before the benchmark and
|
97
|
+
generated ruby code is compiled into a method.
|
98
|
+
This is the fastest evaluation strategy because it benchmarks
|
99
|
+
pure execution speed of the generated ruby code.
|
100
|
+
|
101
|
+
4. Compiled Tilt benchmark. Template is compiled with Tilt, which gives a more
|
102
|
+
accurate result of the performance in production mode in frameworks like
|
103
|
+
Sinatra, Ramaze and Camping. (Rails still uses its own template
|
104
|
+
compilation.)
|
105
|
+
|
106
|
+
"
|
107
|
+
end
|
108
|
+
|
109
|
+
def bench(name, &block)
|
110
|
+
@benches.push([name, block])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
SlimBenchmarks.new(ARGV[0], ARGV[1]).run
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!DOCTYPE HTML>
|
2
|
+
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<title>Simple Benchmark</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1><%= header %></h1>
|
9
|
+
<% unless item.empty? %>
|
10
|
+
<ul>
|
11
|
+
<% for i in item %>
|
12
|
+
<% if i[:current] %>
|
13
|
+
<li><strong><%= i[:name] %></strong></li>
|
14
|
+
<% else %>
|
15
|
+
<li><a href="<%= i[:url] %>"><%= i[:name] %></a></li>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
18
|
+
</ul>
|
19
|
+
<% else %>
|
20
|
+
<p>The list is empty.</p>
|
21
|
+
<% end %>
|
22
|
+
</body>
|
23
|
+
</html>
|