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: identify.go
    path of file: ./repos/client/go/chat
    
    the code of the file until where you have to start completion: package chat

import (
	"context"
	"fmt"
	"strings"
	"sync"

	"golang.org/x/sync/errgroup"

	"github.com/keybase/client/go/chat/globals"
	"github.com/keybase/client/go/chat/storage"
	"github.com/keybase/client/go/chat/utils"
	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
)

type DummyIdentifyNotifier struct{}

func (d DummyIdentifyNotifier) Reset()             {}
func (d DummyIdentifyNotifier) ResetOnGUIConnect() {}
func (d DummyIdentifyNotifier) Send(ctx context.Context, update keybase1.CanonicalTLFNameAndIDWithBreaks) {
}

type SimpleIdentifyNotifier struct {
	globals.Contextified
	utils.DebugLabeler
	storage *storage.Storage
}

func NewSimpleIdentifyNotifier(g *globals.Context) *SimpleIdentifyNotifier {
	return &SimpleIdentifyNotifier{
		Contextified: globals.NewContextified(g),
		DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "SimpleIdentifyNotifier", false),
		storage:      storage.New(g, g.ConvSource),
	}
}

func (d *SimpleIdentifyNotifier) Reset()             {}
func (d *SimpleIdentifyNotifier) ResetOnGUIConnect() {}

func (d *SimpleIdentifyNotifier) Send(ctx context.Context, update keybase1.CanonicalTLFNameAndIDWithBreaks) {
	// Send to storage as well (charge forward on error)
	if err := d.storage.UpdateTLFIdentifyBreak(ctx, update.TlfID.ToBytes(), update.Breaks.Breaks); err != nil {
		d.Debug(ctx, "failed to update storage with TLF i
    
func (t *NameIdentifier) identifyUser(ctx context.Context, assertion string, private bool, idBehavior keybase1.TLFIdentifyBehavior) (keybase1.TLFIdentifyFailure, error) {
	reason := "You accessed a public conversation."
	if private {
		reason = fmt.Sprintf("You accessed a private conversation with %s.", assertion)
	}

	arg := keybase1.Identify2Arg{
		UserAssertion:    assertion,
		UseDelegateUI:    false,
		Reason:           keybase1.IdentifyReason{Reason: reason},
		CanSuppressUI:    true,
		IdentifyBehavior: idBehavior,
	}

	uis := libkb.UIs{
		IdentifyUI: chatNullIdentifyUI{},
	}
	eng := engine.NewResolveThenIdentify2(t.G().ExternalG(), &arg)
	m := libkb.NewMetaContext(ctx, t.G().ExternalG()).WithUIs(uis)
	if err := engine.RunEngine2(m, eng); err != nil {
		switch err.(type) {
		// Ignore these errors
		// NOTE: Even though we ignore a `libkb.UserDeletedError` here, if we have
		// previously chatted with the user we will still validate the sigchain
		// when identifying the user and then return this error.
		case libkb.NotFoundError, libkb.ResolutionError, libkb.UserDeletedError:
			return keybase1.TLFIdentifyFailure{}, nil
		}
		return keybase1.TLFIdentifyFailure{}, err
	}
	resp, err := eng.Result(m)
	if err != nil {
		return keybase1.TLFIdentifyFailure{}, err
	}
	var frep keybase1.TLFIdentifyFailure
	if resp != nil && resp.TrackBreaks != nil {
		frep.User = resp.Upk.ExportToSimpleUser()
		frep.Breaks = resp.TrackBreaks
	}

	return frep, nil
}