func Network(s string) string {
	i := strings.LastIndex(s, ":")
	if i < 0 {
		return "unix"
	}
	host, port := s[:i], s[i+1:]
	if port == "" || !isServiceName(port) {
		return "unix"
	} else if strings.IndexByte(host, '/') >= 0 {
		return "unix"
	}
	return "tcp"
}
Network guesses a network type for the specified address.  The assignment of
a network type uses the following heuristics:

If s does not have the form [host]:port, the network is assigned as "unix".
The network "unix" is also assigned if port == "", port contains characters
other than ASCII letters, digits, and "-", or if host contains a "/".

Otherwise, the network is assigned as "tcp". Note that this function does
not verify whether the address is lexically valid.
package jrpc2
import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"github.com/creachadair/jrpc2/channel"
	"github.com/creachadair/jrpc2/code"
)
type Assigner interface {
	Assign(ctx context.Context, method string) Handler
	Names() []string
}
type Handler interface {
	Handle(context.Context, *Request) (interface{}, error)
}
type Request struct {
	id     json.RawMessage  
	method string           
	params json.RawMessage  
}
func (r *Request) IsNotification() bool { return r.id == nil }
func (r *Request) ID() string { return string(r.id) }
func (r *Request) Method() string { return r.method }
func (r *Request) HasParams() bool { return len(r.params) != 0 }
func (r *Request) UnmarshalParams(v interface{}) error {
	if len(r.params) == 0 {
		return nil
	}
	switch t := v.(type) {
	case *json.RawMessage:
		*t = json.RawMessage(string(r.params))  
		return nil
	case strictFielder:
		dec := json.NewDecoder(bytes.NewReader(r.params))
		dec.DisallowUnknownFields()
		if err := dec.Decode(v); err != nil {
			return Errorf(code.InvalidParams, "invalid parameters: %v", err.Error())
		}
		return nil
	}
	return json.Unmarshal(r.params, v)
}
func (r *Request) ParamString() string { return string(r.params) }
var ErrInvalidVersion = Errorf(code.InvalidRequest, "incorrect version marker")
func ParseRequests(msg []byte) ([]*Request, error) {
	var req jmessages
	if err := req.parseJSON(msg); err != nil {
		return nil, err
	}
	var err error
	out := make([]*Request, len(req))
	for i, req := range req {
		if req.V != Version {
			err = ErrInvalidVersion
		}
		out[i] = &Request{
			id:     fixID(req.ID),
			method: req.M,
			params: req.P,
		}
	}
	return out, err
}
type Response struct {
	id     string
	err    *Error
	result json.RawMessage
	ch     chan *jmessage
	cancel func()
}
func (r *Response) ID() string { return r.id }
func (r *Response) SetID(id string) { r.id = id }
func (r *Response) Error() *Error { return r.err }
func (r *Response) UnmarshalResult(v interface{}) error {
	if r.err != nil {
		return r.err
	}
	switch t := v.(type) {
	case *json.RawMessage:
		*t = json.RawMessage(string(r.result))  
		return nil
	case strictFielder:
		dec := json.NewDecoder(bytes.NewReader(r.result))
		dec.DisallowUnknownFields()
		return dec.Decode(v)
	}
	return json.Unmarshal(r.result, v)
}
func (r *Response) ResultString() string { return string(r.result) }
func (r *Response) MarshalJSON() ([]byte, error) {
	return json.Marshal(&jmessage{
		V:  Version,
		ID: json.RawMessage(r.id),
		R:  r.result,
		E:  r.err,
	})
}
func (r *Response) wait() {
	raw, ok := <-r.ch
	if ok {
		r.err = raw.E
		r.result = raw.R
		close(r.ch)
		r.cancel()  
		if id := string(fixID(raw.ID)); id != r.id {
			panic(fmt.Sprintf("Mismatched response ID %q expecting %q", id, r.id))
		}
	}
}
type jmessages []*jmessage
func (j jmessages) toJSON() ([]byte, error) {
	if len(j) == 1 && !j[0].batch {
		return json.Marshal(j[0])
	}
	return json.Marshal([]*jmessage(j))
}
func (j *jmessages) parseJSON(data []byte) error {
	*j = (*j)[:0]  
	var msgs []json.RawMessage
	var batch bool
	if len(data) == 0 || data[0] != '[' {
		msgs = append(msgs, nil)
		if err := json.Unmarshal(data, &msgs[0]); err != nil {
			return Errorf(code.ParseError, "invalid request message")
		}
	} else if err := json.Unmarshal(data, &msgs); err != nil {
		return Errorf(code.ParseError, "invalid request batch")
	} else {
		batch = true
	}
	for _, raw := range msgs {
		req := new(jmessage)
		req.parseJSON(raw)
		req.batch = batch
		*j = append(*j, req)
	}
	return nil
}
type jmessage struct {
	V  string          `json:"jsonrpc"`       
	ID json.RawMessage `json:"id,omitempty"`  
	M string          `json:"method,omitempty"`
	P json.RawMessage `json:"params,omitempty"`  
	E *Error          `json:"error,omitempty"`   
	R json.RawMessage `json:"result,omitempty"`  
	batch bool   
	err   error  
}
func (j *jmessage) fail(code code.Code, msg string) error {
	j.err = Errorf(code, msg)
	return j.err
}
func (j *jmessage) parseJSON(data []byte) error {
	var obj map[string]json.RawMessage
	if err := json.Unmarshal(data, &obj); err != nil {
		return j.fail(code.ParseError, "request is not a JSON object")
	}
	*j = jmessage{}     
	var extra []string  
	for key, val := range obj {
		switch key {
		case "jsonrpc":
			if json.Unmarshal(val, &j.V) != nil {
				j.fail(code.ParseError, "invalid version key")
			}
		case "id":
			j.ID = val
		case "method":
			if json.Unmarshal(val, &j.M) != nil {
				j.fail(code.ParseError, "invalid method name")
			}
		case "params":
			if !isNull(val) {
				j.P = val
			}
			if len(j.P) != 0 && j.P[0] != '[' && j.P[0] != '{' {
				j.fail(code.InvalidRequest, "parameters must be array or object")
			}
		case "error":
			if json.Unmarshal(val, &j.E) != nil {
				j.fail(code.ParseError, "invalid error value")
			}
		case "result":
			j.R = val
		default:
			extra = append(extra, key)
		}
	}
	if j.M != "" && (j.E != nil || j.R != nil) {
		j.fail(code.InvalidRequest, "mixed request and reply fields")
	}
	if j.err == nil && len(extra) != 0 {
		j.err = DataErrorf(code.InvalidRequest, extra, "extra fields in request")
	}
	return nil
}
func (j *jmessage) isRequestOrNotification() bool { return j.E == nil && j.R == nil && j.M != "" }
func (j *jmessage) isNotification() bool { return j.isRequestOrNotification() && fixID(j.ID) == nil }
type jerror struct {
	C int32           `json:"code"`
	M string          `json:"message,omitempty"`
	D json.RawMessage `json:"data,omitempty"`
}
func fixID(id json.RawMessage) json.RawMessage {
	if !isNull(id) {
		return id
	}
	return nil
}
func encode(ch channel.Sender, rsps jmessages) (int, error) {
	bits, err := rsps.toJSON()
	if err != nil {
		return 0, err
	}
	return len(bits), ch.Send(bits)
}