paged_scopes 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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.textile +471 -0
- data/Rakefile +55 -0
- data/VERSION.yml +4 -0
- data/lib/paged_scopes.rb +9 -0
- data/lib/paged_scopes/collection.rb +45 -0
- data/lib/paged_scopes/context.rb +36 -0
- data/lib/paged_scopes/controller.rb +54 -0
- data/lib/paged_scopes/index.rb +62 -0
- data/lib/paged_scopes/pages.rb +194 -0
- data/lib/paged_scopes/paginator.rb +68 -0
- data/lib/paged_scopes/resources.rb +32 -0
- data/paged_scopes.gemspec +72 -0
- data/rails/init.rb +1 -0
- data/spec/collection_spec.rb +66 -0
- data/spec/context_spec.rb +27 -0
- data/spec/controller_spec.rb +234 -0
- data/spec/index_spec.rb +31 -0
- data/spec/page_spec.rb +249 -0
- data/spec/paginator_spec.rb +256 -0
- data/spec/resources_spec.rb +72 -0
- data/spec/spec_helper.rb +160 -0
- metadata +95 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
module PagedScopes
|
2
|
+
class Paginator
|
3
|
+
attr_reader :page
|
4
|
+
|
5
|
+
def initialize(page)
|
6
|
+
@page = page
|
7
|
+
end
|
8
|
+
|
9
|
+
def set_path(&block)
|
10
|
+
@path = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def path
|
14
|
+
@path || raise(RuntimeError, "No path proc supplied.")
|
15
|
+
end
|
16
|
+
|
17
|
+
def previous
|
18
|
+
path.call(@page.previous) unless @page.first?
|
19
|
+
end
|
20
|
+
|
21
|
+
def next
|
22
|
+
path.call(@page.next) unless @page.last?
|
23
|
+
end
|
24
|
+
|
25
|
+
def first
|
26
|
+
path.call(@page.class.first)
|
27
|
+
end
|
28
|
+
|
29
|
+
def last
|
30
|
+
path.call(@page.class.last)
|
31
|
+
end
|
32
|
+
|
33
|
+
def window(options)
|
34
|
+
raise ArgumentError, "No window block supplied." unless block_given?
|
35
|
+
raise ArgumentError, "please specify a :inner option" unless inner = options[:inner]
|
36
|
+
return if @page.page_count < 2
|
37
|
+
outer = options[:outer] || 0
|
38
|
+
extras = [ options[:extras] ].flatten.compact
|
39
|
+
numbers = case
|
40
|
+
when @page.number <= inner + 1
|
41
|
+
1 .. 1 + 2 * inner
|
42
|
+
when @page.number >= @page.page_count - inner
|
43
|
+
@page.page_count - 2 * inner .. @page.page_count
|
44
|
+
else
|
45
|
+
@page.number - inner .. @page.number + inner
|
46
|
+
end.to_a
|
47
|
+
1.upto(outer) { |n| numbers << n << @page.page_count-n+1 }
|
48
|
+
numbers.uniq!
|
49
|
+
numbers.sort!
|
50
|
+
numbers.reject! { |number| !number.between?(1, @page.page_count) }
|
51
|
+
returning [] do |results|
|
52
|
+
results << yield(:first, @page.first? ? nil : first, []) if extras.include?(:first)
|
53
|
+
results << yield(:previous, previous, []) if extras.include?(:previous)
|
54
|
+
numbers.zip([nil]+numbers, numbers[1..-1]) do |number, prev_number, next_number|
|
55
|
+
page = @page.class.find(number)
|
56
|
+
path = page == @page ? nil : @path.call(page)
|
57
|
+
classes = []
|
58
|
+
classes << :selected if page == @page
|
59
|
+
classes << :gap_before if prev_number && prev_number < number - 1
|
60
|
+
classes << :gap_after if next_number && next_number > number + 1
|
61
|
+
results << yield(page, path, classes)
|
62
|
+
end
|
63
|
+
results << yield(:next, self.next, []) if extras.include?(:next)
|
64
|
+
results << yield(:last, @page.last? ? nil : last, []) if extras.include?(:last)
|
65
|
+
end.join("\n")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module PagedScopes
|
2
|
+
module Resources
|
3
|
+
def resources_with_paged(*entities, &block)
|
4
|
+
options = entities.extract_options!
|
5
|
+
if page_options = options.delete(:paged)
|
6
|
+
resources_without_paged(*(entities.dup << options), &block)
|
7
|
+
page_options = {} unless page_options.is_a? Hash
|
8
|
+
page_name = page_options.delete(:name)
|
9
|
+
page_options.slice!(:as, :name)
|
10
|
+
page_options.merge!(:only => :none)
|
11
|
+
preserved_options = ActionController::Resources::INHERITABLE_OPTIONS + [ :name_prefix, :path_prefix ]
|
12
|
+
with_options(options.slice(*preserved_options)) do |map|
|
13
|
+
map.resources_without_paged(page_name || :pages, page_options) do |page|
|
14
|
+
page.resources(*(entities.dup << { :only => :index }))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
else
|
18
|
+
resources_without_paged(*(entities << options), &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(base)
|
23
|
+
base.class_eval do
|
24
|
+
alias_method_chain :resources, :paged
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if defined? ActionController::Resources
|
31
|
+
ActionController::Resources.send :include, PagedScopes::Resources
|
32
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{paged_scopes}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Matthew Hollingworth"]
|
12
|
+
s.date = %q{2009-10-10}
|
13
|
+
s.email = %q{mdholling@gmail.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE",
|
16
|
+
"README.textile"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".document",
|
20
|
+
".gitignore",
|
21
|
+
"LICENSE",
|
22
|
+
"README.textile",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION.yml",
|
25
|
+
"lib/paged_scopes.rb",
|
26
|
+
"lib/paged_scopes/collection.rb",
|
27
|
+
"lib/paged_scopes/context.rb",
|
28
|
+
"lib/paged_scopes/controller.rb",
|
29
|
+
"lib/paged_scopes/index.rb",
|
30
|
+
"lib/paged_scopes/pages.rb",
|
31
|
+
"lib/paged_scopes/paginator.rb",
|
32
|
+
"lib/paged_scopes/resources.rb",
|
33
|
+
"paged_scopes.gemspec",
|
34
|
+
"rails/init.rb",
|
35
|
+
"spec/collection_spec.rb",
|
36
|
+
"spec/context_spec.rb",
|
37
|
+
"spec/controller_spec.rb",
|
38
|
+
"spec/index_spec.rb",
|
39
|
+
"spec/page_spec.rb",
|
40
|
+
"spec/paginator_spec.rb",
|
41
|
+
"spec/resources_spec.rb",
|
42
|
+
"spec/spec_helper.rb"
|
43
|
+
]
|
44
|
+
s.homepage = %q{http://github.com/mholling/paged_scopes}
|
45
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
46
|
+
s.require_paths = ["lib"]
|
47
|
+
s.rubygems_version = %q{1.3.5}
|
48
|
+
s.summary = %q{PagedScopes is an ActiveRecord pagination gem. It lets you easily paginate collection associations and named scopes. It also paginates collections which already have :limit and :offset scopes in place. You can also find the page containing a given object in a collection, and find the next and previous objects for each object in the collection.}
|
49
|
+
s.test_files = [
|
50
|
+
"spec/collection_spec.rb",
|
51
|
+
"spec/context_spec.rb",
|
52
|
+
"spec/controller_spec.rb",
|
53
|
+
"spec/index_spec.rb",
|
54
|
+
"spec/page_spec.rb",
|
55
|
+
"spec/paginator_spec.rb",
|
56
|
+
"spec/resources_spec.rb",
|
57
|
+
"spec/spec_helper.rb"
|
58
|
+
]
|
59
|
+
|
60
|
+
if s.respond_to? :specification_version then
|
61
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
62
|
+
s.specification_version = 3
|
63
|
+
|
64
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
65
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 2.2.1"])
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<activerecord>, [">= 2.2.1"])
|
68
|
+
end
|
69
|
+
else
|
70
|
+
s.add_dependency(%q<activerecord>, [">= 2.2.1"])
|
71
|
+
end
|
72
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'paged_scopes'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe "Collection" do
|
4
|
+
describe "(ActiveRecord::Base class)" do
|
5
|
+
it "should have a per_page setter and getter" do
|
6
|
+
Article.per_page = 5
|
7
|
+
Article.per_page.should == 5
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a default page name of 'Page'" do
|
11
|
+
Article.page_name.should == "Page"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have a page_name setter and getter" do
|
15
|
+
Article.page_name = "Group"
|
16
|
+
Article.page_name.should == "Group"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not have a #pages method" do
|
20
|
+
Article.respond_to?(:pages).should be_false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
[ [ "association", "User.first.articles" ],
|
25
|
+
[ "named scope", "Article.scoped(:conditions => 'title IS NULL')" ] ].each do |collection_type, collection|
|
26
|
+
describe "(#{collection_type})" do
|
27
|
+
before(:each) do
|
28
|
+
@collection = eval(collection)
|
29
|
+
Article.stub!(:per_page).and_return(10)
|
30
|
+
Article.page_name = "Page"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have a default per_page of the ActiveRecord::Base class" do
|
34
|
+
@collection.per_page.should == 10
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have a per_page setter and getter" do
|
38
|
+
@collection.per_page = 20
|
39
|
+
@collection.per_page.should == 20
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not overwrite the ActiveRecord::Base per_page value when per_page is set" do
|
43
|
+
@collection.per_page = 20
|
44
|
+
Article.per_page.should == 10
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have a default page_name of the ActiveRecord::Base class" do
|
48
|
+
@collection.page_name.should == "Page"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should have a page_name setter and getter" do
|
52
|
+
@collection.page_name = "Group"
|
53
|
+
@collection.page_name.should == "Group"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should not overwrite the ActiveRecord::Base page_name value when page_name is set" do
|
57
|
+
@collection.page_name = "Group"
|
58
|
+
Article.page_name.should == "Page"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should have a #pages method" do
|
62
|
+
@collection.respond_to?(:pages).should be_true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe "Context" do
|
4
|
+
in_contexts do
|
5
|
+
it "should know the object after an object obtained with #all" do
|
6
|
+
articles = @articles.all
|
7
|
+
until articles.empty? do
|
8
|
+
articles.shift.next.should == articles.first
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should know the object before an object obtained with #all" do
|
13
|
+
articles = @articles.all
|
14
|
+
until articles.empty? do
|
15
|
+
articles.pop.previous.should == articles.last
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be known for an object obtained with #first" do
|
20
|
+
@articles.all.should have_at_least(2).articles
|
21
|
+
@articles.first.next.should_not be_nil
|
22
|
+
@articles.first.previous.should be_nil
|
23
|
+
end
|
24
|
+
# (For a collection including :limit , this won't work with #last unless the collection
|
25
|
+
# has been evaluated already!)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe "Controller" do
|
4
|
+
|
5
|
+
context "class" do
|
6
|
+
it "should raise 404 on PagedScopes::PageNotFound" do
|
7
|
+
Class.new(ActionController::Base).rescue_responses['PagedScopes::PageNotFound'].should == :not_found
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should get the default collection name from the controller name" do
|
11
|
+
[ "ArticlesController", "ArticleController", "Admin::ArticlesController" ].each do |controller_name|
|
12
|
+
@class = Class.new(ActionController::Base)
|
13
|
+
@class.stub!(:name).and_return(controller_name)
|
14
|
+
@class.send(:default_collection_name).should == "articles"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should not get the default collection name from a misnamed controller" do
|
19
|
+
[ "", "SomeClassName" ].each do |controller_name|
|
20
|
+
@class = Class.new(ActionController::Base)
|
21
|
+
@class.stub!(:name).and_return(controller_name)
|
22
|
+
lambda { @class.send(:default_collection_name) }.should raise_error(RuntimeError)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "instance using #page_for" do
|
28
|
+
before(:each) do
|
29
|
+
@class = Class.new(ActionController::Base)
|
30
|
+
@controller = @class.new
|
31
|
+
@articles = User.first.articles
|
32
|
+
@articles.per_page = 3
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should default to the first page of the collection" do
|
36
|
+
in_controller @controller do
|
37
|
+
page_for(@articles).should == @articles.pages.first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should find the page from a page id in the params" do
|
42
|
+
in_controller @controller do
|
43
|
+
@articles.pages.each do |page|
|
44
|
+
stub!(:params).and_return(:page_id => page.id)
|
45
|
+
page_for(@articles).should == page
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should find the page containing an object if specified" do
|
51
|
+
in_controller @controller do
|
52
|
+
@articles.each do |article|
|
53
|
+
page_for(@articles, article).should == @articles.pages.find_by_article(article)
|
54
|
+
# page_for(@articles, article).articles.all.should include(article)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should set per_page on the collection if specified" do
|
60
|
+
in_controller @controller do
|
61
|
+
page_for(@articles, :per_page => 4)
|
62
|
+
@articles.per_page.should == 4
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should set the page model name on the collection if specified" do
|
67
|
+
in_controller @controller do
|
68
|
+
page_for(@articles, :name => "Group")
|
69
|
+
@articles.page_name.should == "Group"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should set the pagination path proc if specified using a :path option" do
|
74
|
+
in_controller @controller do
|
75
|
+
@page = page_for(@articles, :path => :page_articles_path)
|
76
|
+
self.should_receive(:page_articles_path).with(@page.next)
|
77
|
+
@page.paginator.next
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should set the pagination path proc if specified with a block" do
|
82
|
+
in_controller @controller do
|
83
|
+
@page = page_for(@articles) { |page| "path/to/page/#{page.to_param}" }
|
84
|
+
@page.paginator.next.should == "path/to/page/#{@page.next.to_param}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "class using #paginate" do
|
90
|
+
before(:each) do
|
91
|
+
@class = Class.new(ActionController::Base)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should add a protected paginate callback as a before filter when paginate is called" do
|
95
|
+
@class.paginate :articles
|
96
|
+
@class.before_filters.map(&:to_s).should include("paginate_articles")
|
97
|
+
@class.protected_instance_methods.map(&:to_s).should include("paginate_articles")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should use the default collection name if no collection name is specified" do
|
101
|
+
@class.stub!(:name).and_return("ArticlesController")
|
102
|
+
@class.paginate
|
103
|
+
@class.before_filters.map(&:to_s).should include("paginate_articles")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should pass filter options except for :per_page, :name and :path on to the before filter" do
|
107
|
+
@options = { :per_page => 3, :name => "Group", :path => :page_articles_path, :only => [ :index, :show ], :if => :test }
|
108
|
+
@class.paginate :articles, @options
|
109
|
+
@filter = @class.filter_chain.detect { |filter| filter.method.to_s == "paginate_articles" }
|
110
|
+
@filter.options.keys.should_not include(:per_page, :name, :path)
|
111
|
+
@filter.options.keys.should include(:only, :if)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "instance using paginate with options in the controller class" do
|
116
|
+
before(:each) do
|
117
|
+
@options = { :per_page => 3, :name => "Group", :path => :page_articles_path, :only => [ :index, :show ], :if => :test }
|
118
|
+
@class = Class.new(ActionController::Base)
|
119
|
+
@class.paginate :articles, @options
|
120
|
+
@controller = @class.new
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should set :per_page on the collection" do
|
124
|
+
in_controller @controller do
|
125
|
+
@articles = User.first.articles
|
126
|
+
paginate_articles
|
127
|
+
@articles.per_page.should == @options[:per_page]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should set :page_name on the collection" do
|
132
|
+
in_controller @controller do
|
133
|
+
@articles = User.first.articles
|
134
|
+
paginate_articles
|
135
|
+
@articles.page_name.should == @options[:name]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should set a page instance variable named accordingly" do
|
140
|
+
in_controller @controller do
|
141
|
+
@articles = User.first.articles
|
142
|
+
paginate_articles
|
143
|
+
@group.should_not be_nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should set :path on the page's paginator" do
|
148
|
+
in_controller @controller do
|
149
|
+
@articles = User.first.articles
|
150
|
+
paginate_articles
|
151
|
+
self.should_receive(@options[:path])
|
152
|
+
@group.paginator.first
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "instance using #paginate in the controller class" do
|
158
|
+
before(:each) do
|
159
|
+
@class = Class.new(ActionController::Base)
|
160
|
+
@class.paginate :articles, :per_page => 3
|
161
|
+
@controller = @class.new
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should raise an error if no collection is set" do
|
165
|
+
in_controller @controller do
|
166
|
+
lambda { paginate_articles }.should raise_error(RuntimeError)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should pass :per_page, :name and :path options on to the call to #page_for" do
|
171
|
+
@options = { :per_page => 3, :name => "Group", :path => :page_articles_path }
|
172
|
+
@class.paginate :articles, @options
|
173
|
+
@controller = @class.new
|
174
|
+
in_controller @controller do
|
175
|
+
@articles = User.first.articles
|
176
|
+
self.should_receive(:page_for).with(@articles, nil, @options)
|
177
|
+
paginate_articles
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "when the collection is set before the filter is run" do
|
182
|
+
before(:each) do
|
183
|
+
in_controller @controller do
|
184
|
+
@articles = User.first.articles
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should get the page from the collection object if set as an instance variable" do
|
189
|
+
in_controller @controller do
|
190
|
+
@articles.each do |article|
|
191
|
+
@article = article
|
192
|
+
paginate_articles
|
193
|
+
@page.articles.all.should include(@article)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should get the page from the params if a collection object is not set or is a new record" do
|
199
|
+
in_controller @controller do
|
200
|
+
@articles.per_page = 3
|
201
|
+
stub!(:params).and_return(:page_id => @articles.pages.last.id)
|
202
|
+
[ nil, Article.new ].each do |article|
|
203
|
+
@article = article
|
204
|
+
paginate_articles
|
205
|
+
@page.should == @articles.pages.last
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should raise PageNotFound if the page id in the params is not in range" do
|
211
|
+
in_controller @controller do
|
212
|
+
@articles.per_page = 3
|
213
|
+
stub!(:params).and_return(:page_id => @articles.pages.last.id + 1)
|
214
|
+
lambda { paginate_articles }.should raise_error(PagedScopes::PageNotFound)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should get the first page if the current object is a new record" do
|
219
|
+
in_controller @controller do
|
220
|
+
@article = @articles.new
|
221
|
+
paginate_articles
|
222
|
+
@page.should == @articles.pages.first
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should otherwise default to the first page" do
|
227
|
+
in_controller @controller do
|
228
|
+
paginate_articles
|
229
|
+
@page.should == @articles.pages.first
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|