func (b *block) Write(p []byte) (int, error) {
	if b.err != nil {
		return 0, b.err
	}
	b.buf = append(b.buf, p...)
	l := (len(b.buf) / b.size) * b.size
	if l > 0 {
		n, err := b.w.Write(b.buf[:l])
		copy(b.buf, b.buf[l:])
		b.buf = b.buf[:len(b.buf)-l]
		if err != nil {
			b.err = err
			return n, err
		}
	}
	return len(p), nil
}
Write implements the io.Writer interface.
package wrapio
import (
	"fmt"
	"hash"
	"io"
	"sync"
)
type wrap struct {
	handler func([]byte)
	r       io.Reader
	w       io.Writer
}
func (w *wrap) Read(p []byte) (int, error) {
	n, err := w.r.Read(p)
	if n > 0 {
		w.handler(p[:n])
	}
	return n, err
}
func (w *wrap) Write(p []byte) (int, error) {
	w.handler(p)
	return w.w.Write(p)
}
func NewFuncReader(handler func([]byte), r io.Reader) io.Reader {
	if handler == nil || r == nil {
		return nil
	}
	return &wrap{handler: handler, r: r}
}
func NewFuncWriter(handler func([]byte), w io.Writer) io.Writer {
	if handler == nil || w == nil {
		return nil
	}
	return &wrap{handler: handler, w: w}
}
func NewHashReader(h hash.Hash, r io.Reader) io.Reader {
	if h == nil {
		return nil
	}
	return NewFuncReader(func(p []byte) {
		h.Write(p)
	}, r)
}
func NewHashWriter(h hash.Hash, w io.Writer) io.Writer {
	if h == nil {
		return nil
	}
	return NewFuncWriter(func(p []byte) {
		h.Write(p)
	}, w)
}
type Stats struct {
	sync.Mutex
	Total   int      
	Average float64  
	Calls   int      
}
func (s Stats) String() string {
	return fmt.Sprintf("[Total: %d, Average: %f, Calls: %d]",
		s.Total, s.Average, s.Calls)
}
func (s *Stats) update(p []byte) {
	s.Lock()
	defer s.Unlock()
	s.Total += len(p)
	s.Calls++
	s.Average = float64(s.Total / s.Calls)
}
func NewStatsReader(r io.Reader) (*Stats, io.Reader) {
	s := &Stats{}
	return s, NewFuncReader(s.update, r)
}
func NewStatsWriter(w io.Writer) (*Stats, io.Writer) {
	s := &Stats{}
	return s, NewFuncWriter(s.update, w)
}
type block struct {
	r    io.Reader
	w    io.Writer
	size int
	buf  []byte
	err  error  
}
func (b *block) Read(p []byte) (int, error) {
	if b.err != nil && len(b.buf) == 0 {
		return 0, b.err
	}
	n := (len(p) / b.size) * b.size
	if n == 0 {
		return 0, nil
	}
	if b.err == nil {
		l, err := b.r.Read(p)
		b.err = err
		b.buf = append(b.buf, p[:l]...)
	}
	if n > len(b.buf) {
		n = (len(b.buf) / b.size) * b.size
	}
	if b.err != nil && n == 0 {
		n = len(b.buf)
	}
	copy(p, b.buf[:n])
	copy(b.buf, b.buf[n:])
	b.buf = b.buf[:len(b.buf)-n]
	return n, nil
}