bemer 0.0.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.gitignore +12 -0
- data/.overcommit.yml +59 -0
- data/.rspec +4 -0
- data/.rubocop.yml +12 -1
- data/.rubocop_todo.yml +3 -6
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/LICENSE-RU +23 -0
- data/README.md +2 -10
- data/Rakefile +8 -1
- data/bemer.gemspec +19 -6
- data/lib/bemer.rb +93 -2
- data/lib/bemer/asset_matcher.rb +21 -0
- data/lib/bemer/builders.rb +23 -0
- data/lib/bemer/builders/tag/element.rb +22 -0
- data/lib/bemer/builders/template.rb +57 -0
- data/lib/bemer/builders/template_list.rb +56 -0
- data/lib/bemer/builders/tree.rb +35 -0
- data/lib/bemer/builders/tree/element.rb +22 -0
- data/lib/bemer/common_template.rb +29 -0
- data/lib/bemer/component.rb +19 -0
- data/lib/bemer/component_pack.rb +39 -0
- data/lib/bemer/configuration.rb +36 -0
- data/lib/bemer/context.rb +44 -0
- data/lib/bemer/context_extentions.rb +12 -0
- data/lib/bemer/context_extentions/structure.rb +32 -0
- data/lib/bemer/context_extentions/template.rb +15 -0
- data/lib/bemer/default_template_list.rb +35 -0
- data/lib/bemer/entity.rb +94 -0
- data/lib/bemer/entity_builder.rb +126 -0
- data/lib/bemer/helpers.rb +41 -0
- data/lib/bemer/mixin_list.rb +74 -0
- data/lib/bemer/modifier_list.rb +68 -0
- data/lib/bemer/pipeline.rb +85 -0
- data/lib/bemer/pipeline/handler.rb +132 -0
- data/lib/bemer/predicate.rb +63 -0
- data/lib/bemer/railtie.rb +36 -0
- data/lib/bemer/renderer.rb +15 -0
- data/lib/bemer/tag.rb +35 -0
- data/lib/bemer/tag_builder.rb +11 -0
- data/lib/bemer/template.rb +90 -0
- data/lib/bemer/template_catalog.rb +42 -0
- data/lib/bemer/template_catalog/drawer.rb +31 -0
- data/lib/bemer/template_list.rb +62 -0
- data/lib/bemer/tree.rb +143 -0
- data/lib/bemer/tree/base_node.rb +49 -0
- data/lib/bemer/tree/node.rb +129 -0
- data/lib/bemer/tree/text_node.rb +11 -0
- data/lib/bemer/version.rb +1 -1
- data/spec/bemer/entity_spec.rb +37 -0
- data/spec/bemer/mixin_list_spec.rb +99 -0
- data/spec/bemer/modifier_list_spec.rb +83 -0
- data/spec/bemer_spec.rb +36 -0
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +4 -0
- data/spec/dummy/app/jobs/application_job.rb +4 -0
- data/spec/dummy/app/mailers/application_mailer.rb +6 -0
- data/spec/dummy/app/models/application_record.rb +5 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +5 -0
- data/spec/dummy/bin/rails +6 -0
- data/spec/dummy/bin/rake +6 -0
- data/spec/dummy/bin/setup +39 -0
- data/spec/dummy/bin/update +31 -0
- data/spec/dummy/bin/yarn +13 -0
- data/spec/dummy/config.ru +7 -0
- data/spec/dummy/config/application.rb +27 -0
- data/spec/dummy/config/boot.rb +7 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +7 -0
- data/spec/dummy/config/environments/development.rb +51 -0
- data/spec/dummy/config/environments/production.rb +84 -0
- data/spec/dummy/config/environments/test.rb +44 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +7 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +8 -0
- data/spec/dummy/config/initializers/bemer.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
- data/spec/dummy/config/initializers/inflections.rb +17 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +16 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +58 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/config/secrets.yml +32 -0
- data/spec/dummy/config/spring.rb +8 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/package.json +5 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/rails_helper.rb +37 -0
- data/spec/spec_helper.rb +41 -0
- metadata +301 -7
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
module Builders
|
|
5
|
+
class Template
|
|
6
|
+
ALL_METHODS = [*Pipeline::MODES, *Pipeline::ADD_MODES].freeze
|
|
7
|
+
MULTI_ARGUMENT_METHODS = [Pipeline::ADD_CLS_MODE, Pipeline::ADD_MIX_MODE,
|
|
8
|
+
Pipeline::CLS_MODE, Pipeline::MIX_MODE].freeze
|
|
9
|
+
|
|
10
|
+
private_constant :ALL_METHODS, :MULTI_ARGUMENT_METHODS
|
|
11
|
+
|
|
12
|
+
def initialize(templates, block: '*', elem: nil, condition: true, **options)
|
|
13
|
+
@block = block
|
|
14
|
+
@element = elem
|
|
15
|
+
@condition = condition
|
|
16
|
+
@options = options
|
|
17
|
+
@predicate = Bemer::Predicate.new(block: block, elem: elem, condition: condition, **options)
|
|
18
|
+
@templates = templates
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
(ALL_METHODS - MULTI_ARGUMENT_METHODS - Pipeline::STRUCTURE_RELATED_MODES).each do |mode|
|
|
22
|
+
define_method(mode) do |body|
|
|
23
|
+
templates.unshift Bemer::Template.new(mode, body, predicate)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
MULTI_ARGUMENT_METHODS.each do |mode|
|
|
28
|
+
define_method(mode) do |*body|
|
|
29
|
+
body, = *body if body[0].respond_to?(:call)
|
|
30
|
+
|
|
31
|
+
templates.unshift Bemer::Template.new(mode, body, predicate)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Pipeline::STRUCTURE_RELATED_MODES.each do |mode|
|
|
36
|
+
define_method(mode) do |body = nil, &block|
|
|
37
|
+
body = block if block.respond_to?(:call)
|
|
38
|
+
|
|
39
|
+
templates.unshift Bemer::Template.new(mode, body, predicate)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def specify(condition = @condition, block: @block, elem: @element, **new_options)
|
|
44
|
+
block = @block.eql?('*') ? block : @block
|
|
45
|
+
elem = @element.nil? || @element.eql?('*') ? elem : @element
|
|
46
|
+
params = { **new_options, **options, condition: condition, block: block, elem: elem }
|
|
47
|
+
builder = Builders::Template.new(templates, params)
|
|
48
|
+
|
|
49
|
+
block_given? ? yield(builder) : builder
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
protected
|
|
53
|
+
|
|
54
|
+
attr_reader :templates, :predicate, :options
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
module Builders
|
|
5
|
+
class TemplateList
|
|
6
|
+
def initialize(templates)
|
|
7
|
+
@templates = templates
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def block(name = '*', condition = true, **options)
|
|
11
|
+
params = { **options, condition: condition, block: name, elem: nil }
|
|
12
|
+
|
|
13
|
+
builder = Builders::Template.new(templates, params)
|
|
14
|
+
|
|
15
|
+
block_given? ? yield(builder) : builder
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def elem(name = '*', condition = true, block: '*', **options)
|
|
19
|
+
params = { **options, condition: condition, block: block || '*', elem: name }
|
|
20
|
+
|
|
21
|
+
builder = Builders::Template.new(templates, params)
|
|
22
|
+
|
|
23
|
+
block_given? ? yield(builder) : builder
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def match(condition = true, block: '*', elem: '*', **options)
|
|
27
|
+
entities = []
|
|
28
|
+
|
|
29
|
+
entities << { block: block } if need_block?(block, elem)
|
|
30
|
+
entities << { block: block || '*', elem: elem } if need_element?(elem)
|
|
31
|
+
|
|
32
|
+
builders = entities.map do |entity|
|
|
33
|
+
Builders::Template.new(templates, **options, condition: condition, **entity)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
return yield(builders[0], builders[1]) if block_given?
|
|
37
|
+
|
|
38
|
+
builders.length.odd? ? builders[0] : builders
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
protected
|
|
42
|
+
|
|
43
|
+
attr_reader :templates
|
|
44
|
+
|
|
45
|
+
def need_block?(block, element)
|
|
46
|
+
return true if block.eql?('*') && element.eql?('*')
|
|
47
|
+
|
|
48
|
+
!block.nil? && !block.instance_of?(FalseClass) && !need_element?(element)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def need_element?(element)
|
|
52
|
+
!element.nil? && !element.instance_of?(FalseClass)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/dependencies/autoload'
|
|
4
|
+
|
|
5
|
+
module Bemer
|
|
6
|
+
module Builders
|
|
7
|
+
class Tree
|
|
8
|
+
extend ActiveSupport::Autoload
|
|
9
|
+
|
|
10
|
+
eager_autoload do
|
|
11
|
+
autoload :Element
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(tree)
|
|
15
|
+
@tree = tree
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def block(name = '', **options, &content)
|
|
19
|
+
tree.add_node(name, options, &content)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def elem(block = '', name = '', **options, &content)
|
|
23
|
+
tree.add_node(block, name, options, &content)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def text(content = nil, &callback)
|
|
27
|
+
tree.add_text_node(content, &callback)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
attr_reader :tree
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
module Builders
|
|
5
|
+
class Tree
|
|
6
|
+
class Element
|
|
7
|
+
def initialize(tree, block)
|
|
8
|
+
@tree = tree
|
|
9
|
+
@block = block
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def elem(name = '', **options, &content)
|
|
13
|
+
tree.add_node(block, name, options, &content)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
attr_reader :tree, :block
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
class CommonTemplate
|
|
5
|
+
attr_reader :mode
|
|
6
|
+
|
|
7
|
+
def initialize(mode)
|
|
8
|
+
@mode = mode.to_s.sub('add_', '').to_sym
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def apply!(node)
|
|
12
|
+
case mode
|
|
13
|
+
when Pipeline::REPLACE_MODE then replace!(node)
|
|
14
|
+
when Pipeline::CONTENT_MODE then node.add_child_nodes
|
|
15
|
+
else node.public_send(mode)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def replace!(node)
|
|
22
|
+
node.need_replace = true
|
|
23
|
+
|
|
24
|
+
node.replacers << node.dup
|
|
25
|
+
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
class Component
|
|
5
|
+
def initialize(view)
|
|
6
|
+
@template_catalog = view.instance_variable_get(:@bemer_template_catalog)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def render(**options, &block)
|
|
10
|
+
return if !block_given? || template_catalog.nil?
|
|
11
|
+
|
|
12
|
+
Tree.new(template_catalog, options).render(&block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
protected
|
|
16
|
+
|
|
17
|
+
attr_reader :template_catalog
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
class ComponentPack
|
|
5
|
+
def initialize(view)
|
|
6
|
+
@view = view
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def render
|
|
10
|
+
return unless block_given?
|
|
11
|
+
|
|
12
|
+
create_template_catalog!
|
|
13
|
+
|
|
14
|
+
yield
|
|
15
|
+
|
|
16
|
+
remove_template_catalog!
|
|
17
|
+
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
protected
|
|
22
|
+
|
|
23
|
+
attr_reader :view
|
|
24
|
+
|
|
25
|
+
def create_template_catalog!
|
|
26
|
+
return unless view.instance_variable_get(:@bemer_template_catalog).nil?
|
|
27
|
+
|
|
28
|
+
view.assign(bemer_template_catalog: TemplateCatalog.new(object_id))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def remove_template_catalog!
|
|
32
|
+
template_catalog = view.instance_variable_get(:@bemer_template_catalog)
|
|
33
|
+
|
|
34
|
+
return if template_catalog.nil? || !template_catalog.owner.eql?(object_id)
|
|
35
|
+
|
|
36
|
+
view.remove_instance_variable(:@bemer_template_catalog)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'singleton'
|
|
4
|
+
|
|
5
|
+
module Bemer
|
|
6
|
+
class Configuration
|
|
7
|
+
include Singleton
|
|
8
|
+
|
|
9
|
+
attr_accessor :bem, :default_block_tag, :default_element_tag, :default_path_prefix,
|
|
10
|
+
:element_name_separator, :modifier_name_separator, :modifier_value_separator,
|
|
11
|
+
:prepend_asset_paths, :paths, :asset_paths
|
|
12
|
+
attr_reader :can_use_new_matcher
|
|
13
|
+
attr_writer :path
|
|
14
|
+
|
|
15
|
+
alias can_use_new_matcher? can_use_new_matcher
|
|
16
|
+
|
|
17
|
+
def initialize # rubocop:disable Metrics/MethodLength
|
|
18
|
+
@asset_paths = []
|
|
19
|
+
@bem = false
|
|
20
|
+
@can_use_new_matcher = RUBY_VERSION >= '2.4.0'
|
|
21
|
+
@default_block_tag = :div
|
|
22
|
+
@default_element_tag = :div
|
|
23
|
+
@default_path_prefix = nil
|
|
24
|
+
@element_name_separator = '__'
|
|
25
|
+
@modifier_name_separator = '_'
|
|
26
|
+
@modifier_value_separator = '_'
|
|
27
|
+
@path = 'app/bemer_components'
|
|
28
|
+
@paths = []
|
|
29
|
+
@prepend_asset_paths = true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def path
|
|
33
|
+
Rails.root.join(@path)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
5
|
+
module Bemer
|
|
6
|
+
class Context
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
def_delegators :node, :bem, :bem_cascade, :block, :elem, :first?, :last?, :name, :position, :tag
|
|
10
|
+
|
|
11
|
+
def initialize(node, template = nil)
|
|
12
|
+
@node = node
|
|
13
|
+
@template = template
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def params
|
|
17
|
+
@params ||= Hash[node.params]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def attrs
|
|
21
|
+
@attrs ||= Hash[node.attrs]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def cls
|
|
25
|
+
@cls ||= node.cls.dup
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def js
|
|
29
|
+
@js ||= node.js.dup
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def mix
|
|
33
|
+
@mix ||= node.mix.dup
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def mods
|
|
37
|
+
@mods ||= ActiveSupport::HashWithIndifferentAccess[node.mods]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
protected
|
|
41
|
+
|
|
42
|
+
attr_reader :template, :node
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
module ContextExtentions
|
|
5
|
+
module Structure
|
|
6
|
+
def content(**options)
|
|
7
|
+
old_params = Hash[node.params]
|
|
8
|
+
|
|
9
|
+
node.params.merge!(options)
|
|
10
|
+
|
|
11
|
+
output = node.add_child_nodes
|
|
12
|
+
node.params = old_params
|
|
13
|
+
|
|
14
|
+
output
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ctx(**options)
|
|
18
|
+
duplicate = node.dup
|
|
19
|
+
|
|
20
|
+
duplicate.params.merge!(options)
|
|
21
|
+
|
|
22
|
+
bem_cascade = node.tree.parent_node.bem_cascade
|
|
23
|
+
duplicate.entity.bem_cascade = bem_cascade
|
|
24
|
+
duplicate.entity_builder.bem_cascade = bem_cascade
|
|
25
|
+
|
|
26
|
+
node.tree.add(duplicate)
|
|
27
|
+
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
module ContextExtentions
|
|
5
|
+
module Template
|
|
6
|
+
def apply_next(**options)
|
|
7
|
+
node.apply_next(template, options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def apply(mode, **options)
|
|
11
|
+
node.apply(mode, template, options)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bemer
|
|
4
|
+
class DefaultTemplateList
|
|
5
|
+
def initialize(view, cached = true)
|
|
6
|
+
@path = ''
|
|
7
|
+
@view = view
|
|
8
|
+
@cached = cached
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def compile(&block)
|
|
12
|
+
template_catalog.add(path, cached, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
protected
|
|
16
|
+
|
|
17
|
+
attr_reader :cached, :path, :view
|
|
18
|
+
|
|
19
|
+
def template_catalog
|
|
20
|
+
template_catalog = view.instance_variable_get(:@bemer_template_catalog)
|
|
21
|
+
|
|
22
|
+
return template_catalog unless template_catalog.nil?
|
|
23
|
+
|
|
24
|
+
build_template_catalog!
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def build_template_catalog!
|
|
28
|
+
template_catalog = TemplateCatalog.new(object_id)
|
|
29
|
+
|
|
30
|
+
view.assign(bemer_template_catalog: template_catalog)
|
|
31
|
+
|
|
32
|
+
template_catalog
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|