Use ServiceClient and pagination in Flavor operations.
diff --git a/openstack/compute/v2/flavors/client.go b/openstack/compute/v2/flavors/client.go
deleted file mode 100644
index edeec66..0000000
--- a/openstack/compute/v2/flavors/client.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package flavors
-
-import (
-	"fmt"
-	"net/url"
-	"strconv"
-
-	"github.com/rackspace/gophercloud"
-	identity "github.com/rackspace/gophercloud/openstack/identity/v2"
-)
-
-type Client struct {
-	endpoint  string
-	authority identity.AuthResults
-	options   gophercloud.AuthOptions
-}
-
-func NewClient(e string, a identity.AuthResults, ao gophercloud.AuthOptions) *Client {
-	return &Client{
-		endpoint:  e,
-		authority: a,
-		options:   ao,
-	}
-}
-
-func (c *Client) getListUrl(lfo ListFilterOptions) string {
-	v := url.Values{}
-	if lfo.ChangesSince != "" {
-		v.Set("changes-since", lfo.ChangesSince)
-	}
-	if lfo.MinDisk != 0 {
-		v.Set("minDisk", strconv.Itoa(lfo.MinDisk))
-	}
-	if lfo.MinRam != 0 {
-		v.Set("minRam", strconv.Itoa(lfo.MinRam))
-	}
-	if lfo.Marker != "" {
-		v.Set("marker", lfo.Marker)
-	}
-	if lfo.Limit != 0 {
-		v.Set("limit", strconv.Itoa(lfo.Limit))
-	}
-	tail := ""
-	if len(v) > 0 {
-		tail = fmt.Sprintf("?%s", v.Encode())
-	}
-	return fmt.Sprintf("%s/flavors/detail%s", c.endpoint, tail)
-}
-
-func (c *Client) getGetUrl(id string) string {
-	return fmt.Sprintf("%s/flavors/%s", c.endpoint, id)
-}
-
-func (c *Client) getListHeaders() (map[string]string, error) {
-	t, err := identity.GetToken(c.authority)
-	if err != nil {
-		return map[string]string{}, err
-	}
-
-	return map[string]string{
-		"X-Auth-Token": t.ID,
-	}, nil
-}
diff --git a/openstack/compute/v2/flavors/flavors.go b/openstack/compute/v2/flavors/flavors.go
index 146bcc4..4318eb6 100644
--- a/openstack/compute/v2/flavors/flavors.go
+++ b/openstack/compute/v2/flavors/flavors.go
@@ -1,31 +1,37 @@
 package flavors
 
 import (
-	"github.com/mitchellh/mapstructure"
+	"errors"
 	"reflect"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/rackspace/gophercloud/pagination"
 )
 
+// ErrCannotInterpret is returned by an Extract call if the response body doesn't have the expected structure.
+var ErrCannotInterpet = errors.New("Unable to interpret a response body.")
+
 // Flavor records represent (virtual) hardware configurations for server resources in a region.
-//
-// The Id field contains the flavor's unique identifier.
-// For example, this identifier will be useful when specifying which hardware configuration to use for a new server instance.
-//
-// The Disk and Ram fields provide a measure of storage space offered by the flavor, in GB and MB, respectively.
-//
-// The Name field provides a human-readable moniker for the flavor.
-//
-// Swap indicates how much space is reserved for swap.
-// If not provided, this field will be set to 0.
-//
-// VCpus indicates how many (virtual) CPUs are available for this flavor.
 type Flavor struct {
-	Disk       int
-	Id         string
-	Name       string
-	Ram        int
+	// The Id field contains the flavor's unique identifier.
+	// For example, this identifier will be useful when specifying which hardware configuration to use for a new server instance.
+	ID string `mapstructure:"id"`
+
+	// The Disk and RA< fields provide a measure of storage space offered by the flavor, in GB and MB, respectively.
+	Disk int `mapstructure:"disk"`
+	RAM  int `mapstructure:"ram"`
+
+	// The Name field provides a human-readable moniker for the flavor.
+	Name string `mapstructure:"name"`
+
 	RxTxFactor float64 `mapstructure:"rxtx_factor"`
-	Swap       int
-	VCpus      int
+
+	// Swap indicates how much space is reserved for swap.
+	// If not provided, this field will be set to 0.
+	Swap int `mapstructure:"swap"`
+
+	// VCPUs indicates how many (virtual) CPUs are available for this flavor.
+	VCPUs int `mapstructure:"vcpus"`
 }
 
 func defaulter(from, to reflect.Kind, v interface{}) (interface{}, error) {
@@ -35,44 +41,38 @@
 	return v, nil
 }
 
-// GetFlavors provides access to the list of flavors returned by the List function.
-func GetFlavors(lr ListResults) ([]Flavor, error) {
-	fa, ok := lr["flavors"]
-	if !ok {
-		return nil, ErrNotImplemented
-	}
-	fms := fa.([]interface{})
+// ExtractFlavors provides access to the list of flavors in a page acquired from the List operation.
+func ExtractFlavors(page pagination.Page) ([]Flavor, error) {
+	casted := page.(ListResult).Body
+	var flavors []Flavor
 
-	flavors := make([]Flavor, len(fms))
-	for i, fm := range fms {
-		flavorObj := fm.(map[string]interface{})
-		cfg := &mapstructure.DecoderConfig{
-			DecodeHook: defaulter,
-			Result:     &flavors[i],
-		}
-		decoder, err := mapstructure.NewDecoder(cfg)
-		if err != nil {
-			return flavors, err
-		}
-		err = decoder.Decode(flavorObj)
-		if err != nil {
-			return flavors, err
-		}
+	cfg := &mapstructure.DecoderConfig{
+		DecodeHook: defaulter,
+		Result:     &flavors,
 	}
+	decoder, err := mapstructure.NewDecoder(cfg)
+	if err != nil {
+		return flavors, err
+	}
+	err = decoder.Decode(casted)
+	if err != nil {
+		return flavors, err
+	}
+
 	return flavors, nil
 }
 
-// GetFlavor provides access to the individual flavor returned by the Get function.
-func GetFlavor(gr GetResults) (*Flavor, error) {
+// ExtractFlavor provides access to the individual flavor returned by the Get function.
+func ExtractFlavor(gr GetResults) (*Flavor, error) {
 	f, ok := gr["flavor"]
 	if !ok {
-		return nil, ErrNotImplemented
+		return nil, ErrCannotInterpet
 	}
 
 	flav := new(Flavor)
 	cfg := &mapstructure.DecoderConfig{
 		DecodeHook: defaulter,
-		Result: flav,
+		Result:     flav,
 	}
 	decoder, err := mapstructure.NewDecoder(cfg)
 	if err != nil {
diff --git a/openstack/compute/v2/flavors/requests.go b/openstack/compute/v2/flavors/requests.go
index 3758206..7563d04 100644
--- a/openstack/compute/v2/flavors/requests.go
+++ b/openstack/compute/v2/flavors/requests.go
@@ -1,58 +1,79 @@
 package flavors
 
 import (
-	"fmt"
 	"github.com/racker/perigee"
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
 )
 
-var ErrNotImplemented = fmt.Errorf("Flavors functionality not implemented.")
+// ListResult contains a single page of the response from a List call.
+type ListResult struct {
+	pagination.MarkerPageBase
+}
 
-type ListResults map[string]interface{}
+// IsEmpty determines if a page contains any results.
+func (p ListResult) IsEmpty() (bool, error) {
+	flavors, err := ExtractFlavors(p)
+	if err != nil {
+		return true, err
+	}
+	return len(flavors) == 0, nil
+}
+
+// LastMarker returns the ID field of the final result from this page, to be used as the marker for the next.
+func (p ListResult) LastMarker() (string, error) {
+	flavors, err := ExtractFlavors(p)
+	if err != nil {
+		return "", err
+	}
+	if len(flavors) == 0 {
+		return "", nil
+	}
+	return flavors[len(flavors)-1].ID, nil
+}
+
+// GetResults temporarily encodes the result of a Get operation.
 type GetResults map[string]interface{}
 
 // ListFilterOptions helps control the results returned by the List() function.
-// ChangesSince, if provided, instructs List to return only those things which have changed since the timestamp provided.
-// MinDisk and MinRam, if provided, elides flavors which do not meet your criteria.
 // For example, a flavor with a minDisk field of 10 will not be returned if you specify MinDisk set to 20.
-// Marker and Limit control paging.
-// Limit instructs List to refrain from sending excessively large lists of flavors.
-// Marker instructs List where to start listing from.
 // Typically, software will use the last ID of the previous call to List to set the Marker for the current call.
 type ListFilterOptions struct {
+
+	// ChangesSince, if provided, instructs List to return only those things which have changed since the timestamp provided.
 	ChangesSince string
-	MinDisk, MinRam int
+
+	// MinDisk and MinRAM, if provided, elides flavors which do not meet your criteria.
+	MinDisk, MinRAM int
+
+	// Marker and Limit control paging.
+	// Marker instructs List where to start listing from.
 	Marker string
+
+	// Limit instructs List to refrain from sending excessively large lists of flavors.
 	Limit int
 }
 
 // List instructs OpenStack to provide a list of flavors.
 // You may provide criteria by which List curtails its results for easier processing.
 // See ListFilterOptions for more details.
-func List(c *Client, lfo ListFilterOptions) (ListResults, error) {
-	var lr ListResults
-
-	h, err := c.getListHeaders()
-	if err != nil {
-		return nil, err
+func List(client *gophercloud.ServiceClient, lfo ListFilterOptions) pagination.Pager {
+	createPage := func(r pagination.LastHTTPResponse) pagination.Page {
+		p := ListResult{pagination.MarkerPageBase{LastHTTPResponse: r}}
+		p.MarkerPageBase.Owner = p
+		return p
 	}
 
-	err = perigee.Get(c.getListUrl(lfo), perigee.Options{
-		Results:     &lr,
-		MoreHeaders: h,
-	})
-	return lr, err
+	return pagination.NewPager(client, getListURL(client, lfo), createPage)
 }
 
 // Get instructs OpenStack to provide details on a single flavor, identified by its ID.
-func Get(c *Client, id string) (GetResults, error) {
+// Use ExtractFlavor to convert its result into a Flavor.
+func Get(client *gophercloud.ServiceClient, id string) (GetResults, error) {
 	var gr GetResults
-	h, err := c.getListHeaders()	// same for Get Flavor API
-	if err != nil {
-		return gr, err
-	}
-	err = perigee.Get(c.getGetUrl(id), perigee.Options{
-		Results: &gr,
-		MoreHeaders: h,
+	err := perigee.Get(getFlavorURL(client, id), perigee.Options{
+		Results:     &gr,
+		MoreHeaders: client.Provider.AuthenticatedHeaders(),
 	})
 	return gr, err
 }
diff --git a/openstack/compute/v2/flavors/urls.go b/openstack/compute/v2/flavors/urls.go
new file mode 100644
index 0000000..0e2d7c2
--- /dev/null
+++ b/openstack/compute/v2/flavors/urls.go
@@ -0,0 +1,37 @@
+package flavors
+
+import (
+	"fmt"
+	"net/url"
+	"strconv"
+
+	"github.com/rackspace/gophercloud"
+)
+
+func getListURL(client *gophercloud.ServiceClient, lfo ListFilterOptions) string {
+	v := url.Values{}
+	if lfo.ChangesSince != "" {
+		v.Set("changes-since", lfo.ChangesSince)
+	}
+	if lfo.MinDisk != 0 {
+		v.Set("minDisk", strconv.Itoa(lfo.MinDisk))
+	}
+	if lfo.MinRAM != 0 {
+		v.Set("minRam", strconv.Itoa(lfo.MinRAM))
+	}
+	if lfo.Marker != "" {
+		v.Set("marker", lfo.Marker)
+	}
+	if lfo.Limit != 0 {
+		v.Set("limit", strconv.Itoa(lfo.Limit))
+	}
+	tail := ""
+	if len(v) > 0 {
+		tail = fmt.Sprintf("?%s", v.Encode())
+	}
+	return client.ServiceURL("flavors", "detail") + tail
+}
+
+func getFlavorURL(client *gophercloud.ServiceClient, id string) string {
+	return client.ServiceURL("flavors", id)
+}