serbea 0.7.0 β 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -2
- data/README.md +5 -5
- data/lib/serbea.rb +3 -2
- data/lib/serbea/bridgetown_support.rb +11 -18
- data/lib/serbea/helpers.rb +6 -5
- data/lib/serbea/pipeline.rb +20 -6
- data/lib/serbea/rails_support.rb +28 -10
- data/lib/serbea/template_engine.rb +11 -23
- data/lib/version.rb +1 -1
- data/serbea.gemspec +4 -2
- metadata +26 -13
- data/lib/serbea/component_renderer.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 352c314f5f5a9b6df23933e1b379af39617c82c9b583f4c0703480a5f71df498
|
4
|
+
data.tar.gz: 364a353dba20ce3af4bcc071247477ec6dfa6f95c15bb94c88677520344a3cf1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bcdd89d15300e24e051f68de0d87899bec18c9f304162e3b667afc7c8a420ab5978e5eb91ab40f8dfd4201375a7fab769d9419a19562196e3ba93b85692e262
|
7
|
+
data.tar.gz: 8ba0cddf305d712c3e970adb06979e27f426aae797b2d99702f844e6e5c9248d34a96e35238134314da783e5fbd3de93b56cf7d5701ecc909690719393aa05fc
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
π Serbea: Similar to ERB, Except Awesomer
|
1
|
+
# π Serbea: Similar to ERB, Except Awesomer
|
2
2
|
|
3
|
-
The Ruby template language you always dreamed of is here.
|
3
|
+
The Ruby template language you've always dreamed of is finally here. _Le roi est mort, vive le roi!_
|
4
4
|
|
5
|
-
Serbea combines the best ideas from "brace-style" template languages such as Liquid, Nunjucks, Twig, Jinja, Mustache, etc.βand applies them to the world of ERB. You can use Serbea in Rails
|
5
|
+
Serbea combines the best ideas from "brace-style" template languages such as Liquid, Nunjucks, Twig, Jinja, Mustache, etc.βand applies them to the world of ERB. You can use Serbea in Rails applications, Bridgetown static sites, or pretty much any Ruby scenario you could imagine.
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
@@ -11,9 +11,9 @@ Serbea combines the best ideas from "brace-style" template languages such as Liq
|
|
11
11
|
* Autoescaped variables by default within the pipeline (`{{ }}`) tags. Use the `safe`/`raw` or `escape`/`h` filters to control escaping on output.
|
12
12
|
* Render directive `{%@ %}` as shortcut for rendering either string-named partials (`render "tmpl"`) or object instances (`render MyComponent.new`).
|
13
13
|
* Supports every convention of ERB and builds upon it with new features (which is why it's "awesomer!").
|
14
|
-
* Builtin frontmatter support
|
14
|
+
* Builtin frontmatter support so you can access the variables written into the top YAML within your templates. In any Rails view, including layouts, you'll have access to the `@frontmatter` ivar which is a merged `HashWithDotAccess::Hash` with data from any part of the view tree (partials, pages, layout).
|
15
15
|
* The filters accessible within Serbea templates are either helpers (where the variable gets passed as the first argument) or instance methods of the variable itself, so you can build extremely expressive pipelines that take advantage of the code you already know and love. (For example, in Rails you could write `{{ "My Link" | link_to: route_path }}`).
|
16
|
-
* The `Serbea::Pipeline.exec` method lets you pass a pipeline template in, along with an optional input value or included helpers module, and you'll get the output as a object of any type (not converted to a string like in traditional templates). For example: `Serbea::Pipeline.exec("
|
16
|
+
* The `Serbea::Pipeline.exec` method lets you pass a pipeline template in, along with an optional input value or included helpers module, and you'll get the output as a object of any type (not converted to a string like in traditional templates). For example: `Serbea::Pipeline.exec("arr |> map: ->(i) { i * 10 }", arr: [1,2,3])` will return `[10, 20, 30]`.
|
17
17
|
|
18
18
|
## What It Looks Like
|
19
19
|
|
data/lib/serbea.rb
CHANGED
@@ -4,14 +4,13 @@ require "tilt/erubi"
|
|
4
4
|
require "serbea/helpers"
|
5
5
|
require "serbea/pipeline"
|
6
6
|
require "serbea/template_engine"
|
7
|
-
require "serbea/component_renderer"
|
8
7
|
|
9
8
|
module Tilt
|
10
9
|
class SerbeaTemplate < ErubiTemplate
|
11
10
|
def prepare
|
12
11
|
@options.merge!(
|
13
12
|
outvar: "@_erbout",
|
14
|
-
bufval: "Serbea::
|
13
|
+
bufval: "Serbea::OutputBuffer.new",
|
15
14
|
literal_prefix: "{%",
|
16
15
|
literal_postfix: "%}",
|
17
16
|
engine_class: Serbea::TemplateEngine
|
@@ -32,6 +31,8 @@ if defined?(Rails::Railtie)
|
|
32
31
|
initializer :serbea do |app|
|
33
32
|
ActiveSupport.on_load(:action_view) do
|
34
33
|
require "serbea/rails_support"
|
34
|
+
|
35
|
+
ActionController::Base.include Serbea::Rails::FrontmatterControllerActions
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
@@ -40,6 +40,8 @@ module Bridgetown
|
|
40
40
|
#
|
41
41
|
# @return [String] The converted content.
|
42
42
|
def convert(content, convertible)
|
43
|
+
return content if convertible.data[:template_engine] != "serbea"
|
44
|
+
|
43
45
|
serb_view = Bridgetown::SerbeaView.new(convertible)
|
44
46
|
|
45
47
|
serb_renderer = Tilt::SerbeaTemplate.new(convertible.relative_path) { content }
|
@@ -53,16 +55,17 @@ module Bridgetown
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
def matches(ext, convertible
|
57
|
-
if convertible
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
58
|
+
def matches(ext, convertible)
|
59
|
+
if convertible.data[:template_engine] == "serbea" ||
|
60
|
+
(convertible.data[:template_engine].nil? &&
|
61
|
+
@config[:template_engine] == "serbea")
|
62
|
+
convertible.data[:template_engine] = "serbea"
|
63
|
+
return true
|
63
64
|
end
|
64
65
|
|
65
|
-
super(ext)
|
66
|
+
super(ext).tap do |ext_matches|
|
67
|
+
convertible.data[:template_engine] = "serbea" if ext_matches
|
68
|
+
end
|
66
69
|
end
|
67
70
|
|
68
71
|
def output_ext(ext)
|
@@ -71,13 +74,3 @@ module Bridgetown
|
|
71
74
|
end
|
72
75
|
end
|
73
76
|
end
|
74
|
-
|
75
|
-
Bridgetown::Hooks.register :site, :pre_render, reloadable: false do |site|
|
76
|
-
# make sure Liquid doesn't find {% %} and decide to process Serbea code!
|
77
|
-
site.contents.each do |convertible|
|
78
|
-
convertible.data.render_with_liquid = false if convertible.extname == ".serb"
|
79
|
-
end
|
80
|
-
site.layouts.values.each do |convertible|
|
81
|
-
convertible.data.render_with_liquid = false if convertible.ext == ".serb"
|
82
|
-
end
|
83
|
-
end
|
data/lib/serbea/helpers.rb
CHANGED
@@ -8,11 +8,12 @@ module Serbea
|
|
8
8
|
|
9
9
|
def capture(obj = nil, &block)
|
10
10
|
previous_buffer_state = @_erbout
|
11
|
-
@_erbout = Serbea::
|
11
|
+
@_erbout = Serbea::OutputBuffer.new
|
12
12
|
|
13
13
|
# For compatibility with ActionView, not used by Bridgetown normally
|
14
14
|
previous_ob_state = @output_buffer
|
15
|
-
@output_buffer = Serbea::
|
15
|
+
@output_buffer = Serbea::OutputBuffer.new
|
16
|
+
|
16
17
|
|
17
18
|
result = instance_exec(obj, &block)
|
18
19
|
if @output_buffer != ""
|
@@ -22,7 +23,7 @@ module Serbea
|
|
22
23
|
@_erbout = previous_buffer_state
|
23
24
|
@output_buffer = previous_ob_state
|
24
25
|
|
25
|
-
result
|
26
|
+
result&.html_safe
|
26
27
|
end
|
27
28
|
|
28
29
|
def pipeline(context, value)
|
@@ -32,11 +33,11 @@ module Serbea
|
|
32
33
|
def helper(name, &helper_block)
|
33
34
|
self.class.define_method(name) do |*args, &block|
|
34
35
|
previous_buffer_state = @_erbout
|
35
|
-
@_erbout = Serbea::
|
36
|
+
@_erbout = Serbea::OutputBuffer.new
|
36
37
|
|
37
38
|
# For compatibility with ActionView, not used by Bridgetown normally
|
38
39
|
previous_ob_state = @output_buffer
|
39
|
-
@output_buffer = Serbea::
|
40
|
+
@output_buffer = Serbea::OutputBuffer.new
|
40
41
|
|
41
42
|
result = helper_block.call(*args, &block)
|
42
43
|
if @output_buffer != ""
|
data/lib/serbea/pipeline.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require "active_support/core_ext/string/output_safety"
|
2
|
+
require "active_support/core_ext/object/blank"
|
2
3
|
|
3
4
|
module Serbea
|
4
5
|
class Pipeline
|
5
|
-
def self.exec(template,
|
6
|
+
def self.exec(template, locals = {}, include_helpers: nil, **kwargs)
|
6
7
|
anon = Class.new do
|
7
8
|
include Serbea::Helpers
|
8
9
|
|
9
|
-
attr_accessor :
|
10
|
+
attr_accessor :output
|
10
11
|
end
|
11
12
|
|
12
13
|
if include_helpers
|
@@ -14,12 +15,11 @@ module Serbea
|
|
14
15
|
end
|
15
16
|
|
16
17
|
pipeline_obj = anon.new
|
17
|
-
pipeline_obj.input = input unless no_input_passed
|
18
18
|
|
19
19
|
full_template = "{{ #{template} | assign_to: :output }}"
|
20
20
|
|
21
21
|
tmpl = Tilt::SerbeaTemplate.new { full_template }
|
22
|
-
tmpl.render(pipeline_obj)
|
22
|
+
tmpl.render(pipeline_obj, locals.presence || kwargs)
|
23
23
|
|
24
24
|
pipeline_obj.output
|
25
25
|
end
|
@@ -54,8 +54,9 @@ module Serbea
|
|
54
54
|
@value_methods_denylist ||= Set.new
|
55
55
|
end
|
56
56
|
|
57
|
-
def initialize(
|
58
|
-
@
|
57
|
+
def initialize(binding, value)
|
58
|
+
@binding = binding
|
59
|
+
@context = binding.receiver
|
59
60
|
@value = value
|
60
61
|
end
|
61
62
|
|
@@ -83,6 +84,19 @@ module Serbea
|
|
83
84
|
else
|
84
85
|
@value = @context.send(name, @value, *args)
|
85
86
|
end
|
87
|
+
elsif @binding.local_variables.include?(name)
|
88
|
+
var = @binding.local_variable_get(name)
|
89
|
+
if var.respond_to?(:call)
|
90
|
+
unless kwargs.empty?
|
91
|
+
@value = var.call(@value, *args, **kwargs)
|
92
|
+
else
|
93
|
+
@value = var.call(@value, *args)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
"Serbea warning: Filter #{name} does not respond to call".tap do |warning|
|
97
|
+
self.class.raise_on_missing_filters ? raise(warning) : STDERR.puts(warning)
|
98
|
+
end
|
99
|
+
end
|
86
100
|
else
|
87
101
|
"Serbea warning: Filter not found: #{name}".tap do |warning|
|
88
102
|
self.class.raise_on_missing_filters ? raise(warning) : STDERR.puts(warning)
|
data/lib/serbea/rails_support.rb
CHANGED
@@ -1,22 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# inspired by https://github.com/haml/haml/blob/main/lib/haml/plugin.rb
|
4
3
|
module Serbea
|
4
|
+
module Rails
|
5
|
+
module FrontmatterHelpers
|
6
|
+
def set_page_frontmatter=(data)
|
7
|
+
@frontmatter ||= HashWithDotAccess::Hash.new
|
8
|
+
@frontmatter.update(data)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module FrontmatterControllerActions
|
13
|
+
extend ActiveSupport::Concern
|
5
14
|
|
6
|
-
|
7
|
-
|
8
|
-
|
15
|
+
included do
|
16
|
+
Serbea::TemplateEngine.front_matter_preamble = "self.set_page_frontmatter = local_frontmatter = YAML.load"
|
17
|
+
|
18
|
+
before_action { @frontmatter ||= HashWithDotAccess::Hash.new }
|
9
19
|
|
10
|
-
|
11
|
-
|
20
|
+
helper Serbea::Rails::FrontmatterHelpers
|
21
|
+
end
|
12
22
|
end
|
13
23
|
|
14
|
-
|
15
|
-
|
24
|
+
class TemplateHandler
|
25
|
+
def handles_encoding?; true; end
|
26
|
+
|
27
|
+
def compile(template, source)
|
28
|
+
"self.class.include(Serbea::Helpers);" + Tilt::SerbeaTemplate.new { source }.precompiled_template([])
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.call(template, source = nil)
|
32
|
+
source ||= template.source
|
16
33
|
|
17
|
-
|
34
|
+
new.compile(template, source)
|
35
|
+
end
|
18
36
|
end
|
19
37
|
end
|
20
38
|
end
|
21
39
|
|
22
|
-
ActionView::Template.register_template_handler(:serb, Serbea::
|
40
|
+
ActionView::Template.register_template_handler(:serb, Serbea::Rails::TemplateHandler)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "strscan"
|
2
2
|
|
3
3
|
module Serbea
|
4
|
-
class
|
4
|
+
class OutputBuffer < String
|
5
5
|
def concat_to_s(input)
|
6
6
|
concat input.to_s
|
7
7
|
end
|
@@ -66,13 +66,11 @@ module Serbea
|
|
66
66
|
|
67
67
|
# Ensure the raw "tag" will strip out all ERB-style processing
|
68
68
|
until string.empty?
|
69
|
-
text, code, string = string.partition(/{% raw %}.*?{% endraw %}/m)
|
69
|
+
text, code, string = string.partition(/{% raw %}(.*?){% endraw %}/m)
|
70
70
|
|
71
71
|
buff << text
|
72
72
|
if code.length > 0
|
73
|
-
buff <<
|
74
|
-
sub("{% raw %}", "").
|
75
|
-
sub("{% endraw %}", "").
|
73
|
+
buff << $1.
|
76
74
|
gsub("{{", "__RAW_START_PRINT__").
|
77
75
|
gsub("}}", "__RAW_END_PRINT__").
|
78
76
|
gsub("{%", "__RAW_START_EVAL__").
|
@@ -84,17 +82,16 @@ module Serbea
|
|
84
82
|
string = buff
|
85
83
|
buff = ""
|
86
84
|
until string.empty?
|
87
|
-
text, code, string = string.partition(/{{.*?}}/m)
|
85
|
+
text, code, string = string.partition(/{{(.*?)}}/m)
|
88
86
|
|
89
87
|
buff << text
|
90
88
|
if code.length > 0
|
91
89
|
original_line_length = code.lines.size
|
92
90
|
|
93
|
-
s = StringScanner.new(
|
94
|
-
done = false
|
91
|
+
s = StringScanner.new($1)
|
95
92
|
escaped_segment = ""
|
96
93
|
segments = []
|
97
|
-
|
94
|
+
until s.eos?
|
98
95
|
portion = s.scan_until(/\|>?/)
|
99
96
|
if portion
|
100
97
|
if portion.end_with?('\|')
|
@@ -124,11 +121,11 @@ module Serbea
|
|
124
121
|
# or just the rest will do
|
125
122
|
segments << s.rest
|
126
123
|
end
|
127
|
-
|
124
|
+
s.terminate
|
128
125
|
end
|
129
126
|
end
|
130
127
|
|
131
|
-
segments[0] = "pipeline(
|
128
|
+
segments[0] = "pipeline(binding, (#{segments[0].strip}))"
|
132
129
|
segments[1..-1].each_with_index do |segment, index|
|
133
130
|
filter, args = segment.strip.match(/([^ :]*)(.*)/m).captures
|
134
131
|
segments[index + 1] = ".filter(:" + filter
|
@@ -148,24 +145,15 @@ module Serbea
|
|
148
145
|
end
|
149
146
|
end
|
150
147
|
|
151
|
-
# Process any directives
|
152
|
-
#
|
153
|
-
# TODO: allow custom directives! aka
|
154
|
-
# {%@something whatever %}
|
155
|
-
# {%@script
|
156
|
-
# const foo = "really? #{really}!"
|
157
|
-
# alert(foo.toLowerCase())
|
158
|
-
# %}
|
159
|
-
# {%@preact AwesomeChart data={#{ruby_data.to_json}} %}
|
148
|
+
# Process any render directives
|
160
149
|
string = buff
|
161
150
|
buff = ""
|
162
151
|
until string.empty?
|
163
|
-
text, code, string = string.partition(/{
|
152
|
+
text, code, string = string.partition(/{%@(.*?)%}/m)
|
164
153
|
|
165
154
|
buff << text
|
166
155
|
if code.length > 0
|
167
|
-
code
|
168
|
-
code.sub!(/%}$/, "")
|
156
|
+
code = $1
|
169
157
|
unless ["end", ""].include? code.strip
|
170
158
|
original_line_length = code.lines.size
|
171
159
|
|
data/lib/version.rb
CHANGED
data/serbea.gemspec
CHANGED
@@ -16,8 +16,10 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test|script|spec|features)/!) }
|
17
17
|
spec.require_paths = ["lib"]
|
18
18
|
|
19
|
-
spec.add_runtime_dependency("rake", "~> 13.0")
|
20
|
-
spec.add_runtime_dependency("erubi", "~> 1.9")
|
21
19
|
spec.add_runtime_dependency("activesupport", "~> 6.0")
|
20
|
+
spec.add_runtime_dependency("erubi", ">= 1.10")
|
21
|
+
spec.add_runtime_dependency("hash_with_dot_access", "~> 1.1")
|
22
22
|
spec.add_runtime_dependency("tilt", "~> 2.0")
|
23
|
+
|
24
|
+
spec.add_development_dependency("rake", "~> 13.0")
|
23
25
|
end
|
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serbea
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bridgetown Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '6.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '6.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: erubi
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.10'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.10'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: hash_with_dot_access
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '1.1'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '1.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: tilt
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.0'
|
69
83
|
description:
|
70
84
|
email: maintainers@bridgetownrb.com
|
71
85
|
executables: []
|
@@ -78,7 +92,6 @@ files:
|
|
78
92
|
- Rakefile
|
79
93
|
- lib/serbea.rb
|
80
94
|
- lib/serbea/bridgetown_support.rb
|
81
|
-
- lib/serbea/component_renderer.rb
|
82
95
|
- lib/serbea/helpers.rb
|
83
96
|
- lib/serbea/pipeline.rb
|
84
97
|
- lib/serbea/rails_support.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Serbea
|
2
|
-
class ComponentRenderer
|
3
|
-
include Helpers
|
4
|
-
|
5
|
-
def initialize(variables = {})
|
6
|
-
@variables = variables
|
7
|
-
end
|
8
|
-
|
9
|
-
def respond_to_missing?(key, include_private = false)
|
10
|
-
@variables.key?(key)
|
11
|
-
end
|
12
|
-
|
13
|
-
def method_missing(key)
|
14
|
-
return @variables[key] if respond_to_missing?(key)
|
15
|
-
|
16
|
-
super
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|