You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: project.go
    path of file: ./repos/devdash/internal
    
    the code of the file until where you have to start completion: package internal

// Dispatch the different widgets from the config to their widget managers and get back the render functions.

// TODO it's a mess in there between concurrent / non concurrent ways of getting widget render functions.
// TODO Initially it was made to go around the limitation of concurrent connection for Google Analytics.
// TODO I feel the absence of generics here...  To refactor somehow (using reflection?).

import (
	"github.com/pkg/errors"
)

type service interface {
	CreateWidgets(widget Widget, tui *Tui) (f func() error, err error)
}

type project struct {
	name        string
	nameOptions map[string]string
	widgets     [][][]Widget
	sizes       [][]string
	themes      map[string]map[string]string
	tui         *Tui

	gaWidget         service
	monitorWidget    service
	gscWidget        service
	githubWidget     service
	travisCIWidget   service
	feedly
    
func (p *project) CreateWidgets() [][][]func() error {
	// TODO: use display.box instead of this shortcut
	err := p.addTitle(p.tui)
	if err != nil {
		err = errors.Wrapf(err, "can't add project title %s", p.name)
		DisplayError(p.tui, err)()
	}

	chs := make([][][]chan func() error, len(p.widgets))

	for ir, row := range p.widgets {
		for ic, col := range row {
			chs[ir] = append(chs[ir], []chan func() error{})
			for _, w := range col {
				w = p.addDefaultTheme(w)
				ch := make(chan func() error)
				chs[ir][ic] = append(chs[ir][ic], ch)

				service, err := p.mapServiceID(w.serviceID())
				if err != nil {
					go func(c chan<- func() error) {
						c <- DisplayError(p.tui, err)
					}(ch)
					continue
				}

				serviceName, err := mapServiceName(w.serviceID())
				if err != nil {
					go func(c chan<- func() error) {
						c <- DisplayError(p.tui, err)
					}(ch)
					continue
				}

				go getRenderers(service, serviceName, w, p.tui, ch)
			}
		}
	}

	funcs := make([][][]func() error, len(chs))
	for r, _ := range chs {
		for c, _ := range chs[r] {
			funcs[r] = append(funcs[r], []func() error{})
			for _, chann := range chs[r][c] {
				f, ok := <-chann
				if ok {
					funcs[r][c] = append(funcs[r][c], f)
				}
			}
		}
	}

	return funcs
}