func (z *Writer) Close() error {
	if z.checkError() != nil {
		return z.err
	}
	if z.closed {
		return nil
	}
	z.closed = true
	if !z.wroteHeader {
		z.Write(nil)
		if z.err != nil {
			return z.err
		}
	}
	z.compressCurrent(true)
	if z.checkError() != nil {
		return z.err
	}
	close(z.results)
	put4(z.buf[0:4], z.digest.Sum32())
	put4(z.buf[4:8], uint32(z.size))
	_, z.err = z.w.Write(z.buf[0:8])
	return z.err
}
Close closes the Writer, flushing any unwritten data to the underlying
io.Writer, but does not close the underlying io.Writer.
package pgzip
import (
	"bytes"
	"errors"
	"fmt"
	"hash"
	"io"
	"sync"
	"github.com/klauspost/compress/flate"
	"github.com/klauspost/crc32"
)
const (
	defaultBlockSize = 250000
	tailSize         = 16384
	defaultBlocks    = 16
)
const (
	NoCompression       = flate.NoCompression
	BestSpeed           = flate.BestSpeed
	BestCompression     = flate.BestCompression
	DefaultCompression  = flate.DefaultCompression
	ConstantCompression = flate.ConstantCompression
)
type Writer struct {
	Header
	w             io.Writer
	level         int
	wroteHeader   bool
	blockSize     int
	blocks        int
	currentBuffer []byte
	prevTail      []byte
	digest        hash.Hash32
	size          int
	closed        bool
	buf           [10]byte
	err           error
	pushedErr     chan error
	results       chan result
	dictFlatePool *sync.Pool
	dstPool       *sync.Pool
}
type result struct {
	result        chan []byte
	notifyWritten chan struct{}
}
func (z *Writer) SetConcurrency(blockSize, blocks int) error {
	if blockSize <= tailSize {
		return fmt.Errorf("gzip: block size cannot be less than or equal to %d", tailSize)
	}
	if blocks <= 0 {
		return errors.New("gzip: blocks cannot be zero or less")
	}
	z.blockSize = blockSize
	z.results = make(chan result, blocks)
	z.blocks = blocks
	return nil
}
func NewWriter(w io.Writer) *Writer {
	z, _ := NewWriterLevel(w, DefaultCompression)
	return z
}
func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
	if level < ConstantCompression || level > BestCompression {
		return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
	}
	z := new(Writer)
	z.SetConcurrency(defaultBlockSize, defaultBlocks)
	z.init(w, level)
	return z, nil
}
func (z *Writer) pushError(err error) {
	z.pushedErr <- err
	close(z.pushedErr)
}
func (z *Writer) init(w io.Writer, level int) {
	digest := z.digest
	if digest != nil {
		digest.Reset()
	} else {
		digest = crc32.NewIEEE()
	}
	*z = Writer{
		Header: Header{
			OS: 255,  
		},
		w:         w,
		level:     level,
		digest:    digest,
		pushedErr: make(chan error, 1),
		results:   make(chan result, z.blocks),
		blockSize: z.blockSize,
		blocks:    z.blocks,
	}
	z.dictFlatePool = &sync.Pool{
		New: func() interface{} {
			f, _ := flate.NewWriterDict(w, level, nil)
			return f
		},
	}
	z.dstPool = &sync.Pool{New: func() interface{} { return make([]byte, 0, z.blockSize) }}
}
func (z *Writer) Reset(w io.Writer) {
	if z.results != nil && !z.closed {
		close(z.results)
	}
	z.SetConcurrency(defaultBlockSize, defaultBlocks)
	z.init(w, z.level)
}
func put2(p []byte, v uint16) {
	p[0] = uint8(v >> 0)
	p[1] = uint8(v >> 8)
}
func put4(p []byte, v uint32) {
	p[0] = uint8(v >> 0)
	p[1] = uint8(v >> 8)
	p[2] = uint8(v >> 16)
	p[3] = uint8(v >> 24)
}
func (z *Writer) writeBytes(b []byte) error {
	if len(b) > 0xffff {
		return errors.New("gzip.Write: Extra data is too large")
	}
	put2(z.buf[0:2], uint16(len(b)))
	_, err := z.w.Write(z.buf[0:2])
	if err != nil {
		return err
	}
	_, err = z.w.Write(b)
	return err
}
func (z *Writer) writeString(s string) (err error) {
	needconv := false
	for _, v := range s {
		if v == 0 || v > 0xff {
			return errors.New("gzip.Write: non-Latin-1 header string")
		}
		if v > 0x7f {
			needconv = true
		}
	}
	if needconv {
		b := make([]byte, 0, len(s))
		for _, v := range s {
			b = append(b, byte(v))
		}
		_, err = z.w.Write(b)
	} else {
		_, err = io.WriteString(z.w, s)
	}
	if err != nil {
		return err
	}
	z.buf[0] = 0
	_, err = z.w.Write(z.buf[0:1])
	return err
}
func (z *Writer) compressCurrent(flush bool) {
	r := result{}
	r.result = make(chan []byte, 1)
	r.notifyWritten = make(chan struct{}, 0)
	z.results <- r
	c := z.currentBuffer
	if len(c) > z.blockSize*2 {
		c = c[:z.blockSize]
		go compressBlock(c, z.prevTail, *z, r)
		z.prevTail = c[len(c)-tailSize:]
		z.currentBuffer = z.currentBuffer[z.blockSize:]
		z.compressCurrent(flush)
		return
	}
	go compressBlock(c, z.prevTail, *z, r)
	if len(c) > tailSize {
		z.prevTail = c[len(c)-tailSize:]
	} else {
		z.prevTail = nil
	}
	z.currentBuffer = make([]byte, 0, z.blockSize+(z.blockSize/4))
	if flush {
		_ = <-r.notifyWritten
	}
}
func (z *Writer) checkError() error {
	if z.err != nil {
		return z.err
	}
	select {
	case err := <-z.pushedErr:
		z.err = err
	default:
	}
	return z.err
}
func (z *Writer) Write(p []byte) (int, error) {
	if z.checkError() != nil {
		return 0, z.err
	}
	if !z.wroteHeader {
		z.wroteHeader = true
		z.buf[0] = gzipID1
		z.buf[1] = gzipID2
		z.buf[2] = gzipDeflate
		z.buf[3] = 0
		if z.Extra != nil {
			z.buf[3] |= 0x04
		}
		if z.Name != "" {
			z.buf[3] |= 0x08
		}
		if z.Comment != "" {
			z.buf[3] |= 0x10
		}
		put4(z.buf[4:8], uint32(z.ModTime.Unix()))
		if z.level == BestCompression {
			z.buf[8] = 2
		} else if z.level == BestSpeed {
			z.buf[8] = 4
		} else {
			z.buf[8] = 0
		}
		z.buf[9] = z.OS
		var n int
		n, z.err = z.w.Write(z.buf[0:10])
		if z.err != nil {
			return n, z.err
		}
		if z.Extra != nil {
			z.err = z.writeBytes(z.Extra)
			if z.err != nil {
				return n, z.err
			}
		}
		if z.Name != "" {
			z.err = z.writeString(z.Name)
			if z.err != nil {
				return n, z.err
			}
		}
		if z.Comment != "" {
			z.err = z.writeString(z.Comment)
			if z.err != nil {
				return n, z.err
			}
		}
		go func() {
			listen := z.results
			for {
				r, ok := <-listen
				if !ok {
					return
				}
				buf := <-r.result
				n, err := z.w.Write(buf)
				if err != nil {
					z.pushError(err)
					close(r.notifyWritten)
					return
				}
				if n != len(buf) {
					z.pushError(fmt.Errorf("gzip: short write %d should be %d", n, len(buf)))
					close(r.notifyWritten)
					return
				}
				z.dstPool.Put(buf)
				close(r.notifyWritten)
			}
		}()
		z.currentBuffer = make([]byte, 0, z.blockSize+(z.blockSize/4))
	}
	if len(p) > z.blockSize*z.blocks {
		q := p
		for len(q) > 0 {
			length := len(q)
			if length > z.blockSize {
				length = z.blockSize
			}
			z.digest.Write(q[:length])
			z.currentBuffer = append(z.currentBuffer, q[:length]...)
			if len(z.currentBuffer) >= z.blockSize {
				z.compressCurrent(false)
				if z.err != nil {
					return len(p) - len(q) - length, z.err
				}
			}
			z.size += length
			q = q[length:]
		}
		return len(p), z.err
	} else {
		z.size += len(p)
		z.digest.Write(p)
		z.currentBuffer = append(z.currentBuffer, p...)
		if len(z.currentBuffer) >= z.blockSize {
			z.compressCurrent(false)
		}
		return len(p), z.err
	}
}
func compressBlock(p, prevTail []byte, z Writer, r result) {
	defer close(r.result)
	buf := z.dstPool.Get().([]byte)
	dest := bytes.NewBuffer(buf[:0])
	compressor := z.dictFlatePool.Get().(*flate.Writer)
	compressor.ResetDict(dest, prevTail)
	compressor.Write(p)
	err := compressor.Flush()
	if err != nil {
		z.pushError(err)
		return
	}
	if z.closed {
		err = compressor.Close()
		if err != nil {
			z.pushError(err)
			return
		}
	}
	z.dictFlatePool.Put(compressor)
	buf = dest.Bytes()
	r.result <- buf
}
func (z *Writer) Flush() error {
	if z.checkError() != nil {
		return z.err
	}
	if z.closed {
		return nil
	}
	if !z.wroteHeader {
		_, err := z.Write(nil)
		if err != nil {
			return err
		}
	}
	z.compressCurrent(true)
	if z.checkError() != nil {
		return z.err
	}
	return nil
}
func (z Writer) UncompressedSize() int {
	return z.size
}