func startClient(clientConfig clientConfigStruct, dbi *mysqlCredentials) {
	db, err := dbi.connect()
	defer db.Close()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	var ignore string
	var maxConnections int
	err = db.QueryRow("show global variables like 'max_connections'").Scan(&ignore, &maxConnections)
	checkErr(err)
	if maxConnections > clientConfig.triteMaxConnections {
		db.SetMaxOpenConns(clientConfig.triteMaxConnections)
	} else {
		fmt.Fprintln(os.Stderr, "MySQL max connections is lower than", clientConfig.triteMaxConnections)
		fmt.Fprintln(os.Stderr, "Increase MySQL's max_connections variable or decrease triteMaxConnections")
		os.Exit(1)
	}
	db.SetMaxIdleConns(0)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	var version string
	err = db.QueryRow("show global variables like 'version'").Scan(&ignore, &version)
	checkErr(err)
	var importFlag string
	if strings.HasPrefix(version, "5.1") || strings.HasPrefix(version, "5.5") {
		err = db.QueryRow("show global variables like '%innodb%import%'").Scan(&importFlag, &ignore)
		checkErr(err)
		_, err = db.Exec("set global " + importFlag + "=1")
		checkErr(err)
	} else if strings.HasPrefix(version, "5.6") || strings.HasPrefix(version, "10") {
	} else {
		fmt.Fprintln(os.Stderr, version, "is not supported")
		os.Exit(1)
	}
	var mysqldir string
	err = db.QueryRow("show variables like 'datadir'").Scan(&ignore, &mysqldir)
	checkErr(err)
	err = ioutil.WriteFile(mysqldir+"/trite_test", []byte("delete\n"), mysqlPerms)
	if err != nil {
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, "The MySQL data directory is not writable as this user!")
		fmt.Fprintln(os.Stderr)
		os.Exit(1)
	} else {
		os.Remove(mysqldir + "/trite_test")
	}
	taburl := "http://" + clientConfig.triteServerURL + ":" + clientConfig.triteServerPort + "/tables/"
	backurl := "http://" + clientConfig.triteServerURL + ":" + clientConfig.triteServerPort + "/backups/"
	gzurl := "http://" + clientConfig.triteServerURL + ":" + clientConfig.triteServerPort + "/gz/"
	urls := []string{taburl, backurl}
	for _, url := range urls {
		_, err = http.Head(url)
		if err != nil {
			fmt.Fprintln(os.Stderr)
			fmt.Fprintln(os.Stderr)
			fmt.Fprintln(os.Stderr, "Problem connecting to", url)
			fmt.Fprintln(os.Stderr, "Check that the server is running, port number is correct or that a firewall is not blocking access")
			os.Exit(1)
		}
	}
	base, err := http.Get(taburl)
	checkHTTP(base, taburl)
	defer base.Body.Close()
	checkErr(err)
	schemas := parseAnchor(base)
	var wgDownload sync.WaitGroup
	dl := make(chan downloadInfoStruct)
	go func() {
		for d := range dl {
			downloadTable(clientConfig, d)
			wgDownload.Done()
		}
	}()
	displayChan := make(chan displayInfoStruct)
	go display(displayChan)
	var wgApply sync.WaitGroup
	for _, schema := range schemas {
		checkSchema(db, schema, taburl+path.Join(schema, schema+sqlExtension))
		tablesDir, err := http.Get(taburl + path.Join(schema, "tables"))
		checkHTTP(tablesDir, taburl+path.Join(schema, "tables"))
		defer tablesDir.Body.Close()
		checkErr(err)
		tables := parseAnchor(tablesDir)
		if len(tables) > 0 {
			for _, table := range tables {
				wgDownload.Add(1)
				wgApply.Add(1)
				downloadInfo := downloadInfoStruct{
					db:          db,
					taburl:      taburl,
					backurl:     backurl,
					gzurl:       gzurl,
					schema:      schema,
					table:       table[:len(table)-4],
					mysqldir:    mysqldir,
					uid:         dbi.uid,
					gid:         dbi.gid,
					version:     version,
					displayChan: displayChan,
					wgApply:     &wgApply,
				}
				if mysqlUTF8.NeedsEncoding(downloadInfo.schema) {
					downloadInfo.encodedSchema = mysqlUTF8.EncodeFilename(downloadInfo.schema)
				}
				if mysqlUTF8.NeedsEncoding(downloadInfo.table) {
					downloadInfo.encodedTable = mysqlUTF8.EncodeFilename(downloadInfo.table)
				}
				dl <- downloadInfo
			}
		}
	}
	wgDownload.Wait()
	wgApply.Wait()
	time.Sleep(1 * time.Millisecond)
	fmt.Println()
	objectTypes := []string{"trigger", "view", "procedure", "function"}
	for _, schema := range schemas {
		for _, objectType := range objectTypes {
			applyObjects(db, clientConfig, objectType, schema, taburl)
		}
	}
	if importFlag != "" {
		_, err = db.Exec("set global " + importFlag + "=0")
	}
	errCount := getErrCount()
	if errCount > 0 {
		f, err := os.OpenFile(clientConfig.errorLogFile, os.O_WRONLY|os.O_APPEND, 0644)
		checkErr(err)
		l := log.New(f, "", log.LstdFlags)
		for i := 0; i < 10; i++ {
			l.Println()
		}
		f.Close()
		fmt.Println()
		fmt.Println("! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ")
		fmt.Println(errCount, "errors were encountered")
		fmt.Println("Check", clientConfig.errorLogFile, "for more details")
		fmt.Println("! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ")
	}
}
startClient is responsible for retrieving database creation satements and binary table files from a trite server instance.
package main
import (
	"bufio"
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"text/tabwriter"
	"time"
	"github.com/joshuaprunier/mysqlUTF8"
	"github.com/klauspost/pgzip"
	"golang.org/x/net/html"
)
type (
	clientConfigStruct struct {
		triteServerURL          string
		triteServerPort         string
		triteMaxConnections     int
		errorLogFile            string
		minDownloadProgressSize int64
		gz                      bool
	}
	downloadInfoStruct struct {
		db            *sql.DB
		taburl        string
		backurl       string
		gzurl         string
		schema        string
		table         string
		encodedSchema string
		encodedTable  string
		mysqldir      string
		uid           int
		gid           int
		engine        string
		extensions    []string
		triteFiles    []string
		version       string
		displayInfo   displayInfoStruct
		displayChan   chan displayInfoStruct
		wgApply       *sync.WaitGroup
	}
	displayInfoStruct struct {
		w       io.Writer
		fqTable string
		status  string
	}
)
const (
	mysqlPerms = 0660
)
var (
	displayTable           string
	errCount               int
	errDownloadUnsupported error
	errDownloadExp         error
	errApplyDrop           error
	errDownloadSize        error
	errApplyCreate         error
	errApplyDiscard        error
	errApplyLock           error
	errApplyRename         error
	errApplyImport         error
	errApplyAnalyze        error
	errApplyUnlock         error
	errObjectApply         error
)