func NewCloseFrame(p []byte) *Frame {
	return NewFrame(OpClose, true, p)
}
NewCloseFrame creates close frame with given close body.
Note that p is not copied.
Note that p must have length of MaxControlFramePayloadSize bytes or less due
to RFC.
package ws
import (
	"encoding/binary"
)
const (
	MaxControlFramePayloadSize = 125
)
type OpCode byte
const (
	OpContinuation OpCode = 0x0
	OpText         OpCode = 0x1
	OpBinary       OpCode = 0x2
	OpClose        OpCode = 0x8
	OpPing         OpCode = 0x9
	OpPong         OpCode = 0xa
)
func (c OpCode) IsControl() bool {
	return c&0x8 != 0
}
func (c OpCode) IsData() bool {
	return c&0x8 == 0
}
func (c OpCode) IsReserved() bool {
	return (0x3 <= c && c <= 0x7) || (0xb <= c && c <= 0xf)
}
type StatusCode uint16
type StatusCodeRange struct {
	Min, Max StatusCode
}
var (
	StatusRangeNotInUse    = StatusCodeRange{0, 999}
	StatusRangeProtocol    = StatusCodeRange{1000, 2999}
	StatusRangeApplication = StatusCodeRange{3000, 3999}
	StatusRangePrivate     = StatusCodeRange{4000, 4999}
)
const (
	StatusNormalClosure           StatusCode = 1000
	StatusGoingAway               StatusCode = 1001
	StatusProtocolError           StatusCode = 1002
	StatusUnsupportedData         StatusCode = 1003
	StatusNoMeaningYet            StatusCode = 1004
	StatusInvalidFramePayloadData StatusCode = 1007
	StatusPolicyViolation         StatusCode = 1008
	StatusMessageTooBig           StatusCode = 1009
	StatusMandatoryExt            StatusCode = 1010
	StatusInternalServerError     StatusCode = 1011
	StatusTLSHandshake            StatusCode = 1015
	StatusAbnormalClosure StatusCode = 1006
	StatusNoStatusRcvd StatusCode = 1005
)
func (s StatusCode) In(r StatusCodeRange) bool {
	return r.Min <= s && s <= r.Max
}
func (s StatusCode) Empty() bool {
	return s == 0
}
func (s StatusCode) IsNotUsed() bool {
	return s.In(StatusRangeNotInUse)
}
func (s StatusCode) IsApplicationSpec() bool {
	return s.In(StatusRangeApplication)
}
func (s StatusCode) IsPrivateSpec() bool {
	return s.In(StatusRangePrivate)
}
func (s StatusCode) IsProtocolSpec() bool {
	return s.In(StatusRangeProtocol)
}
func (s StatusCode) IsProtocolDefined() bool {
	switch s {
	case StatusNormalClosure,
		StatusGoingAway,
		StatusProtocolError,
		StatusUnsupportedData,
		StatusInvalidFramePayloadData,
		StatusPolicyViolation,
		StatusMessageTooBig,
		StatusMandatoryExt,
		StatusInternalServerError,
		StatusNoStatusRcvd,
		StatusAbnormalClosure,
		StatusTLSHandshake:
		return true
	}
	return false
}
func (s StatusCode) IsProtocolReserved() bool {
	switch s {
	case StatusNoStatusRcvd, StatusAbnormalClosure, StatusTLSHandshake:
		return true
	default:
		return false
	}
}
type Header struct {
	Fin    bool
	Rsv    byte
	OpCode OpCode
	Masked bool
	Mask   [4]byte
	Length int64
}
func (h Header) Rsv1() bool { return h.Rsv&bit5 != 0 }
func (h Header) Rsv2() bool { return h.Rsv&bit6 != 0 }
func (h Header) Rsv3() bool { return h.Rsv&bit7 != 0 }
type Frame struct {
	Header  Header
	Payload []byte
}
func NewFrame(op OpCode, fin bool, p []byte) *Frame {
	return &Frame{
		Header: Header{
			Fin:    fin,
			OpCode: op,
			Length: int64(len(p)),
		},
		Payload: p,
	}
}
func NewTextFrame(p []byte) *Frame {
	return NewFrame(OpText, true, p)
}
func NewBinaryFrame(p []byte) *Frame {
	return NewFrame(OpBinary, true, p)
}
func NewPingFrame(p []byte) *Frame {
	return NewFrame(OpPing, true, p)
}
func NewPongFrame(p []byte) *Frame {
	return NewFrame(OpPong, true, p)
}