2019-01-02 06:33:26 -05:00
|
|
|
// Copyright 2019 The Hugo Authors. All rights reserved.
|
2015-12-10 17:19:38 -05:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
package page
|
2015-07-21 15:01:56 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
2015-07-25 10:34:35 -04:00
|
|
|
"time"
|
2016-04-22 14:43:00 -04:00
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
"github.com/gohugoio/hugo/htesting/hqt"
|
|
|
|
"github.com/gohugoio/hugo/source"
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
"github.com/gohugoio/hugo/resources/resource"
|
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
qt "github.com/frankban/quicktest"
|
2015-07-21 15:01:56 -04:00
|
|
|
)
|
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
var eq = qt.CmpEquals(hqt.DeepAllowUnexported(
|
|
|
|
&testPage{},
|
|
|
|
&source.FileInfo{},
|
|
|
|
))
|
|
|
|
|
2015-07-25 11:22:19 -04:00
|
|
|
func TestDefaultSort(t *testing.T) {
|
2017-02-04 22:20:06 -05:00
|
|
|
t.Parallel()
|
2019-08-10 15:05:17 -04:00
|
|
|
c := qt.New(t)
|
2015-07-25 10:34:35 -04:00
|
|
|
d1 := time.Now()
|
2015-07-25 11:22:19 -04:00
|
|
|
d2 := d1.Add(-1 * time.Hour)
|
|
|
|
d3 := d1.Add(-2 * time.Hour)
|
2016-11-06 09:38:52 -05:00
|
|
|
d4 := d1.Add(-3 * time.Hour)
|
2015-07-25 10:34:35 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
p := createSortTestPages(4)
|
2015-07-25 10:34:35 -04:00
|
|
|
|
|
|
|
// first by weight
|
2016-11-06 09:38:52 -05:00
|
|
|
setSortVals([4]time.Time{d1, d2, d3, d4}, [4]string{"b", "a", "c", "d"}, [4]int{4, 3, 2, 1}, p)
|
2019-01-02 06:33:26 -05:00
|
|
|
SortByDefault(p)
|
2016-11-06 09:38:52 -05:00
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p[0].Weight(), qt.Equals, 1)
|
2016-11-06 09:38:52 -05:00
|
|
|
|
|
|
|
// Consider zero weight, issue #2673
|
|
|
|
setSortVals([4]time.Time{d1, d2, d3, d4}, [4]string{"b", "a", "d", "c"}, [4]int{0, 0, 0, 1}, p)
|
2019-01-02 06:33:26 -05:00
|
|
|
SortByDefault(p)
|
2016-02-06 16:10:36 -05:00
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p[0].Weight(), qt.Equals, 1)
|
2015-07-25 10:34:35 -04:00
|
|
|
|
|
|
|
// next by date
|
2016-11-06 09:38:52 -05:00
|
|
|
setSortVals([4]time.Time{d3, d4, d1, d2}, [4]string{"a", "b", "c", "d"}, [4]int{1, 1, 1, 1}, p)
|
2019-01-02 06:33:26 -05:00
|
|
|
SortByDefault(p)
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p[0].Date(), qt.Equals, d1)
|
2015-07-25 10:34:35 -04:00
|
|
|
|
2016-02-06 16:10:36 -05:00
|
|
|
// finally by link title
|
2016-11-06 09:38:52 -05:00
|
|
|
setSortVals([4]time.Time{d3, d3, d3, d3}, [4]string{"b", "c", "a", "d"}, [4]int{1, 1, 1, 1}, p)
|
2019-01-02 06:33:26 -05:00
|
|
|
SortByDefault(p)
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p[0].LinkTitle(), qt.Equals, "al")
|
|
|
|
c.Assert(p[1].LinkTitle(), qt.Equals, "bl")
|
|
|
|
c.Assert(p[2].LinkTitle(), qt.Equals, "cl")
|
2016-02-06 16:10:36 -05:00
|
|
|
}
|
|
|
|
|
2018-11-28 06:28:24 -05:00
|
|
|
// https://github.com/gohugoio/hugo/issues/4953
|
|
|
|
func TestSortByLinkTitle(t *testing.T) {
|
|
|
|
t.Parallel()
|
2019-08-10 15:05:17 -04:00
|
|
|
c := qt.New(t)
|
2019-01-02 06:33:26 -05:00
|
|
|
pages := createSortTestPages(6)
|
2018-11-28 06:28:24 -05:00
|
|
|
|
|
|
|
for i, p := range pages {
|
2019-01-02 06:33:26 -05:00
|
|
|
pp := p.(*testPage)
|
2018-11-28 06:28:24 -05:00
|
|
|
if i < 5 {
|
2019-01-02 06:33:26 -05:00
|
|
|
pp.title = fmt.Sprintf("title%d", i)
|
2018-11-28 06:28:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if i > 2 {
|
2019-01-02 06:33:26 -05:00
|
|
|
pp.linkTitle = fmt.Sprintf("linkTitle%d", i)
|
2018-11-28 06:28:24 -05:00
|
|
|
}
|
2019-01-02 06:33:26 -05:00
|
|
|
|
2018-11-28 06:28:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pages.shuffle()
|
|
|
|
|
|
|
|
bylt := pages.ByLinkTitle()
|
|
|
|
|
|
|
|
for i, p := range bylt {
|
|
|
|
if i < 3 {
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p.LinkTitle(), qt.Equals, fmt.Sprintf("linkTitle%d", i+3))
|
2018-11-28 06:28:24 -05:00
|
|
|
} else {
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p.LinkTitle(), qt.Equals, fmt.Sprintf("title%d", i-3))
|
2018-11-28 06:28:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-06 16:10:36 -05:00
|
|
|
func TestSortByN(t *testing.T) {
|
2017-02-04 22:20:06 -05:00
|
|
|
t.Parallel()
|
2016-02-06 16:10:36 -05:00
|
|
|
d1 := time.Now()
|
|
|
|
d2 := d1.Add(-2 * time.Hour)
|
|
|
|
d3 := d1.Add(-10 * time.Hour)
|
2016-11-06 09:38:52 -05:00
|
|
|
d4 := d1.Add(-20 * time.Hour)
|
2016-02-06 16:10:36 -05:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
p := createSortTestPages(4)
|
2016-02-06 16:10:36 -05:00
|
|
|
|
|
|
|
for i, this := range []struct {
|
|
|
|
sortFunc func(p Pages) Pages
|
|
|
|
assertFunc func(p Pages) bool
|
|
|
|
}{
|
2019-01-02 06:33:26 -05:00
|
|
|
{(Pages).ByWeight, func(p Pages) bool { return p[0].Weight() == 1 }},
|
|
|
|
{(Pages).ByTitle, func(p Pages) bool { return p[0].Title() == "ab" }},
|
2016-02-06 16:10:36 -05:00
|
|
|
{(Pages).ByLinkTitle, func(p Pages) bool { return p[0].LinkTitle() == "abl" }},
|
2019-01-02 06:33:26 -05:00
|
|
|
{(Pages).ByDate, func(p Pages) bool { return p[0].Date() == d4 }},
|
|
|
|
{(Pages).ByPublishDate, func(p Pages) bool { return p[0].PublishDate() == d4 }},
|
|
|
|
{(Pages).ByExpiryDate, func(p Pages) bool { return p[0].ExpiryDate() == d4 }},
|
|
|
|
{(Pages).ByLastmod, func(p Pages) bool { return p[1].Lastmod() == d3 }},
|
|
|
|
{(Pages).ByLength, func(p Pages) bool { return p[0].(resource.LengthProvider).Len() == len(p[0].(*testPage).content) }},
|
2016-02-06 16:10:36 -05:00
|
|
|
} {
|
2016-11-06 09:38:52 -05:00
|
|
|
setSortVals([4]time.Time{d1, d2, d3, d4}, [4]string{"b", "ab", "cde", "fg"}, [4]int{0, 3, 2, 1}, p)
|
2016-02-06 16:10:36 -05:00
|
|
|
|
|
|
|
sorted := this.sortFunc(p)
|
|
|
|
if !this.assertFunc(sorted) {
|
|
|
|
t.Errorf("[%d] sort error", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLimit(t *testing.T) {
|
2017-02-04 22:20:06 -05:00
|
|
|
t.Parallel()
|
2019-08-10 15:05:17 -04:00
|
|
|
c := qt.New(t)
|
2019-01-02 06:33:26 -05:00
|
|
|
p := createSortTestPages(10)
|
2016-02-06 16:10:36 -05:00
|
|
|
firstFive := p.Limit(5)
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(len(firstFive), qt.Equals, 5)
|
2016-02-06 16:10:36 -05:00
|
|
|
for i := 0; i < 5; i++ {
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(firstFive[i], qt.Equals, p[i])
|
2016-02-06 16:10:36 -05:00
|
|
|
}
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p.Limit(10), eq, p)
|
|
|
|
c.Assert(p.Limit(11), eq, p)
|
2015-07-25 10:34:35 -04:00
|
|
|
}
|
|
|
|
|
2015-07-21 15:01:56 -04:00
|
|
|
func TestPageSortReverse(t *testing.T) {
|
2017-02-04 22:20:06 -05:00
|
|
|
t.Parallel()
|
2019-08-10 15:05:17 -04:00
|
|
|
c := qt.New(t)
|
2019-01-02 06:33:26 -05:00
|
|
|
p1 := createSortTestPages(10)
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p1[0].(*testPage).fuzzyWordCount, qt.Equals, 0)
|
|
|
|
c.Assert(p1[9].(*testPage).fuzzyWordCount, qt.Equals, 9)
|
2015-07-20 19:29:22 -04:00
|
|
|
p2 := p1.Reverse()
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(p2[0].(*testPage).fuzzyWordCount, qt.Equals, 9)
|
|
|
|
c.Assert(p2[9].(*testPage).fuzzyWordCount, qt.Equals, 0)
|
2015-07-20 19:29:22 -04:00
|
|
|
// cached
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(pagesEqual(p2, p1.Reverse()), qt.Equals, true)
|
2015-07-21 15:01:56 -04:00
|
|
|
}
|
|
|
|
|
2017-02-10 08:01:25 -05:00
|
|
|
func TestPageSortByParam(t *testing.T) {
|
2017-02-04 22:20:06 -05:00
|
|
|
t.Parallel()
|
2019-08-10 15:05:17 -04:00
|
|
|
c := qt.New(t)
|
2017-02-19 02:50:08 -05:00
|
|
|
var k interface{} = "arbitrarily.nested"
|
2017-02-10 08:01:25 -05:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
unsorted := createSortTestPages(10)
|
|
|
|
delete(unsorted[9].Params(), "arbitrarily")
|
2017-02-10 08:01:25 -05:00
|
|
|
|
|
|
|
firstSetValue, _ := unsorted[0].Param(k)
|
|
|
|
secondSetValue, _ := unsorted[1].Param(k)
|
|
|
|
lastSetValue, _ := unsorted[8].Param(k)
|
|
|
|
unsetValue, _ := unsorted[9].Param(k)
|
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(firstSetValue, qt.Equals, "xyz100")
|
|
|
|
c.Assert(secondSetValue, qt.Equals, "xyz99")
|
|
|
|
c.Assert(lastSetValue, qt.Equals, "xyz92")
|
|
|
|
c.Assert(unsetValue, qt.Equals, nil)
|
2017-02-10 08:01:25 -05:00
|
|
|
|
2017-02-19 02:50:08 -05:00
|
|
|
sorted := unsorted.ByParam("arbitrarily.nested")
|
2017-02-10 08:01:25 -05:00
|
|
|
firstSetSortedValue, _ := sorted[0].Param(k)
|
|
|
|
secondSetSortedValue, _ := sorted[1].Param(k)
|
|
|
|
lastSetSortedValue, _ := sorted[8].Param(k)
|
|
|
|
unsetSortedValue, _ := sorted[9].Param(k)
|
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(firstSetSortedValue, qt.Equals, firstSetValue)
|
|
|
|
c.Assert(lastSetSortedValue, qt.Equals, secondSetValue)
|
|
|
|
c.Assert(secondSetSortedValue, qt.Equals, lastSetValue)
|
|
|
|
c.Assert(unsetSortedValue, qt.Equals, unsetValue)
|
2017-02-10 08:01:25 -05:00
|
|
|
}
|
|
|
|
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
func TestPageSortByParamNumeric(t *testing.T) {
|
|
|
|
t.Parallel()
|
2019-08-10 15:05:17 -04:00
|
|
|
c := qt.New(t)
|
|
|
|
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
var k interface{} = "arbitrarily.nested"
|
|
|
|
|
|
|
|
n := 10
|
2019-01-02 06:33:26 -05:00
|
|
|
unsorted := createSortTestPages(n)
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
v := 100 - i
|
|
|
|
if i%2 == 0 {
|
|
|
|
v = 100.0 - i
|
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
unsorted[i].(*testPage).params = map[string]interface{}{
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
"arbitrarily": map[string]interface{}{
|
|
|
|
"nested": v,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2019-01-02 06:33:26 -05:00
|
|
|
delete(unsorted[9].Params(), "arbitrarily")
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
|
|
|
|
firstSetValue, _ := unsorted[0].Param(k)
|
|
|
|
secondSetValue, _ := unsorted[1].Param(k)
|
|
|
|
lastSetValue, _ := unsorted[8].Param(k)
|
|
|
|
unsetValue, _ := unsorted[9].Param(k)
|
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(firstSetValue, qt.Equals, 100)
|
|
|
|
c.Assert(secondSetValue, qt.Equals, 99)
|
|
|
|
c.Assert(lastSetValue, qt.Equals, 92)
|
|
|
|
c.Assert(unsetValue, qt.Equals, nil)
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
|
|
|
|
sorted := unsorted.ByParam("arbitrarily.nested")
|
|
|
|
firstSetSortedValue, _ := sorted[0].Param(k)
|
|
|
|
secondSetSortedValue, _ := sorted[1].Param(k)
|
|
|
|
lastSetSortedValue, _ := sorted[8].Param(k)
|
|
|
|
unsetSortedValue, _ := sorted[9].Param(k)
|
|
|
|
|
2019-08-10 15:05:17 -04:00
|
|
|
c.Assert(firstSetSortedValue, qt.Equals, 92)
|
|
|
|
c.Assert(secondSetSortedValue, qt.Equals, 93)
|
|
|
|
c.Assert(lastSetSortedValue, qt.Equals, 100)
|
|
|
|
c.Assert(unsetSortedValue, qt.Equals, unsetValue)
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
}
|
|
|
|
|
2015-07-21 15:01:56 -04:00
|
|
|
func BenchmarkSortByWeightAndReverse(b *testing.B) {
|
2019-01-02 06:33:26 -05:00
|
|
|
p := createSortTestPages(300)
|
2015-07-21 15:01:56 -04:00
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
p = p.ByWeight().Reverse()
|
|
|
|
}
|
2015-07-25 10:34:35 -04:00
|
|
|
}
|
|
|
|
|
2016-11-06 09:38:52 -05:00
|
|
|
func setSortVals(dates [4]time.Time, titles [4]string, weights [4]int, pages Pages) {
|
2015-07-25 10:34:35 -04:00
|
|
|
for i := range dates {
|
2019-01-02 06:33:26 -05:00
|
|
|
this := pages[i].(*testPage)
|
|
|
|
other := pages[len(dates)-1-i].(*testPage)
|
|
|
|
|
|
|
|
this.date = dates[i]
|
|
|
|
this.lastMod = dates[i]
|
|
|
|
this.weight = weights[i]
|
|
|
|
this.title = titles[i]
|
2016-02-06 16:10:36 -05:00
|
|
|
// make sure we compare apples and ... apples ...
|
2019-01-02 06:33:26 -05:00
|
|
|
other.linkTitle = this.Title() + "l"
|
|
|
|
other.pubDate = dates[i]
|
|
|
|
other.expiryDate = dates[i]
|
|
|
|
other.content = titles[i] + "_content"
|
2015-07-25 10:34:35 -04:00
|
|
|
}
|
2019-01-02 06:33:26 -05:00
|
|
|
lastLastMod := pages[2].Lastmod()
|
|
|
|
pages[2].(*testPage).lastMod = pages[1].Lastmod()
|
|
|
|
pages[1].(*testPage).lastMod = lastLastMod
|
2018-04-23 23:57:33 -04:00
|
|
|
|
|
|
|
for _, p := range pages {
|
2019-01-02 06:33:26 -05:00
|
|
|
p.(*testPage).content = ""
|
2018-04-23 23:57:33 -04:00
|
|
|
}
|
2015-07-21 15:01:56 -04:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
func createSortTestPages(num int) Pages {
|
2015-07-21 15:01:56 -04:00
|
|
|
pages := make(Pages, num)
|
|
|
|
|
|
|
|
for i := 0; i < num; i++ {
|
2019-01-02 06:33:26 -05:00
|
|
|
p := newTestPage()
|
|
|
|
p.path = fmt.Sprintf("/x/y/p%d.md", i)
|
2019-10-11 07:55:46 -04:00
|
|
|
p.title = fmt.Sprintf("Title %d", i%(num+1/2))
|
2018-01-15 14:40:39 -05:00
|
|
|
p.params = map[string]interface{}{
|
2017-02-19 02:50:08 -05:00
|
|
|
"arbitrarily": map[string]interface{}{
|
|
|
|
"nested": ("xyz" + fmt.Sprintf("%v", 100-i)),
|
|
|
|
},
|
2015-07-21 15:01:56 -04:00
|
|
|
}
|
2017-02-04 22:20:06 -05:00
|
|
|
|
2015-07-21 15:01:56 -04:00
|
|
|
w := 5
|
2016-11-06 09:38:52 -05:00
|
|
|
|
2015-07-21 15:01:56 -04:00
|
|
|
if i%2 == 0 {
|
|
|
|
w = 10
|
|
|
|
}
|
2017-02-04 22:20:06 -05:00
|
|
|
p.fuzzyWordCount = i
|
2019-01-02 06:33:26 -05:00
|
|
|
p.weight = w
|
|
|
|
p.description = "initial"
|
2017-02-04 22:20:06 -05:00
|
|
|
|
|
|
|
pages[i] = p
|
2015-07-21 15:01:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return pages
|
|
|
|
}
|