func main() {
	fmt.Println("start")
	var credentials *nimbusapi.Credentials
	var err error

	sp := flag.String("credentials", "", "path to credentials file")
	flag.Parse()
	if *sp == "" {
		credentials, err = nimbusapi.LoadCredentialsFromDefault()
	} else {
		credentials, err = nimbusapi.LoadCredentialsFromPath(*sp)
	}
	if err != nil {
		log.Fatalf("Error loading credentials %s\n", err)
	}

	requester, err := nimbusapi.NewRequester(credentials)
	if err != nil {
		log.Fatalf("NewRequester failed %s\n", err)
	}

	collectionList, err := nimbusapi.ListCollections(requester,
		credentials.Name)
	if err != nil {
		log.Fatalf("Request failed %s\n", err)
	}
	fmt.Printf("starting collection list = %v\n", collectionList)

	collectionName := nimbusapi.ReservedCollectionName(credentials.Name,
		fmt.Sprintf("test-%05d", len(collectionList)))
	collection, err := nimbusapi.CreateCollection(requester,
		credentials.Name, collectionName)
	if err != nil {
		log.Fatalf("CreateCollection failed %s\n", err)
	}
	fmt.Printf("created collection = %v\n", collection)

	archiveBody := strings.NewReader(testBody)
	versionIdentifier, err := nimbusapi.Archive(requester, collectionName,
		testKey, nil, archiveBody)
	if err != nil {
		log.Fatalf("Archive failed %s\n", err)
	}
	fmt.Printf("archived key '%s' to version %v\n", testKey, versionIdentifier)

	retrieveBody, err := nimbusapi.Retrieve(requester, collectionName,
		testKey, nimbusapi.RetrieveParams{})
	if err != nil {
		log.Fatalf("Retrieve failed %s\n", err)
	}

	retrieveResult, err := ioutil.ReadAll(retrieveBody)
	retrieveBody.Close()
	if err != nil {
		log.Fatalf("read failed %s\n", err)
	}
	fmt.Printf("retrieved key '%s'; matches testBody = %v\n", testKey,
		string(retrieveResult) == testBody)

	keySlice, _, err := nimbusapi.ListKeysInCollection(requester,
		collectionName)
	if err != nil {
		log.Fatalf("ListKeysInCollection failed %s\n", err)
	}
	for _, keyEntry := range keySlice {
		fmt.Printf("deleting key %v\n", keyEntry)
		err = nimbusapi.DeleteKey(requester, collectionName, keyEntry.Name)
		if err != nil {
			log.Fatalf("DeleteKey %v failed %s\n", keyEntry, err)
		}
	}

	success, err := nimbusapi.DeleteCollection(requester, credentials.Name,
		collectionName)
	if err != nil {
		log.Fatalf("DeleteCollection failed %s\n", err)
	}
	fmt.Printf("deleted collection = %s %v\n", collectionName, success)

	fmt.Println("end")
}
func main() {
	log.Println("program starts")
	flags, err := loadflags()
	if err != nil {
		log.Fatalf("Unable to load flags: %s\n", err)
	}
	log.Printf("flags = %v", flags)

	var credentials *nimbusapi.Credentials
	if flags.credentialsPath == "" {
		credentials, err = nimbusapi.LoadCredentialsFromDefault()
	} else {
		credentials, err = nimbusapi.LoadCredentialsFromPath(
			flags.credentialsPath)
	}
	if err != nil {
		log.Fatalf("Error loading credentials %s\n", err)
	}

	if flags.collection == "" {
		flags.collection = nimbusapi.DefaultCollectionName(credentials.Name)
	}

	info, err := os.Stat(flags.filePath)
	if err != nil {
		log.Fatalf("Unable to stat %s %s", flags.filePath, err)
	}
	sliceCount := int(info.Size() / flags.sliceSize)
	if info.Size()%flags.sliceSize != 0 {
		sliceCount += 1
	}
	log.Printf("archiving %s %d bytes %d slices", flags.filePath, info.Size(),
		sliceCount)

	conjoinedIdentifier, err := startConjoined(credentials, flags)
	if err != nil {
		log.Fatalf("StartConjoined %s %s failed %s", flags.collection,
			flags.key, err)
	}
	log.Printf("conjoined_identifier = %s", conjoinedIdentifier)

	work := make(chan workUnit, sliceCount)
	results := make(chan workResult, sliceCount)
	for id := 0; id < flags.connectionCount; id++ {
		requester, err := nimbusapi.NewRequester(credentials)
		if err != nil {
			log.Fatalf("Error creating requester %s\n", err)
		}
		go worker(id, flags.filePath, requester, work, results)
	}

	var offset int64
	var size = flags.sliceSize
	for conjoinedPart := 1; conjoinedPart <= sliceCount; conjoinedPart++ {
		if conjoinedPart == sliceCount {
			size = info.Size() - offset
		}
		workUnit := workUnit{
			flags.collection,
			flags.key,
			conjoinedIdentifier,
			conjoinedPart,
			offset,
			size,
		}
		work <- workUnit
		offset += size
	}

	var completedSize int64
	for completed := 0; completed < sliceCount; completed++ {
		workResult := <-results
		if workResult.err != nil {
			abortConjoined(credentials, flags, conjoinedIdentifier)
			log.Fatalf("Error in worker %d %s %s\n", workResult.workerID,
				workResult.err, workResult.action)
		}
		completedSize += workResult.size
		completedPercent := int(
			float64(completedSize) / float64(info.Size()) * 100.0)
		log.Printf("worker %d completed conjoinedPart %d %d%%",
			workResult.workerID, workResult.conjoinedPart, completedPercent)
	}
	close(work)
	close(results)

	err = finishConjoined(credentials, flags, conjoinedIdentifier)
	if err != nil {
		log.Fatalf("FinishConjoined %s %s failed %s", flags.collection,
			flags.key, err)
	}
	log.Printf("archive complete %s %s conjoined_identifier = %s",
		flags.collection, flags.key, conjoinedIdentifier)

	log.Println("program ends")
}