abc 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/.travis.yml +28 -0
- data/.yardopts +8 -0
- data/Gemfile +16 -0
- data/LICENSE +27 -0
- data/README.md +72 -0
- data/Rakefile +1 -0
- data/abc.gemspec +20 -0
- data/adapters/Gemfile +19 -0
- data/adapters/Rakefile +1 -0
- data/adapters/abc-adapters.gemspec +24 -0
- data/adapters/abc/adapters/persistence/repositories/base.rb +43 -0
- data/adapters/abc/adapters/persistence/repositories/page.rb +18 -0
- data/adapters/abc/adapters/persistence/repositories/text.rb +18 -0
- data/adapters/lib/abc-adapters.rb +17 -0
- data/adapters/lib/adapters/config.rb +29 -0
- data/adapters/spec/adapters/persistence/repositories/base_spec.rb +45 -0
- data/adapters/spec/adapters/persistence/repositories/page_spec.rb +15 -0
- data/adapters/spec/adapters/persistence/repositories/text_spec.rb +15 -0
- data/adapters/spec/lib/adapters/config_spec.rb +30 -0
- data/adapters/spec/spec_helper.rb +10 -0
- data/contributing.md +66 -0
- data/core/Gemfile +20 -0
- data/core/Guardfile +6 -0
- data/core/Rakefile +1 -0
- data/core/abc-core.gemspec +22 -0
- data/core/abc/entities/content/text.rb +19 -0
- data/core/abc/entities/menu/menu.rb +16 -0
- data/core/abc/entities/menu/menu_entry.rb +20 -0
- data/core/abc/entities/menu/menuable.rb +6 -0
- data/core/abc/entities/menu/path.rb +17 -0
- data/core/abc/entities/pages/page.rb +16 -0
- data/core/abc/entities/view/viewable.rb +7 -0
- data/core/abc/entities/view/viewable_presenter.rb +9 -0
- data/core/abc/interactors/creates_menu.rb +23 -0
- data/core/abc/interactors/pages/builds_page.rb +21 -0
- data/core/lib/abc-core.rb +1 -0
- data/core/spec/entities/content/text_spec.rb +37 -0
- data/core/spec/entities/menu/menu_entry_spec.rb +11 -0
- data/core/spec/entities/menu/menu_spec.rb +17 -0
- data/core/spec/entities/menu/menuable_spec.rb +7 -0
- data/core/spec/entities/menu/path_spec.rb +8 -0
- data/core/spec/entities/pages/page_spec.rb +19 -0
- data/core/spec/entities/view/viewable_presenter_spec.rb +7 -0
- data/core/spec/entities/view/viewable_spec.rb +7 -0
- data/core/spec/interactors/creates_menu_spec.rb +31 -0
- data/core/spec/interactors/pages/builds_page_spec.rb +15 -0
- data/core/spec/spec_helper.rb +10 -0
- data/delivery/backend/Gemfile +44 -0
- data/delivery/backend/Guardfile +6 -0
- data/delivery/backend/Rakefile +1 -0
- data/delivery/backend/abc-backend.gemspec +26 -0
- data/delivery/backend/app/controllers/abc/application_controller.rb +6 -0
- data/delivery/backend/app/controllers/abc/backend/base_controller.rb +8 -0
- data/delivery/backend/app/presenters/abc/html/menu_entry_presenter.rb +87 -0
- data/delivery/backend/app/presenters/abc/html/menu_presenter.rb +68 -0
- data/delivery/backend/app/views/abc/backend/base/index.html.erb +1 -0
- data/delivery/backend/config.ru +6 -0
- data/delivery/backend/config/routes.rb +3 -0
- data/delivery/backend/lib/abc-backend.rb +2 -0
- data/delivery/backend/lib/abc/backend/engine.rb +7 -0
- data/delivery/backend/spec/integration/backend_spec.rb +10 -0
- data/delivery/backend/spec/integration/menu_spec.rb +18 -0
- data/delivery/backend/spec/internal/config/database.yml +3 -0
- data/delivery/backend/spec/internal/config/routes.rb +5 -0
- data/delivery/backend/spec/internal/db/schema.rb +3 -0
- data/delivery/backend/spec/internal/log/.gitignore +1 -0
- data/delivery/backend/spec/internal/public/favicon.ico +0 -0
- data/delivery/backend/spec/presenters/html/menu_entry_presenter_spec.rb +49 -0
- data/delivery/backend/spec/presenters/html/menu_presenter_spec.rb +74 -0
- data/delivery/backend/spec/spec_helper.rb +14 -0
- data/delivery/backend/spec/tiny_spec_helper.rb +13 -0
- data/delivery/frontend/Gemfile +45 -0
- data/delivery/frontend/Guardfile +6 -0
- data/delivery/frontend/Rakefile +1 -0
- data/delivery/frontend/abc-frontend.gemspec +29 -0
- data/delivery/frontend/app/conductors/abc/frontend/conductors/shows_page.rb +69 -0
- data/delivery/frontend/app/controllers/abc/application_controller.rb +6 -0
- data/delivery/frontend/app/controllers/abc/frontend/base_controller.rb +8 -0
- data/delivery/frontend/app/controllers/abc/frontend/pages_controller.rb +12 -0
- data/delivery/frontend/app/presenters/abc/html/page_presenter.rb +13 -0
- data/delivery/frontend/app/views/abc/frontend/base/index.html.erb +1 -0
- data/delivery/frontend/app/views/abc/frontend/pages/show.html.haml +1 -0
- data/delivery/frontend/config.ru +6 -0
- data/delivery/frontend/config/routes.rb +5 -0
- data/delivery/frontend/lib/abc-frontend.rb +3 -0
- data/delivery/frontend/lib/abc/frontend/engine.rb +7 -0
- data/delivery/frontend/spec/conductors/abc/frontend/shows_page_spec.rb +41 -0
- data/delivery/frontend/spec/integration/backend_spec.rb +10 -0
- data/delivery/frontend/spec/integration/pages_spec.rb +11 -0
- data/delivery/frontend/spec/internal/config/database.yml +3 -0
- data/delivery/frontend/spec/internal/config/routes.rb +5 -0
- data/delivery/frontend/spec/internal/db/schema.rb +3 -0
- data/delivery/frontend/spec/internal/log/.gitignore +1 -0
- data/delivery/frontend/spec/internal/public/favicon.ico +0 -0
- data/delivery/frontend/spec/presenters/html/page_presenter_spec.rb +19 -0
- data/delivery/frontend/spec/spec_helper.rb +15 -0
- data/delivery/frontend/spec/tiny_spec_helper.rb +14 -0
- data/documentation/architecture.md +131 -0
- data/documentation/architecture.png +0 -0
- data/documentation/architecture.svg +1192 -0
- data/lib/abc.rb +7 -0
- data/lib/abc/base_conductor.rb +63 -0
- data/lib/abc/base_conductor_spec.rb +9 -0
- data/lib/abc/base_interactor.rb +17 -0
- data/lib/abc/package.rb +11 -0
- data/script/bundle +2 -0
- data/script/projects +2 -0
- data/script/rspec +2 -0
- data/script/run +8 -0
- data/spec/lib/abc/base_interactor_spec.rb +11 -0
- data/spec/shared/callable.rb +24 -0
- data/yard/setup.rb +10 -0
- data/yard/templates/default/fulldoc/html/css/common.css +109 -0
- data/yard/templates/default/layout/html/layout.erb +56 -0
- metadata +163 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'abc/entities/pages/page'
|
3
|
+
|
4
|
+
module Abc
|
5
|
+
module Entities
|
6
|
+
describe Page do
|
7
|
+
let(:title) { "Afterburner" }
|
8
|
+
subject { Page.new(title) }
|
9
|
+
|
10
|
+
it "has a title" do
|
11
|
+
subject.title.should == title
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can be hashified" do
|
15
|
+
subject.to_hash.should == {:title => title}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'abc/interactors/creates_menu'
|
3
|
+
|
4
|
+
module Abc
|
5
|
+
module Interactors
|
6
|
+
describe CreatesMenu do
|
7
|
+
let(:menu_entries) do
|
8
|
+
[{:title => "One", :children => [{ :title => "One first child"}]}]
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".new" do
|
12
|
+
it "creates new menu" do
|
13
|
+
menu_creator = CreatesMenu.send(:new, [])
|
14
|
+
expect(menu_creator.to_response).to be_kind_of(Abc::Menu)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "adds menu entries to menu" do
|
18
|
+
menu_creator = CreatesMenu.send(:new, menu_entries)
|
19
|
+
menu_creator.menu.entries.each do |menu_entry|
|
20
|
+
expect(menu_entry).to be_kind_of(Abc::MenuEntry)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns a menu" do
|
26
|
+
menu_creator = CreatesMenu.call(menu_entries)
|
27
|
+
expect(menu_creator).to be_kind_of(Abc::Menu)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'abc/interactors/pages/builds_page'
|
3
|
+
|
4
|
+
module Abc
|
5
|
+
module Interactors
|
6
|
+
describe BuildsPage do
|
7
|
+
let(:data) {{:title => "More like Awesome-burner, amirite??"}}
|
8
|
+
|
9
|
+
it "returns a page" do
|
10
|
+
builder = BuildsPage.call(data)
|
11
|
+
expect(builder).to be_kind_of(Abc::Entities::Page)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
git 'git://github.com/rails/rails.git' do
|
6
|
+
gem 'railties'
|
7
|
+
gem 'actionpack'
|
8
|
+
gem 'activemodel'
|
9
|
+
end
|
10
|
+
|
11
|
+
group :test do
|
12
|
+
gem 'rspec'
|
13
|
+
gem 'rspec-rails', :require => false
|
14
|
+
unless ENV['TRAVIS']
|
15
|
+
gem 'simplecov'
|
16
|
+
end
|
17
|
+
gem 'capybara'
|
18
|
+
platforms :jruby do
|
19
|
+
gem 'activerecord-jdbcsqlite3-adapter'
|
20
|
+
end
|
21
|
+
|
22
|
+
platforms :ruby do
|
23
|
+
gem 'sqlite3'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
group :development, :test do
|
28
|
+
gem 'combustion', github: 'pat/combustion'
|
29
|
+
unless ENV['TRAVIS']
|
30
|
+
gem 'pry'
|
31
|
+
gem 'pry-nav'
|
32
|
+
gem 'guard-shell'
|
33
|
+
gem 'rb-fsevent', '~> 0.9', :platform => :ruby
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
group :development do
|
38
|
+
gem 'yard', "~> 0.8.4.1"
|
39
|
+
gem 'rdoc'
|
40
|
+
gem 'kramdown'
|
41
|
+
end
|
42
|
+
|
43
|
+
gem 'abc', :path => '../../'
|
44
|
+
gem 'abc-core', :path => '../../core'
|
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../../lib/abc/package', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
# Describe your gem and declare its dependencies:
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "abc-backend"
|
6
|
+
s.version = Abc::VERSION
|
7
|
+
s.authors = Abc::AUTHORS
|
8
|
+
s.email = Abc::EMAILS
|
9
|
+
s.homepage = Abc::HOMEPAGE
|
10
|
+
s.summary = Abc::SUMMARY
|
11
|
+
s.description = Abc::DESCRIPTION
|
12
|
+
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
|
15
|
+
s.files = Dir['app/**/*', 'lib/**/*', 'config/**/*', 'spec/**/*']
|
16
|
+
s.test_files = s.files.grep(%r{^(spec)/})
|
17
|
+
|
18
|
+
s.required_ruby_version = '>= 1.9.3' # that's right.
|
19
|
+
|
20
|
+
s.add_dependency 'railties', Abc::RAILS_VERSION
|
21
|
+
s.add_dependency 'activesupport', Abc::RAILS_VERSION
|
22
|
+
s.add_dependency 'actionpack', Abc::RAILS_VERSION
|
23
|
+
s.add_dependency 'activemodel', Abc::RAILS_VERSION
|
24
|
+
s.add_dependency 'abc', Abc::VERSION
|
25
|
+
s.add_dependency 'abc-core', Abc::VERSION
|
26
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
|
3
|
+
module Abc
|
4
|
+
module Html
|
5
|
+
class MenuEntryPresenter
|
6
|
+
include ActionView::Helpers::TagHelper
|
7
|
+
include ActionView::Context # Nested content_tags
|
8
|
+
|
9
|
+
attr_accessor :menu_entry, :list_element_pair
|
10
|
+
|
11
|
+
def initialize(menu_entry, options = {})
|
12
|
+
options = {:list_element_pair => [:ul, :li]}.merge(options)
|
13
|
+
self.menu_entry = menu_entry
|
14
|
+
self.list_element_pair = options[:list_element_pair]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Renders a menu item in HTML format, and, if it has children, renders those too.
|
18
|
+
#
|
19
|
+
# **A note on HTML safety:**
|
20
|
+
#
|
21
|
+
# It is up to each menu item presenter to check that it is rendering itself safely.
|
22
|
+
# By default, most of the menu has to be declared safe, or else its
|
23
|
+
# constituent tags won't render properly. So we declare vast swaths of the
|
24
|
+
# menu HTML safe, and in truth these parts are. The parts that
|
25
|
+
# need to be especially watched are any spots where you render user input.
|
26
|
+
# By design, that surface is constrained to the `render_as_html` method.
|
27
|
+
# You must, however, return a string marked with html_safe from that method
|
28
|
+
# or else the menu will raise `ActiveSupport::SafeBuffer::SafeConcatError`.
|
29
|
+
#
|
30
|
+
# (This doesn't meant that the entire string must be unsanitized; just that
|
31
|
+
# you must make assurances that your content is appropriately escaped. By
|
32
|
+
# default, ABC uses `ERB::Util#h` to sanitize the user-interpreted parts, but
|
33
|
+
# your derivative classes may have to implement this on their own.)
|
34
|
+
#
|
35
|
+
# @return [SafeBuffer] A safe string containing the MenuEntry and its children.
|
36
|
+
def to_html
|
37
|
+
content = render_as_html
|
38
|
+
raise ActiveSupport::SafeBuffer::SafeConcatError unless content.html_safe?
|
39
|
+
|
40
|
+
content_tag(list_element_tag) do
|
41
|
+
if menu_entry_children.present?
|
42
|
+
render_with_children_as_html content
|
43
|
+
else
|
44
|
+
content
|
45
|
+
end
|
46
|
+
end.html_safe
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
# Renders this menu item and its children with the assumption it has children.
|
52
|
+
#
|
53
|
+
# @param content [SafeBuffer] A safe string to use as the content of this, the parent {MenuEntry.
|
54
|
+
# @return [SafeBuffer] A safe string to be rendered by the parent {Menu} or {MenuEntry}.
|
55
|
+
def render_with_children_as_html(content)
|
56
|
+
content.safe_concat(
|
57
|
+
content_tag(list_container_tag) do
|
58
|
+
menu_entry_children.reduce(::ActiveSupport::SafeBuffer.new) do |buffer, child|
|
59
|
+
child_presenter = self.class.new(child, :list_element_pair => list_element_pair)
|
60
|
+
buffer.safe_concat child_presenter.to_html
|
61
|
+
end
|
62
|
+
end.html_safe
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def list_container_tag
|
67
|
+
list_element_pair.first
|
68
|
+
end
|
69
|
+
|
70
|
+
def list_element_tag
|
71
|
+
list_element_pair.last
|
72
|
+
end
|
73
|
+
|
74
|
+
# Render this {MenuItem} without children.
|
75
|
+
#
|
76
|
+
# **NB**: ERB::Util#h will mark a string as safe.
|
77
|
+
#
|
78
|
+
# @returns [SafeBuffer] A safe string to be rendered or appended with children.
|
79
|
+
def render_as_html
|
80
|
+
ERB::Util.h menu_entry_title
|
81
|
+
end
|
82
|
+
|
83
|
+
delegate :children, :to => :menu_entry, :allow_nil => true, :prefix => true
|
84
|
+
delegate :title, :to => :menu_entry, :prefix => true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
|
4
|
+
module Abc
|
5
|
+
module Html
|
6
|
+
class MenuPresenter
|
7
|
+
include ActionView::Helpers::TagHelper
|
8
|
+
include ActionView::Context
|
9
|
+
|
10
|
+
attr_accessor :menu, :menu_element, :list_element_pair, :menu_entry_presenter_class
|
11
|
+
|
12
|
+
def initialize(menu, options = {})
|
13
|
+
options = default_initialize_options.merge(options)
|
14
|
+
|
15
|
+
self.menu = menu
|
16
|
+
self.menu_element = options[:menu_element]
|
17
|
+
self.list_element_pair = options[:list_element_pair]
|
18
|
+
self.menu_entry_presenter_class = options[:menu_entry_presenter_class]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Outputs the menu in HTML format.
|
22
|
+
#
|
23
|
+
# @return An HTML-safe string containing the markup of the menu in question.
|
24
|
+
def to_html
|
25
|
+
content_tag(menu_element) do
|
26
|
+
content_tag(list_container_tag) do
|
27
|
+
# Reduce will concat into a first SafeBuffer here, so if the first
|
28
|
+
# node is html_safe, this will produce expected outcome. And of course,
|
29
|
+
# MenuEntries are expected to be html_safe.
|
30
|
+
menu_entries.reduce(::ActiveSupport::SafeBuffer.new) do |buffer, child|
|
31
|
+
menu_entry_presenter = menu_entry_presenter_class.new(
|
32
|
+
child, :list_element_pair => list_element_pair
|
33
|
+
)
|
34
|
+
buffer.safe_concat menu_entry_presenter.to_html
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end.html_safe
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the elements that are used to determine what contains a series of
|
41
|
+
# children and the actual children itself. Defaults to [:ul, :li].
|
42
|
+
# We sometimes refer to the pair as the container and the enumerator.
|
43
|
+
#
|
44
|
+
# @param pair [Array] A pair of HTML element names
|
45
|
+
def list_element_pair=(pair)
|
46
|
+
raise "List element pair must be an array" unless pair.is_a?(Array)
|
47
|
+
raise "List element pair must specify two element types" unless pair.count == 2
|
48
|
+
raise "List element pair should be symbols" unless pair.all? {|e| e.is_a?(Symbol)}
|
49
|
+
@list_element_pair = pair
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def default_initialize_options
|
54
|
+
{
|
55
|
+
:menu_element => :nav,
|
56
|
+
:list_element_pair => [:ul, :li],
|
57
|
+
:menu_entry_presenter_class => MenuEntryPresenter
|
58
|
+
}.freeze
|
59
|
+
end
|
60
|
+
|
61
|
+
def list_container_tag
|
62
|
+
list_element_pair.first
|
63
|
+
end
|
64
|
+
|
65
|
+
delegate :entries, :to => :menu, :prefix => true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Welcome to Afterburner CMS
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'tiny_spec_helper'
|
2
|
+
require 'interactors/creates_menu'
|
3
|
+
|
4
|
+
describe "Menu" do
|
5
|
+
describe "when using an HTML presenter" do
|
6
|
+
let(:children_for_one) {
|
7
|
+
[{:title => "One first child"}, {:title => "One second child"}]
|
8
|
+
}
|
9
|
+
let(:menu_entries) { [{:title => "One", :children => children_for_one}] }
|
10
|
+
|
11
|
+
let(:menu) { Abc::Interactors::CreatesMenu.call(menu_entries) }
|
12
|
+
let(:present) { Abc::Html::MenuPresenter.new(menu).to_html }
|
13
|
+
|
14
|
+
it "renders properly" do
|
15
|
+
present.should == "<nav><ul><li>One<ul><li>One first child</li><li>One second child</li></ul></li></ul></nav>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
*.log
|
File without changes
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'tiny_spec_helper'
|
2
|
+
require 'presenters/abc/html/menu_entry_presenter'
|
3
|
+
|
4
|
+
class MockMenuEntry
|
5
|
+
attr_accessor :children, :title
|
6
|
+
def initialize(opts = {}); @children = opts[:children] || []; @title = opts[:title]; end
|
7
|
+
def list_element_pair=(_); @list_element_pair = _; end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Abc
|
11
|
+
module Html
|
12
|
+
describe MenuEntryPresenter do
|
13
|
+
let(:menu_item) { MockMenuEntry.new(:title => "Root") }
|
14
|
+
let(:child) { MockMenuEntry.new(:title => "Child") }
|
15
|
+
subject { MenuEntryPresenter.new(menu_item) }
|
16
|
+
|
17
|
+
it "renders itself" do
|
18
|
+
subject.to_html.should == "<li>Root</li>"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "renders with the list enumerator of list_element_pair" do
|
22
|
+
subject.list_element_pair = [:nav, :div]
|
23
|
+
subject.to_html.should == "<div>Root</div>"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "raises an error if its content is not marked html_safe" do
|
27
|
+
subject.stub!(:render_as_html).and_return("unsafe string")
|
28
|
+
expect { subject.to_html }.to raise_error(::ActiveSupport::SafeBuffer::SafeConcatError)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with children" do
|
32
|
+
before(:each) { menu_item.children = [child] }
|
33
|
+
# TODO: Remove this diagnostic spec.
|
34
|
+
it "child count should be one" do
|
35
|
+
subject.menu_entry.children.count.should == 1
|
36
|
+
end
|
37
|
+
|
38
|
+
it "renders its children" do
|
39
|
+
subject.to_html.should == "<li>Root<ul><li>Child</li></ul></li>"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "wraps children in the passed list element" do
|
43
|
+
subject.list_element_pair = [:nav, :div]
|
44
|
+
subject.to_html.should == "<div>Root<nav><div>Child</div></nav></div>"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|