code: func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {
  	// Sanity check interfaces
  	if dst == nil || src == nil {
  		return 0, fmt.Errorf("src/dst reader/writer nil")
  	}
  	if len(keys) == 0 {
  		// Default keys : ctrl-p ctrl-q
  		keys = []byte{16, 17}
  	}
  
  	buf := make([]byte, 32*1024)
  	for {
  		nr, er := src.Read(buf)
  		if nr > 0 {
  			preservBuf := []byte{}
  			for i, key := range keys {
  				preservBuf = append(preservBuf, buf[0:nr]...)
  				if nr != 1 || buf[0] != key {
  					break
  				}
  				if i == len(keys)-1 {
  					// src.Close()
  					return 0, DetachError{}
  				}
  				nr, er = src.Read(buf)
  			}
  			nw, ew := dst.Write(preservBuf)
  			nr = len(preservBuf)
  			if nw > 0 {
  				written += int64(nw)
  			}
  			if ew != nil {
  				err = ew
  				break
  			}
  			if nr != nw {
  				err = io.ErrShortWrite
  				break
  			}
  		}
  		if er != nil {
  			if er != io.EOF {
  				err = er
  			}
  			break
  		}
  	}
  	return written, err
  }
docs: // CopyDetachable is similar to io.Copy but support a detach key sequence to break out.