func (t *Trending) appendBaseHostToPath(urlStr string, exists bool) *url.URL {
	if exists == false {
		return nil
	}
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil
	}
	return t.BaseURL.ResolveReference(rel)
}
appendBaseHostToPath will add the base host to a relative url urlStr.

A urlStr like "/trending" will be returned as https://github.com/trending
package trending
import (
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"github.com/PuerkitoBio/goquery"
)
const (
	TimeToday = "daily"
	TimeWeek = "weekly"
	TimeMonth = "monthly"
	defaultBaseURL = "https://github.com"
	urlTrendingPath = "/trending"
	urlDevelopersPath = "/developers"
	modeRepositories = "repositories"
	modeDevelopers = "developers"
	modeLanguages = "languages"
)
type Trending struct {
	BaseURL *url.URL
	Client *http.Client
}
type Project struct {
	Name string
	Owner string
	RepositoryName string
	Description string
	Language string
	Stars int
	URL *url.URL
	ContributorURL *url.URL
	Contributor []Developer
}
type Language struct {
	Name string
	URLName string
	URL *url.URL
}
type Developer struct {
	ID int
	DisplayName string
	FullName string
	URL *url.URL
	Avatar *url.URL
}
func NewTrending() *Trending {
	return NewTrendingWithClient(http.DefaultClient)
}
func NewTrendingWithClient(client *http.Client) *Trending {
	baseURL, _ := url.Parse(defaultBaseURL)
	t := Trending{
		BaseURL: baseURL,
		Client:  client,
	}
	return &t
}
func (t *Trending) GetProjects(time, language string) ([]Project, error) {
	var projects []Project
	u, err := t.generateURL(modeRepositories, time, language)
	if err != nil {
		return projects, err
	}
	res, err := t.Client.Get(u.String())
	if err != nil {
		return projects, err
	}
	doc, err := goquery.NewDocumentFromResponse(res)
	if err != nil {
		return projects, err
	}
	doc.Find("ol.repo-list li").Each(func(i int, s *goquery.Selection) {
		name := t.getProjectName(s.Find("h3 a").Text())
		splittedName := strings.SplitAfterN(name, "/", 2)
		owner := splittedName[0][:len(splittedName[0])-1]
		owner = strings.TrimSpace(owner)
		repositoryName := strings.TrimSpace(splittedName[1])
		address, exists := s.Find("h3 a").First().Attr("href")
		projectURL := t.appendBaseHostToPath(address, exists)
		description := s.Find(".py-1 p").Text()
		description = strings.TrimSpace(description)
		language := s.Find("div.f6 span").Eq(1).Text()
		language = strings.TrimSpace(language)
		starsString := s.Find("div.f6 a").First().Text()
		starsString = strings.TrimSpace(starsString)
		starsString = strings.Replace(starsString, ",", "", 1)
		starsString = strings.Replace(starsString, ".", "", 1)
		stars, err := strconv.Atoi(starsString)
		if err != nil {
			stars = 0
		}
		contributerSelection := s.Find("div.f6 a").Eq(2)
		contributorPath, exists := contributerSelection.Attr("href")
		contributorURL := t.appendBaseHostToPath(contributorPath, exists)
		var developer []Developer
		contributerSelection.Find("img").Each(func(j int, devSelection *goquery.Selection) {
			devName, exists := devSelection.Attr("title")
			linkURL := t.appendBaseHostToPath(devName, exists)
			avatar, exists := devSelection.Attr("src")
			avatarURL := t.buildAvatarURL(avatar, exists)
			developer = append(developer, t.newDeveloper(devName, "", linkURL, avatarURL))
		})
		p := Project{
			Name:           name,
			Owner:          owner,
			RepositoryName: repositoryName,
			Description:    description,
			Language:       language,
			Stars:          stars,
			URL:            projectURL,
			ContributorURL: contributorURL,
			Contributor:    developer,
		}
		projects = append(projects, p)
	})
	return projects, nil
}
func (t *Trending) GetLanguages() ([]Language, error) {
	return t.generateLanguages(".col-md-3 div.select-menu .select-menu-list a")
}
func (t *Trending) GetTrendingLanguages() ([]Language, error) {
	return t.generateLanguages("ul.filter-list a")
}
func (t *Trending) generateLanguages(mainSelector string) ([]Language, error) {
	var languages []Language
	u, err := t.generateURL(modeLanguages, "", "")
	if err != nil {
		return languages, err
	}
	res, err := t.Client.Get(u.String())
	if err != nil {
		return languages, err
	}
	doc, err := goquery.NewDocumentFromResponse(res)
	if err != nil {
		return languages, err
	}
	doc.Find(mainSelector).Each(func(i int, s *goquery.Selection) {
		languageAddress, _ := s.Attr("href")
		languageURLName := ""
		filterURL, _ := url.Parse(languageAddress)
		re := regexp.MustCompile("github.com/trending/([^/\\?]*)")
		if matches := re.FindStringSubmatch(languageAddress); len(matches) >= 2 && len(matches[1]) > 0 {
			languageURLName = matches[1]
		}
		language := Language{
			Name:    strings.TrimSpace(s.Text()),
			URLName: languageURLName,
			URL:     filterURL,
		}
		languages = append(languages, language)
	})
	return languages, nil
}
func (t *Trending) GetDevelopers(time, language string) ([]Developer, error) {
	var developers []Developer
	u, err := t.generateURL(modeDevelopers, time, language)
	if err != nil {
		return developers, err
	}
	res, err := t.Client.Get(u.String())
	if err != nil {
		return developers, err
	}
	doc, err := goquery.NewDocumentFromResponse(res)
	if err != nil {
		return developers, err
	}
	doc.Find(".explore-content li").Each(func(i int, s *goquery.Selection) {
		name := s.Find("h2 a").Text()
		name = strings.TrimSpace(name)
		name = strings.Split(name, " ")[0]
		name = strings.TrimSpace(name)
		fullName := s.Find("h2 a span").Text()
		fullName = t.trimBraces(fullName)
		linkHref, exists := s.Find("h2 a").Attr("href")
		linkURL := t.appendBaseHostToPath(linkHref, exists)
		avatar, exists := s.Find("a img").Attr("src")
		avatarURL := t.buildAvatarURL(avatar, exists)
		developers = append(developers, t.newDeveloper(name, fullName, linkURL, avatarURL))
	})
	return developers, nil
}
func (t *Trending) newDeveloper(name, fullName string, linkURL, avatarURL *url.URL) Developer {
	return Developer{
		ID:          t.getUserIDBasedOnAvatarURL(avatarURL),
		DisplayName: name,
		FullName:    fullName,
		URL:         linkURL,
		Avatar:      avatarURL,
	}
}
func (t *Trending) trimBraces(text string) string {
	text = strings.TrimSpace(text)
	text = strings.TrimLeft(text, "(")
	text = strings.TrimRight(text, ")")
	return text
}
func (t *Trending) buildAvatarURL(avatar string, exists bool) *url.URL {
	if exists == false {
		return nil
	}
	avatarURL, err := url.Parse(avatar)
	if err != nil {
		return nil
	}
	q := avatarURL.Query()
	q.Del("s")
	avatarURL.RawQuery = q.Encode()
	return avatarURL
}
func (t *Trending) getUserIDBasedOnAvatarURL(avatarURL *url.URL) int {
	id := 0
	if avatarURL == nil {
		return id
	}
	re := regexp.MustCompile("u/([0-9]+)")
	if matches := re.FindStringSubmatch(avatarURL.Path); len(matches) >= 2 && len(matches[1]) > 0 {
		id, _ = strconv.Atoi(matches[1])
	}
	return id
}