<commit_before>package lastfm

import (
	"encoding/xml"
	"io"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strings"
)

// lastfm's api root url
var (
	apiRootURL = url.URL{Scheme: "https", Host: "ws.audioscrobbler.com", Path: "/2.0/"}
	apiWebURL  = url.URL{Scheme: "https", Host: "www.last.fm", Path: "/api/auth/"}
)

// getter interface present
// so we can swap getters while testing
type getter interface {
	Get(uri string) (resp *http.Response, err error)
}

// Client struct that holds pointer
// to the LastFM object.
type Client struct {
	lfm *LastFM
}

// LastFM struct with all available clients.
type LastFM struct {
	apiKey      string
	apiSecret   string
	sessionKey  string
	userAgent   string
	getter      getter
	Album       AlbumClient
	Artist      ArtistClient
	Tag         TagClient
	Track       TrackClient
	User        UserClient
	Tasteometer TasteometerClient
}

// Initialize all clients and
// chooses which getter to use.
func New(apiKey, apiSecret string) *LastFM {
	lfm := new(LastFM)
	lfm.apiKey = apiKey
	lfm.apiSecret = apiSecret
	lfm.Album = AlbumClient{Client: Client{lfm}}
	lfm.Artist = ArtistClient{Client: Client{lfm}}
	lfm.Tag = TagClient{Client: Client{lfm}}
	lfm.Track = TrackClient{Client: Client{lfm}}
	lfm.User = UserClient{Client: Client{lfm}}
	lfm.Tasteometer = TasteometerClient{Client: Client{lfm}}

	if apiKey == "api_key_for_testing" {
		lfm.getter = new(dummyGetter)
	} else {
		lfm.getter = http.DefaultClient
	}

	return lfm
}

func (lfm *LastFM) SetSessionKey(sessionKey string) {
	lfm.sessionKey = sessionKey
}

func (lfm *LastFM) GetSessionKey() string {
	return lfm.sessionKey
}

func (lfm *LastFM) SetUserAgent(userAgent string) {
	lfm.userAgent = userAgent
}

func (lfm *LastFM) GetUserAgent() string {
	return lfm.userAgent
}

// Build url for the request.
func (lfm *LastFM) buildURL(query map[string]string) string {
	values := url.Values{}

	for key, value := range query {
		values.Add(key, value)
	}

	uri := apiRootURL
	uri.RawQuery = values.Encode()

	return uri.String()
}

func (lfm *LastFM) getResponse(method string, query map[string]string, response LastfmResponse) (err error) {
	body, _, err := lfm.makeRequest(method, query)

	if err != nil {
		return
	}

	defer body.Close()
	err = xml.NewDecoder(body).Decode(response)

	if err != nil {
		return
	}

	if response.getErrorCode() != 0 {
		err = response.getError()
		return
	}
	return
}

// Add metthod and api_key as part of the query parameters.
// Call getter to get the requests body.
func (lfm *LastFM) makeRequest(method string, params map[string]string) (body io.ReadCloser, hdr http.Header, err error) {
	queryParams := make(map[string]string, len(params)+2)
	queryParams["api_key"] = lfm.apiKey
	queryParams["method"] = method

	for key, value := range params {
		queryParams[key] = value
	}

	response, err := lfm.getter.Get(lfm.buildURL(queryParams))

	if err != nil {

		if response != nil && response.Body != nil {
			response.Body.Close()
		}

		return
	}

	return response.Body, response.Header, err
}

// dummyGetter used for testing.
// Implements getter interface.
type dummyGetter struct{}

// Getter that reads from some file and then returns it
// as body of http.Response.
func (c *dummyGetter) Get(uri string) (resp *http.Response, err error) {
	u, err := url.Parse(uri)

	if err != nil {
		return
	}

	fh, err := os.Open(c.buildFilename(u.Query()))

	if err != nil {
		return
	}

	resp = &http.Response{Body: fh}

	return
}

// Construct unique filename per request.
func (c *dummyGetter) buildFilename(values url.Values) string {
	var parts []string
	var keys []string
	parts = append(parts, values.Get("method"))

	for key := range values {

		if key == "method" || key == "api_key" {
			continue
		}

		keys = append(keys, key)
	}

	sort.Strings(keys)

	for _, key := range keys {
		parts = append(parts, strings.Join([]string{key, strings.Replace(strings.Join(values[key], ","), " ", "-", -1)}, "="))
	}

	return "testing/" + strings.Join(parts, "-") + ".xml"
}
<commit_msg>Add token property with getter and setter.<commit_after>package lastfm

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"io"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strings"
)

// lastfm's api root url
var (
	apiRootURL = url.URL{Scheme: "https", Host: "ws.audioscrobbler.com", Path: "/2.0/"}
	apiWebURL  = url.URL{Scheme: "https", Host: "www.last.fm", Path: "/api/auth/"}
)

// getter interface present
// so we can swap getters while testing
type getter interface {
	Get(uri string) (resp *http.Response, err error)
}

// Client struct that holds pointer
// to the LastFM object.
type Client struct {
	lfm *LastFM
}

// LastFM struct with all available clients.
type LastFM struct {
	apiKey      string
	apiSecret   string
	sessionKey  string
	userAgent   string
	token       string
	getter      getter
	Album       AlbumClient
	Artist      ArtistClient
	Tag         TagClient
	Track       TrackClient
	User        UserClient
	Tasteometer TasteometerClient
}

// Initialize all clients and
// chooses which getter to use.
func New(apiKey, apiSecret string) *LastFM {
	lfm := new(LastFM)
	lfm.apiKey = apiKey
	lfm.apiSecret = apiSecret
	lfm.userAgent = "go-lastfm"
	lfm.Album = AlbumClient{Client: Client{lfm}}
	lfm.Artist = ArtistClient{Client: Client{lfm}}
	lfm.Tag = TagClient{Client: Client{lfm}}
	lfm.Track = TrackClient{Client: Client{lfm}}
	lfm.User = UserClient{Client: Client{lfm}}
	lfm.Tasteometer = TasteometerClient{Client: Client{lfm}}

	if apiKey == "api_key_for_testing" {
		lfm.getter = new(dummyGetter)
	} else {
		lfm.getter = http.DefaultClient
	}

	return lfm
}

func (lfm *LastFM) SetSessionKey(sessionKey string) {
	lfm.sessionKey = sessionKey
}

func (lfm *LastFM) GetSessionKey() string {
	return lfm.sessionKey
}

func (lfm *LastFM) SetUserAgent(userAgent string) {
	lfm.userAgent = userAgent
}

func (lfm *LastFM) GetUserAgent() string {
	return lfm.userAgent
}

func (lfm *LastFM) SetToken(token string) {
	lfm.token = token
}

func (lfm *LastFM) GetToken() string {
	return lfm.token
}

func (lfm *LastFM) getSignature(params map[string]string) string {
	var plainSignature string
	var keys []string

	for key := range params {
		keys = append(keys, key)
	}

	sort.Strings(keys)

	for _, key := range keys {
		plainSignature += key + params[key]
	}

	plainSignature += lfm.apiSecret

	hasher := md5.New()
	hasher.Write([]byte(plainSignature))

	return hex.EncodeToString(hasher.Sum(nil))
}

// Build url for the request.
func (lfm *LastFM) buildURL(query map[string]string) string {
	values := url.Values{}

	for key, value := range query {
		values.Add(key, value)
	}

	uri := apiRootURL
	uri.RawQuery = values.Encode()

	return uri.String()
}

func (lfm *LastFM) getResponse(method string, query map[string]string, response LastfmResponse) (err error) {
	body, _, err := lfm.makeRequest(method, query)

	if err != nil {
		return
	}

	defer body.Close()
	err = xml.NewDecoder(body).Decode(response)

	if err != nil {
		return
	}

	if response.getErrorCode() != 0 {
		err = response.getError()
		return
	}
	return
}

// Add metthod and api_key as part of the query parameters.
// Call getter to get the requests body.
func (lfm *LastFM) makeRequest(method string, params map[string]string) (body io.ReadCloser, hdr http.Header, err error) {
	queryParams := make(map[string]string, len(params)+2)
	queryParams["api_key"] = lfm.apiKey
	queryParams["method"] = method

	for key, value := range params {
		queryParams[key] = value
	}

	response, err := lfm.getter.Get(lfm.buildURL(queryParams))

	if err != nil {

		if response != nil && response.Body != nil {
			response.Body.Close()
		}

		return
	}

	return response.Body, response.Header, err
}

// dummyGetter used for testing.
// Implements getter interface.
type dummyGetter struct{}

// Getter that reads from some file and then returns it
// as body of http.Response.
func (c *dummyGetter) Get(uri string) (resp *http.Response, err error) {
	u, err := url.Parse(uri)

	if err != nil {
		return
	}

	fh, err := os.Open(c.buildFilename(u.Query()))

	if err != nil {
		return
	}

	resp = &http.Response{Body: fh}

	return
}

// Construct unique filename per request.
func (c *dummyGetter) buildFilename(values url.Values) string {
	var parts []string
	var keys []string
	parts = append(parts, values.Get("method"))

	for key := range values {

		if key == "method" || key == "api_key" {
			continue
		}

		keys = append(keys, key)
	}

	sort.Strings(keys)

	for _, key := range keys {
		parts = append(parts, strings.Join([]string{key, strings.Replace(strings.Join(values[key], ","), " ", "-", -1)}, "="))
	}

	return "testing/" + strings.Join(parts, "-") + ".xml"
}

{'fraction_non_alphanumeric': 0.13238007380073802, 'fraction_numerical': 0.0013837638376383763, 'mean_word_length': 3.760153677277717, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7403358', 'n_tokens_mistral': 3125, 'n_tokens_neox': 3024, 'n_words': 836}