func (m *Mutation) DeleteCellsInColumn(family, column string) {
	m.ops = append(m.ops, &btdpb.Mutation{Mutation: &btdpb.Mutation_DeleteFromColumn_{&btdpb.Mutation_DeleteFromColumn{
		FamilyName:      family,
		ColumnQualifier: []byte(column),
	}}})
}
DeleteCellsInColumn will delete all the cells whose columns are family:column.
package bigtable
import (
	"fmt"
	"io"
	"strconv"
	"time"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/cloud"
	btdpb "google.golang.org/cloud/bigtable/internal/data_proto"
	btspb "google.golang.org/cloud/bigtable/internal/service_proto"
	"google.golang.org/cloud/internal/transport"
	"google.golang.org/grpc"
)
const prodAddr = "bigtable.googleapis.com:443"
type Client struct {
	conn   *grpc.ClientConn
	client btspb.BigtableServiceClient
	project, zone, cluster string
}
func NewClient(ctx context.Context, project, zone, cluster string, opts ...cloud.ClientOption) (*Client, error) {
	o := []cloud.ClientOption{
		cloud.WithEndpoint(prodAddr),
		cloud.WithScopes(Scope),
		cloud.WithUserAgent(clientUserAgent),
	}
	o = append(o, opts...)
	conn, err := transport.DialGRPC(ctx, o...)
	if err != nil {
		return nil, fmt.Errorf("dialing: %v", err)
	}
	return &Client{
		conn:   conn,
		client: btspb.NewBigtableServiceClient(conn),
		project: project,
		zone:    zone,
		cluster: cluster,
	}, nil
}
func (c *Client) Close() {
	c.conn.Close()
}
func (c *Client) fullTableName(table string) string {
	return fmt.Sprintf("projects/%s/zones/%s/clusters/%s/tables/%s", c.project, c.zone, c.cluster, table)
}
type Table struct {
	c     *Client
	table string
}
func (c *Client) Open(table string) *Table {
	return &Table{
		c:     c,
		table: table,
	}
}
func (t *Table) ReadRows(ctx context.Context, arg RowRange, f func(Row) bool, opts ...ReadOption) error {
	req := &btspb.ReadRowsRequest{
		TableName: t.c.fullTableName(t.table),
		Target:    &btspb.ReadRowsRequest_RowRange{arg.proto()},
	}
	for _, opt := range opts {
		opt.set(req)
	}
	ctx, cancel := context.WithCancel(ctx)  
	defer cancel()
	stream, err := t.c.client.ReadRows(ctx, req)
	if err != nil {
		return err
	}
	cr := new(chunkReader)
	for {
		res, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		if row := cr.process(res); row != nil {
			if !f(row) {
				cancel()
				for {
					if _, err := stream.Recv(); err != nil {
						return nil
					}
				}
			}
		}
	}
	return nil
}
func (t *Table) ReadRow(ctx context.Context, row string, opts ...ReadOption) (Row, error) {
	var r Row
	err := t.ReadRows(ctx, SingleRow(row), func(rr Row) bool {
		r = rr
		return true
	}, opts...)
	return r, err
}
type chunkReader struct {
	partial map[string]Row  
}
func (cr *chunkReader) process(rrr *btspb.ReadRowsResponse) Row {
	if cr.partial == nil {
		cr.partial = make(map[string]Row)
	}
	row := string(rrr.RowKey)
	r := cr.partial[row]
	if r == nil {
		r = make(Row)
		cr.partial[row] = r
	}
	for _, chunk := range rrr.Chunks {
		switch c := chunk.Chunk.(type) {
		case *btspb.ReadRowsResponse_Chunk_ResetRow:
			r = make(Row)
			cr.partial[row] = r
			continue
		case *btspb.ReadRowsResponse_Chunk_CommitRow:
			delete(cr.partial, row)
			if len(r) == 0 {
				continue
			}
			return r  
		case *btspb.ReadRowsResponse_Chunk_RowContents:
			decodeFamilyProto(r, row, c.RowContents)
		}
	}
	return nil
}
func decodeFamilyProto(r Row, row string, f *btdpb.Family) {
	fam := f.Name  
	for _, col := range f.Columns {
		for _, cell := range col.Cells {
			ri := ReadItem{
				Row:       row,
				Column:    fmt.Sprintf("%s:%s", fam, col.Qualifier),
				Timestamp: Timestamp(cell.TimestampMicros),
				Value:     cell.Value,
			}
			r[fam] = append(r[fam], ri)
		}
	}
}
type RowRange struct {
	start string
	limit string
}
func NewRange(begin, end string) RowRange {
	return RowRange{
		start: begin,
		limit: end,
	}
}
func (r RowRange) Unbounded() bool {
	return r.limit == ""
}
func (r RowRange) Contains(row string) bool {
	return r.start <= row && (r.limit == "" || r.limit > row)
}
func (r RowRange) String() string {
	a := strconv.Quote(r.start)
	if r.Unbounded() {
		return fmt.Sprintf("[%s,∞)", a)
	}
	return fmt.Sprintf("[%s,%q)", a, r.limit)
}
func (r RowRange) proto() *btdpb.RowRange {
	if r.Unbounded() {
		return &btdpb.RowRange{StartKey: []byte(r.start)}
	}
	return &btdpb.RowRange{
		StartKey: []byte(r.start),
		EndKey:   []byte(r.limit),
	}
}
func SingleRow(row string) RowRange {
	return RowRange{
		start: row,
		limit: row + "\x00",
	}
}
func PrefixRange(prefix string) RowRange {
	return RowRange{
		start: prefix,
		limit: prefixSuccessor(prefix),
	}
}
func InfiniteRange(start string) RowRange {
	return RowRange{
		start: start,
		limit: "",
	}
}
func prefixSuccessor(prefix string) string {
	if prefix == "" {
		return ""  
	}
	n := len(prefix)
	for n--; n >= 0 && prefix[n] == '\xff'; n-- {
	}
	if n == -1 {
		return ""
	}
	ans := []byte(prefix[:n])
	ans = append(ans, prefix[n]+1)
	return string(ans)
}
type ReadOption interface {
	set(req *btspb.ReadRowsRequest)
}
func RowFilter(f Filter) ReadOption { return rowFilter{f} }
type rowFilter struct{ f Filter }
func (rf rowFilter) set(req *btspb.ReadRowsRequest) { req.Filter = rf.f.proto() }
func LimitRows(limit int64) ReadOption { return limitRows{limit} }
type limitRows struct{ limit int64 }
func (lr limitRows) set(req *btspb.ReadRowsRequest) { req.NumRowsLimit = lr.limit }
type Row map[string][]ReadItem
func (r Row) Key() string {
	for _, items := range r {
		if len(items) > 0 {
			return items[0].Row
		}
	}
	return ""
}
type ReadItem struct {
	Row, Column string
	Timestamp   Timestamp
	Value       []byte
}
func (t *Table) Apply(ctx context.Context, row string, m *Mutation, opts ...ApplyOption) error {
	after := func(res proto.Message) {
		for _, o := range opts {
			o.after(res)
		}
	}
	if m.cond == nil {
		req := &btspb.MutateRowRequest{
			TableName: t.c.fullTableName(t.table),
			RowKey:    []byte(row),
			Mutations: m.ops,
		}
		res, err := t.c.client.MutateRow(ctx, req)
		if err == nil {
			after(res)
		}
		return err
	}
	req := &btspb.CheckAndMutateRowRequest{
		TableName:       t.c.fullTableName(t.table),
		RowKey:          []byte(row),
		PredicateFilter: m.cond.proto(),
	}
	if m.mtrue != nil {
		req.TrueMutations = m.mtrue.ops
	}
	if m.mfalse != nil {
		req.FalseMutations = m.mfalse.ops
	}
	res, err := t.c.client.CheckAndMutateRow(ctx, req)
	if err == nil {
		after(res)
	}
	return err
}
type ApplyOption interface {
	after(res proto.Message)
}
type applyAfterFunc func(res proto.Message)
func (a applyAfterFunc) after(res proto.Message) { a(res) }
func GetCondMutationResult(matched *bool) ApplyOption {
	return applyAfterFunc(func(res proto.Message) {
		if res, ok := res.(*btspb.CheckAndMutateRowResponse); ok {
			*matched = res.PredicateMatched
		}
	})
}
type Mutation struct {
	ops []*btdpb.Mutation
	cond          Filter
	mtrue, mfalse *Mutation
}
func NewMutation() *Mutation {
	return new(Mutation)
}
func NewCondMutation(cond Filter, mtrue, mfalse *Mutation) *Mutation {
	return &Mutation{cond: cond, mtrue: mtrue, mfalse: mfalse}
}
func (m *Mutation) Set(family, column string, ts Timestamp, value []byte) {
	if ts != ServerTime {
		ts -= ts % 1000
	}
	m.ops = append(m.ops, &btdpb.Mutation{Mutation: &btdpb.Mutation_SetCell_{&btdpb.Mutation_SetCell{
		FamilyName:      family,
		ColumnQualifier: []byte(column),
		TimestampMicros: int64(ts),
		Value:           value,
	}}})
}