Change identity endpoints and services.
diff --git a/openstack/client.go b/openstack/client.go
index a5d0bc8..4fcf057 100644
--- a/openstack/client.go
+++ b/openstack/client.go
@@ -11,6 +11,7 @@
 	services3 "github.com/rackspace/gophercloud/openstack/identity/v3/services"
 	tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
 	"github.com/rackspace/gophercloud/openstack/utils"
+	"github.com/rackspace/gophercloud/pagination"
 )
 
 const (
@@ -194,7 +195,7 @@
 	// Discover the service we're interested in.
 	var services = make([]services3.Service, 0, 1)
 	servicePager := services3.List(v3Client, services3.ListOpts{ServiceType: opts.Type})
-	err := servicePager.EachPage(func(page gophercloud.Page) (bool, error) {
+	err := servicePager.EachPage(func(page pagination.Page) (bool, error) {
 		part, err := services3.ExtractServices(page)
 		if err != nil {
 			return false, err
@@ -226,7 +227,7 @@
 		Availability: opts.Availability,
 		ServiceID:    service.ID,
 	})
-	err = endpointPager.EachPage(func(page gophercloud.Page) (bool, error) {
+	err = endpointPager.EachPage(func(page pagination.Page) (bool, error) {
 		part, err := endpoints3.ExtractEndpoints(page)
 		if err != nil {
 			return false, err
diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go
index bf60406..afac927 100644
--- a/openstack/identity/v3/endpoints/requests.go
+++ b/openstack/identity/v3/endpoints/requests.go
@@ -6,6 +6,7 @@
 	"github.com/racker/perigee"
 	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/openstack/utils"
+	"github.com/rackspace/gophercloud/pagination"
 )
 
 // maybeString returns nil for empty strings and nil for empty.
@@ -94,7 +95,7 @@
 }
 
 // List enumerates endpoints in a paginated collection, optionally filtered by ListOpts criteria.
-func List(client *gophercloud.ServiceClient, opts ListOpts) gophercloud.Pager {
+func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
 	q := make(map[string]string)
 	if opts.Availability != "" {
 		q["interface"] = string(opts.Availability)
@@ -109,16 +110,12 @@
 		q["per_page"] = strconv.Itoa(opts.Page)
 	}
 
-	countPage := func(p gophercloud.Page) (int, error) {
-		es, err := ExtractEndpoints(p)
-		if err != nil {
-			return 0, err
-		}
-		return len(es), nil
+	createPage := func(r pagination.LastHTTPResponse) pagination.Page {
+		return EndpointPage{pagination.LinkedPageBase(r)}
 	}
 
 	u := getListURL(client) + utils.BuildQuery(q)
-	return gophercloud.NewLinkedPager(client, u, countPage)
+	return pagination.NewLinkedPager(client, u, createPage)
 }
 
 // Update changes an existing endpoint with new data.
diff --git a/openstack/identity/v3/endpoints/requests_test.go b/openstack/identity/v3/endpoints/requests_test.go
index 84cb2da..241d175 100644
--- a/openstack/identity/v3/endpoints/requests_test.go
+++ b/openstack/identity/v3/endpoints/requests_test.go
@@ -7,6 +7,7 @@
 	"testing"
 
 	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
 	"github.com/rackspace/gophercloud/testhelper"
 )
 
@@ -129,7 +130,7 @@
 	client := serviceClient()
 
 	count := 0
-	List(client, ListOpts{}).EachPage(func(page gophercloud.Page) (bool, error) {
+	List(client, ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
 		count++
 		actual, err := ExtractEndpoints(page)
 		if err != nil {
diff --git a/openstack/identity/v3/endpoints/results.go b/openstack/identity/v3/endpoints/results.go
index 4d7bfbc..8da90f3 100644
--- a/openstack/identity/v3/endpoints/results.go
+++ b/openstack/identity/v3/endpoints/results.go
@@ -3,6 +3,7 @@
 import (
 	"github.com/mitchellh/mapstructure"
 	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
 )
 
 // Endpoint describes the entry point for another service's API.
@@ -15,13 +16,27 @@
 	URL          string                   `mapstructure:"url" json:"url"`
 }
 
+// EndpointPage is a single page of Endpoint results.
+type EndpointPage struct {
+	pagination.LinkedPageBase
+}
+
+// IsEmpty returns true if no Endpoints were returned.
+func (p EndpointPage) IsEmpty() (bool, error) {
+	es, err := ExtractEndpoints(p)
+	if err != nil {
+		return true, err
+	}
+	return len(es) == 0, nil
+}
+
 // ExtractEndpoints extracts an Endpoint slice from a Page.
-func ExtractEndpoints(page gophercloud.Page) ([]Endpoint, error) {
+func ExtractEndpoints(page pagination.Page) ([]Endpoint, error) {
 	var response struct {
 		Endpoints []Endpoint `mapstructure:"endpoints"`
 	}
 
-	err := mapstructure.Decode(page.(gophercloud.LinkedPage).Body, &response)
+	err := mapstructure.Decode(page.(EndpointPage).Body, &response)
 	if err != nil {
 		return nil, err
 	}
diff --git a/openstack/identity/v3/services/requests.go b/openstack/identity/v3/services/requests.go
index 7bc4a82..af2ce54 100644
--- a/openstack/identity/v3/services/requests.go
+++ b/openstack/identity/v3/services/requests.go
@@ -6,6 +6,7 @@
 	"github.com/racker/perigee"
 	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/openstack/utils"
+	"github.com/rackspace/gophercloud/pagination"
 )
 
 type response struct {
@@ -42,7 +43,7 @@
 }
 
 // List enumerates the services available to a specific user.
-func List(client *gophercloud.ServiceClient, opts ListOpts) gophercloud.Pager {
+func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
 	q := make(map[string]string)
 	if opts.ServiceType != "" {
 		q["type"] = opts.ServiceType
@@ -55,15 +56,11 @@
 	}
 	u := getListURL(client) + utils.BuildQuery(q)
 
-	countPage := func(p gophercloud.Page) (int, error) {
-		services, err := ExtractServices(p)
-		if err != nil {
-			return 0, err
-		}
-		return len(services), nil
+	createPage := func(r pagination.LastHTTPResponse) pagination.Page {
+		return ServicePage{pagination.LinkedPageBase(r)}
 	}
 
-	return gophercloud.NewLinkedPager(client, u, countPage)
+	return pagination.NewLinkedPager(client, u, createPage)
 }
 
 // Get returns additional information about a service, given its ID.
diff --git a/openstack/identity/v3/services/requests_test.go b/openstack/identity/v3/services/requests_test.go
index 59cefe3..804f034 100644
--- a/openstack/identity/v3/services/requests_test.go
+++ b/openstack/identity/v3/services/requests_test.go
@@ -7,6 +7,7 @@
 	"testing"
 
 	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
 	"github.com/rackspace/gophercloud/testhelper"
 )
 
@@ -99,7 +100,7 @@
 	client := serviceClient()
 
 	count := 0
-	err := List(client, ListOpts{}).EachPage(func(page gophercloud.Page) (bool, error) {
+	err := List(client, ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
 		count++
 		actual, err := ExtractServices(page)
 		if err != nil {
diff --git a/openstack/identity/v3/services/results.go b/openstack/identity/v3/services/results.go
index 537ea2e..cccea8e 100644
--- a/openstack/identity/v3/services/results.go
+++ b/openstack/identity/v3/services/results.go
@@ -1,7 +1,7 @@
 package services
 
 import (
-	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
 
 	"github.com/mitchellh/mapstructure"
 )
@@ -14,12 +14,26 @@
 	Type        string  `json:"type"`
 }
 
+// ServicePage is a single page of Service results.
+type ServicePage struct {
+	pagination.LinkedPageBase
+}
+
+// IsEmpty returns true if the page contains no results.
+func (p ServicePage) IsEmpty() (bool, error) {
+	services, err := ExtractServices(p)
+	if err != nil {
+		return true, err
+	}
+	return len(services) == 0, nil
+}
+
 // ExtractServices extracts a slice of Services from a Collection acquired from List.
-func ExtractServices(page gophercloud.Page) ([]Service, error) {
+func ExtractServices(page pagination.Page) ([]Service, error) {
 	var response struct {
 		Services []Service `mapstructure:"services"`
 	}
 
-	err := mapstructure.Decode(page.(gophercloud.LinkedPage).Body, &response)
+	err := mapstructure.Decode(page.(ServicePage).Body, &response)
 	return response.Services, err
 }