multi_version_common_cartridge 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.rubocop.yml +54 -0
- data/Gemfile +2 -0
- data/LICENSE +674 -0
- data/README.md +36 -0
- data/lib/multi_version_common_cartridge.rb +38 -0
- data/lib/multi_version_common_cartridge/cartridge.rb +53 -0
- data/lib/multi_version_common_cartridge/cartridge_versions.rb +25 -0
- data/lib/multi_version_common_cartridge/item.rb +29 -0
- data/lib/multi_version_common_cartridge/manifest.rb +33 -0
- data/lib/multi_version_common_cartridge/resources/basic_lti_link.rb +46 -0
- data/lib/multi_version_common_cartridge/resources/resource.rb +23 -0
- data/lib/multi_version_common_cartridge/sax_machine_nokogiri_xml_saver.rb +85 -0
- data/lib/multi_version_common_cartridge/version.rb +19 -0
- data/lib/multi_version_common_cartridge/writers/basic_lti_extension_writer.rb +45 -0
- data/lib/multi_version_common_cartridge/writers/basic_lti_link_writer.rb +241 -0
- data/lib/multi_version_common_cartridge/writers/basic_lti_vendor_writer.rb +66 -0
- data/lib/multi_version_common_cartridge/writers/cartridge_writer.rb +85 -0
- data/lib/multi_version_common_cartridge/writers/factory.rb +59 -0
- data/lib/multi_version_common_cartridge/writers/item_writer.rb +60 -0
- data/lib/multi_version_common_cartridge/writers/manifest_metadata_writer.rb +62 -0
- data/lib/multi_version_common_cartridge/writers/manifest_organization_writer.rb +67 -0
- data/lib/multi_version_common_cartridge/writers/manifest_resources_writer.rb +48 -0
- data/lib/multi_version_common_cartridge/writers/manifest_writer.rb +88 -0
- data/lib/multi_version_common_cartridge/writers/resource_writer.rb +53 -0
- data/lib/multi_version_common_cartridge/writers/supported_versions.rb +37 -0
- data/lib/multi_version_common_cartridge/xml_definitions.rb +149 -0
- data/multi_version_common_cartridge.gemspec +27 -0
- metadata +163 -0
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
A gem for writing different versions of Common Cartridges.
|
3
|
+
|
4
|
+
It supports Common Cartridge version 1.1, 1.2, 1.3 and Thin CC version 1.2 and 1.3.
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
``` ruby
|
8
|
+
# Create a Common Cartridge
|
9
|
+
cartridge = MultiVersionCommonCartridge::Cartridge.new
|
10
|
+
cartridge.manifest.set_title('My cartridge')
|
11
|
+
cartridge.items = [
|
12
|
+
MultiVersionCommonCartridge::Item.new.tap do |item|
|
13
|
+
item.title = 'My activity'
|
14
|
+
item.identifier = 'Some identifier'
|
15
|
+
item.resource = MultiVersionCommonCartridge::Resources::BasicLtiLink::BasicLtiLink.new.tap do |lti|
|
16
|
+
lti.title = 'My activity title'
|
17
|
+
lti.identiier = 'My activity identifier'
|
18
|
+
lti.scure_launch_url = 'https://example.com/lti'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
]
|
22
|
+
|
23
|
+
# Create a Common Cartridge writer for version 1.2.0
|
24
|
+
writer = MultiVersionCommonCartridge::Writers::CartridgeWriter.new(
|
25
|
+
cartridge, '1.2.0'
|
26
|
+
end
|
27
|
+
|
28
|
+
# Finalize the Common Cartridge for the specified version.
|
29
|
+
writer.finalize
|
30
|
+
|
31
|
+
# Check for error
|
32
|
+
return if writer.errors?
|
33
|
+
|
34
|
+
# Write the Common Cartridge
|
35
|
+
writer.write_to_zip('cartridge.imscc')
|
36
|
+
```
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'multi_version_common_cartridge/version'
|
18
|
+
require 'multi_version_common_cartridge/sax_machine_nokogiri_xml_saver'
|
19
|
+
|
20
|
+
require 'multi_version_common_cartridge/cartridge_versions'
|
21
|
+
require 'multi_version_common_cartridge/item'
|
22
|
+
require 'multi_version_common_cartridge/resources/resource'
|
23
|
+
require 'multi_version_common_cartridge/resources/basic_lti_link'
|
24
|
+
require 'multi_version_common_cartridge/manifest'
|
25
|
+
require 'multi_version_common_cartridge/cartridge'
|
26
|
+
require 'multi_version_common_cartridge/xml_definitions'
|
27
|
+
require 'multi_version_common_cartridge/writers/supported_versions'
|
28
|
+
require 'multi_version_common_cartridge/writers/item_writer'
|
29
|
+
require 'multi_version_common_cartridge/writers/resource_writer'
|
30
|
+
require 'multi_version_common_cartridge/writers/basic_lti_vendor_writer'
|
31
|
+
require 'multi_version_common_cartridge/writers/basic_lti_extension_writer'
|
32
|
+
require 'multi_version_common_cartridge/writers/basic_lti_link_writer'
|
33
|
+
require 'multi_version_common_cartridge/writers/manifest_writer'
|
34
|
+
require 'multi_version_common_cartridge/writers/manifest_metadata_writer'
|
35
|
+
require 'multi_version_common_cartridge/writers/manifest_organization_writer'
|
36
|
+
require 'multi_version_common_cartridge/writers/manifest_resources_writer'
|
37
|
+
require 'multi_version_common_cartridge/writers/cartridge_writer'
|
38
|
+
require 'multi_version_common_cartridge/writers/factory'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
class Cartridge
|
19
|
+
attr_accessor :items
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@items = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def manifest
|
26
|
+
@manifest ||= Manifest.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_item(item)
|
30
|
+
@items << item
|
31
|
+
end
|
32
|
+
|
33
|
+
def all_items
|
34
|
+
@all_items ||= begin
|
35
|
+
@items.each_with_object([]) do |item, memo|
|
36
|
+
memo << item
|
37
|
+
child_items(item, memo)
|
38
|
+
end
|
39
|
+
end.flatten
|
40
|
+
end
|
41
|
+
|
42
|
+
def all_resources
|
43
|
+
@all_resources ||= all_items.map(&:resource).compact
|
44
|
+
end
|
45
|
+
|
46
|
+
private def child_items(item, memo)
|
47
|
+
item.children.each do |child|
|
48
|
+
memo << child
|
49
|
+
child_items(child, memo)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
module CartridgeVersions
|
19
|
+
CC_1_1_0 = '1.1.0'.freeze
|
20
|
+
CC_1_2_0 = '1.2.0'.freeze
|
21
|
+
CC_1_3_0 = '1.3.0'.freeze
|
22
|
+
THIN_CC_1_2_0 = 'Thin 1.2.0'.freeze
|
23
|
+
THIN_CC_1_3_0 = 'Thin 1.3.0'.freeze
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
class Item
|
19
|
+
attr_accessor :title, :identifier, :resource, :children
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@children = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_item(item)
|
26
|
+
children << item
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
class Manifest
|
19
|
+
attr_accessor :identifier, :titles, :description, :organization_identifier
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@titles = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_title(title, language: 'en-US')
|
26
|
+
titles[language] = title
|
27
|
+
end
|
28
|
+
|
29
|
+
def title(language)
|
30
|
+
titles[language]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
module Resources
|
19
|
+
module BasicLtiLink
|
20
|
+
class Vendor
|
21
|
+
attr_accessor :code, :name, :description, :url, :contact_email
|
22
|
+
end
|
23
|
+
|
24
|
+
class BasicLtiLink < MultiVersionCommonCartridge::Resources::Resource
|
25
|
+
attr_accessor :title, :description, :secure_launch_url, :extensions
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@extensions = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def vendor
|
32
|
+
@vendor ||= Vendor.new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Extension
|
37
|
+
attr_accessor :platform, :properties
|
38
|
+
|
39
|
+
def initialize(platform)
|
40
|
+
@platform = platform
|
41
|
+
@properties = {}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
module Resources
|
19
|
+
class Resource
|
20
|
+
attr_accessor :identifier
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
class SaxMachineNokogiriXmlSaver
|
18
|
+
def save(builder, object, name)
|
19
|
+
sax_config = sax_config_for(object)
|
20
|
+
unless sax_config
|
21
|
+
builder.send(name, object)
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
attrs = xml_attributes(object, sax_config)
|
26
|
+
content = xml_content(object, sax_config)
|
27
|
+
create_xml_node(builder, name, content, attrs) do |xml_element|
|
28
|
+
sax_config.top_level_elements.each do |_, configs|
|
29
|
+
configs.each do |config|
|
30
|
+
as = config.instance_variable_get(:@as)
|
31
|
+
save(xml_element, object.send(as), config.name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
sax_config.collection_elements.each do |_, configs|
|
36
|
+
configs.each do |config|
|
37
|
+
as = config.instance_variable_get(:@as)
|
38
|
+
object.send(as).each do |elm|
|
39
|
+
save(xml_element, elm, config.name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private def xml_attributes(object, sax_config)
|
47
|
+
attrs = sax_config.top_level_attributes.map do |attr|
|
48
|
+
[attr.name, object.send(attr.instance_variable_get(:@as))]
|
49
|
+
end.to_h
|
50
|
+
attrs.delete_if { |_, v| v.nil? }
|
51
|
+
end
|
52
|
+
|
53
|
+
private def xml_content(object, sax_config)
|
54
|
+
return if sax_config.top_level_element_value.empty?
|
55
|
+
element_value_config = sax_config.top_level_element_value.last
|
56
|
+
object.send(element_value_config.name)
|
57
|
+
end
|
58
|
+
|
59
|
+
private def create_xml_node(builder, name, content, attrs, &block)
|
60
|
+
if name.include?(':')
|
61
|
+
namespace, name = name.split(':', 2)
|
62
|
+
create_xml_element(builder[namespace], name, content, attrs, &block)
|
63
|
+
else
|
64
|
+
create_xml_element(builder, name, content, attrs, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private def create_xml_element(builder, name, content, attrs, &block)
|
69
|
+
if content
|
70
|
+
builder.send(name, content, attrs) do |xml_element|
|
71
|
+
yield xml_element
|
72
|
+
end
|
73
|
+
else
|
74
|
+
builder.send(name, attrs) do |xml_element|
|
75
|
+
yield xml_element
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private def sax_config_for(object)
|
81
|
+
if object.class.respond_to?(:sax_config)
|
82
|
+
object.class.sax_config
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
VERSION = '1.0.0'.freeze
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# multi_version_common_cartridge
|
2
|
+
# Copyright © 2019 Vista Higher Learning, Inc.
|
3
|
+
#
|
4
|
+
# multi_version_common_cartridge is free software: you can redistribute it
|
5
|
+
# and/or modify it under the terms of the GNU General Public
|
6
|
+
# License as published by the Free Software Foundation, either
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# multi_version_common_cartridge is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with multi_version_common_cartridge. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module MultiVersionCommonCartridge
|
18
|
+
module Writers
|
19
|
+
class BasicLtiExtensionWriter
|
20
|
+
include SupportedVersions
|
21
|
+
|
22
|
+
attr_reader :extension
|
23
|
+
|
24
|
+
def initialize(extension, version)
|
25
|
+
@extension = extension
|
26
|
+
@version = validate_version(version)
|
27
|
+
end
|
28
|
+
|
29
|
+
def finalize
|
30
|
+
end
|
31
|
+
|
32
|
+
def extension_element
|
33
|
+
@extension_element ||= CommonCartridge::Elements::Resources::BasicLtiLink::Extension.new.tap do |element|
|
34
|
+
element.platform = extension.platform
|
35
|
+
element.properties = extension.properties.map do |key, value|
|
36
|
+
CommonCartridge::Elements::Resources::BasicLtiLink::ExtensionProperty.new(
|
37
|
+
name: key, value: value
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|