text:
package libcontainer

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/utils"
)

func newStateTransitionError(from, to containerState) error {
	return &stateTransitionError{
		From: from.status().String(),
		To:   to.status().String(),
	}
}

// stateTransitionError is returned when an invalid state transition happens from one
// state to another.
type stateTransitionError struct {
	From string
	To   string
}

func (s *stateTransitionError) Error() string {
	return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To)
}

type containerState interface {
	transition(containerState) error
	destroy() error
	status() Status
}

func destroy(c *linuxContainer) error {
	if !c.config.Namespaces.Contains(configs.NEWPID) {
		if err := signalAllProcesses(c.cgroupManager, syscall.SIGKILL); err != nil {
			logrus.Warn(err)
		}
	}
	err := c.cgroupManager.Destroy()
	if rerr := os.RemoveAll(c.root); err == nil {
		err = rerr
	}
	c.initProcess = nil
	if herr := runPoststopHooks(c); err == nil {
		err = herr
	}
	c.state = &stoppedState{c: c}
	return err
}

func runPoststopHooks(c *linuxContainer) error {
	if c.config.Hooks != nil {
		s := configs.HookState{
			Version:    c.config.Version,
			ID:         c.id,
			BundlePath: utils.SearchLabels(c.config.Labels, "bundle"),
		}
		for _, hook := range c.config.Hooks.Poststop {
			if err := hook.Run(s); err != nil {
				return err
			}
		}
	}
	return nil
}

// stoppedState represents a container is a stopped/destroyed state.
type stoppedState struct {
	c *linuxContainer
}

func (b *stoppedState) status() Status {
	return Stopped
}

func (b *stoppedState) transition(s containerState) error {
	switch s.(type) {
	case *runningState, *restoredState:
		b.c.state = s
		return nil
	case *stoppedState:
		return nil
	}
	return newStateTransitionError(b, s)
}

func (b *stoppedState) destroy() error {
	return destroy(b.c)
}

// runningState represents a container that is currently running.
type runningState struct {
	c *linuxContainer
}

func (r *runningState) status() Status {
	return Running
}

func (r *runningState) transition(s containerState) error {
	switch s.(type) {
	case *stoppedState:
		t, err := r.c.runType()
		if err != nil {
			return err
		}
		if t == Running {
			return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped)
		}
		r.c.state = s
		return nil
	case *pausedState:
		r.c.state = s
		return nil
	case *runningState:
		return nil
	}
	return newStateTransitionError(r, s)
}

func (r *runningState) destroy() error {
	t, err := r.c.runType()
	if err != nil {
		return err
	}
	if t == Running {
		return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped)
	}
	return destroy(r.c)
}

type createdState struct {
	c *linuxContainer
}

func (i *createdState) status() Status {
	return Created
}

func (i *createdState) transition(s containerState) error {
	switch s.(type) {
	case *runningState, *pausedState, *stoppedState:
		i.c.state = s
		return nil
	case *createdState:
		return nil
	}
	return newStateTransitionError(i, s)
}

func (i *createdState) destroy() error {
	i.c.initProcess.signal(syscall.SIGKILL)
	return destroy(i.c)
}

// pausedState represents a container that is currently pause.  It cannot be destroyed in a
// paused state and must transition back to running first.
type pausedState struct {
	c *linuxContainer
}

func (p *pausedState) status() Status {
	return Paused
}

func (p *pausedState) transition(s containerState) error {
	switch s.(type) {
	case *runningState, *stoppedState:
		p.c.state = s
		return nil
	case *pausedState:
		return nil
	}
	return newStateTransitionError(p, s)
}

func (p *pausedState) destroy() error {
	t, err := p.c.runType()
	if err != nil {
		return err
	}
	if t != Running && t != Created {
		if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
			return err
		}
		return destroy(p.c)
	}
	return newGenericError(fmt.Errorf("container is paused"), ContainerPaused)
}

// restoredState is the same as the running state but also has associated checkpoint
// information that maybe need destroyed when the container is stopped and destroy is called.
type restoredState struct {
	imageDir string
	c        *linuxContainer
}

func (r *restoredState) status() Status {
	return Running
}

func (r *restoredState) transition(s containerState) error {
	switch s.(type) {
	case *stoppedState, *runningState:
		return nil
	}
	return newStateTransitionError(r, s)
}

func (r *restoredState) destroy() error {
	if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	}
	return destroy(r.c)
}

// loadedState is used whenever a container is restored, loaded, or setting additional
// processes inside and it should not be destroyed when it is exiting.
type loadedState struct {
	c *linuxContainer
	s Status
}

func (n *loadedState) status() Status {
	return n.s
}

func (n *loadedState) transition(s containerState) error {
	n.c.state = s
	return nil
}

func (n *loadedState) destroy() error {
	if err := n.c.refreshState(); err != nil {
		return err
	}
	return n.c.state.destroy()
}


text:
.. Django Account Manager documentation master file, created by
   sphinx-quickstart on Mon May  3 00:03:36 2010.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Django Account Manager's documentation!
=======================================

.. toctree::
   :maxdepth: 2

Experimental implementation of `Account Management and Session Identification <https://wiki.mozilla.org/Labs/Weave/Identity/Account_Manager>`_ by Mozilla Labs in `Django <http://www.djangoproject.com/>`_.

Features
--------

 * Connect
 * Disconnect
 * Handle CSRF Django protection
 * Handle sessionstatus

Requirements
------------

To get started, you'll need:
 * Django >= 1.2

Install
-------

        pip install django-account-manager

Configuration
-------------

In your ``settings.py``::

        INSTALLED_APPS = (
            ...,
            'django.contrib.auth',
            'account_manager',
        )

        MIDDLEWARE_CLASSES = (
            ...,
            'account_manager.middleware.AccountManagerMiddleware',
        )

In your ``urls.py``::

        urlpatterns = patterns('',
            ...,
            (r'amcd/', include('account_manager.urls')),
            url(r'xxx/signin/', 'your.view', name='signin'),   # Needed
            url(r'xxx/signout/', 'your.view', name='signout'), # Needed
            ...
        )

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

redpajama_set_name: RedPajamaGithub


text:
package neutrino

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/btcsuite/btcd/addrmgr"
	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/btcutil"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/connmgr"
	"github.com/btcsuite/btcd/peer"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcwallet/walletdb"
	"github.com/lightninglabs/neutrino/banman"
	"github.com/lightninglabs/neutrino/blockntfns"
	"github.com/lightninglabs/neutrino/cache/lru"
	"github.com/lightninglabs/neutrino/filterdb"
	"github.com/lightninglabs/neutrino/headerfs"
	"github.com/lightninglabs/neutrino/pushtx"
	"github.com/lightninglabs/neutrino/query"
)

// These are exported variables so they can be changed by users.
//
// TODO: Export functional options for these as much as possible so they can be
// changed call-to-call.
var (
	// ConnectionRetryInterval is the base amount of time to wait in
	// between retries when connecting to persistent peers.  It is adjusted
	// by the number of retries such that there is a retry backoff.
	ConnectionRetryInterval = time.Second * 5

	// UserAgentName is the user agent name and is used to help identify
	// ourselves to other bitcoin peers.
	UserAgentName = "neutrino"

	// UserAgentVersion is the user agent version and is used to help
	// identify ourselves to other bitcoin peers.
	UserAgentVersion = "0.12.0-beta"

	// Services describes the services that are supported by the server.
	Services = wire.SFNodeWitness | wire.SFNodeCF

	// RequiredServices describes the services that are required to be
	// supported by outbound peers.
	RequiredServices = wire.SFNodeNetwork | wire.SFNodeWitness | wire.SFNodeCF

	// BanThreshold is the maximum ban score before a peer is banned.
	BanThreshold = uint32(100)

	// BanDuration is the duration of a ban.
	BanDuration = time.Hour * 24

	// TargetOutbound is the number of outbound peers to target.
	TargetOutbound = 8

	// MaxPeers is the maximum number of connections the client maintains.
	MaxPeers = 125

	// DisableDNSSeed disables getting initial addresses for Bitcoin nodes
	// from DNS.
	DisableDNSSeed = false

	// DefaultFilterCacheSize is the size (in bytes) of filters neutrino
	// will keep in memory if no size is specified in the neutrino.Config.
	// Since we utilize the cache during batch filter fetching, it is
	// beneficial if it is able to to keep a whole batch. The current batch
	// size is 1000, so we default to 30 MB, which can fit about 1450 to
	// 2300 mainnet filters.
	DefaultFilterCacheSize uint64 = 3120 * 10 * 1000

	// DefaultBlockCacheSize is the size (in bytes) of blocks neutrino will
	// keep in memory if no size is specified in the neutrino.Config.
	DefaultBlockCacheSize uint64 = 4096 * 10 * 1000 // 40 MB
)

// isDevNetwork indicates if the chain is a private development network, namely
// simnet or regtest/regnet.
func isDevNetwork(net wire.BitcoinNet) bool {
	return net == chaincfg.SimNetParams.Net ||
		net == chaincfg.RegressionNetParams.Net
}

// updatePeerHeightsMsg is a message sent from the blockmanager to the server
// after a new block has been accepted. The purpose of the message is to update
// the heights of peers that were known to announce the block before we
// connected it to the main chain or recognized it as an orphan. With these
// updates, peer heights will be kept up to date, allowing for fresh data when
// selecting sync peer candidacy.
type updatePeerHeightsMsg struct {
	newHash    *chainhash.Hash
	newHeight  int32
	originPeer *ServerPeer
}

// peerState maintains state of inbound, persistent, outbound peers as well
// as banned peers and outbound groups.
type peerState struct {
	outboundPeers   map[int32]*ServerPeer
	persistentPeers map[int32]*ServerPeer
	outboundGroups  map[string]int
}

// Count returns the count of all known peers.
func (ps *peerState) Count() int {
	return len(ps.outboundPeers) + len(ps.persistentPeers)
}

// forAllOutboundPeers is a helper function that runs closure on all outbound
// peers known to peerState.
func (ps *peerState) forAllOutboundPeers(closure func(sp *ServerPeer)) {
	for _, e := range ps.outboundPeers {
		closure(e)
	}
	for _, e := range ps.persistentPeers {
		closure(e)
	}
}

// forAllPeers is a helper function that runs closure on all peers known to
// peerState.
func (ps *peerState) forAllPeers(closure func(sp *ServerPeer)) {
	ps.forAllOutboundPeers(closure)
}

// spMsg represents a message over the wire from a specific peer.
type spMsg struct {
	sp  *ServerPeer
	msg wire.Message
}

// spMsgSubscription sends all messages from a peer over a channel, allowing
// pluggable filtering of the messages.
type spMsgSubscription struct {
	msgChan  chan<- spMsg
	quitChan <-chan struct{}
}

// msgSubscription sends all messages from a peer over a channel, allowing
// pluggable filtering of the messages.
type msgSubscription struct {
	msgChan  chan<- wire.Message
	quitChan <-chan struct{}
}

// ServerPeer extends the peer to maintain state shared by the server and the
// blockmanager.
type ServerPeer struct {
	// The following variables must only be used atomically
	feeFilter int64

	*peer.Peer

	connReq        *connmgr.ConnReq
	server         *ChainService
	persistent     bool
	knownAddresses *lru.Cache
	quit           chan struct{}

	// The following map of subcribers is used to subscribe to messages
	// from the peer. This allows broadcast to multiple subscribers at
	// once, allowing for multiple queries to be going to multiple peers at
	// any one time. The mutex is for subscribe/unsubscribe functionality.
	// The sends on these channels WILL NOT block; any messages the channel
	// can't accept will be dropped silently.
	// TODO(halseth): remove one of the maps when all queries go through
	// work manager.
	recvSubscribers  map[spMsgSubscription]struct{}
	recvSubscribers2 map[msgSubscription]struct{}
	mtxSubscribers   sync.RWMutex
}

// NewServerPeer returns a new ServerPeer instance. The peer needs to be set by
// the caller.
func NewServerPeer(s *ChainService, isPersistent bool) *ServerPeer {
	return &ServerPeer{
		server:           s,
		persistent:       isPersistent,
		knownAddresses:   lru.NewCache(5000),
		quit:             make(chan struct{}),
		recvSubscribers:  make(map[spMsgSubscription]struct{}),
		recvSubscribers2: make(map[msgSubscription]struct{}),
	}
}

// newestBlock returns the current best block hash and height using the format
// required by the configuration for the peer package.
func (sp *ServerPeer) newestBlock() (*chainhash.Hash, int32, error) {
	bestHeader, bestHeight, err := sp.server.BlockHeaders.ChainTip()
	if err != nil {
		return nil, 0, err
	}
	bestHash := bestHeader.BlockHash()
	return &bestHash, int32(bestHeight), nil
}

// addKnownAddresses adds the given addresses to the set of known addresses to
// the peer to prevent sending duplicate addresses.
func (sp *ServerPeer) addKnownAddresses(addresses []*wire.NetAddressV2) {
	for _, na := range addresses {
		_, err := sp.knownAddresses.Put(
			addrmgr.NetAddressKey(na), &cachedAddr{},
		)
		if err != nil {
			log.Debugf("Could not store known addresses: %v", err)
		}
	}
}

// OnVerAck is invoked when a peer receives a verack bitcoin message and is used
// to kick start communication with them.
func (sp *ServerPeer) OnVerAck(_ *peer.Peer, msg *wire.MsgVerAck) {
	sp.server.AddPeer(sp)
}

// OnVersion is invoked when a peer receives a version bitcoin message
// and is used to negotiate the protocol version details as well as kick start
// the communications.
func (sp *ServerPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) *wire.MsgReject {
	// Add the remote peer time as a sample for creating an offset against
	// the local clock to keep the network time in sync.
	sp.server.timeSource.AddTimeSample(sp.Addr(), msg.Timestamp)

	// Check to see if the peer supports the latest protocol version and
	// service bits required to service us. If not, then we'll disconnect
	// so we can find compatible peers.
	peerServices := sp.Services()
	if peerServices&wire.SFNodeWitness != wire.SFNodeWitness ||
		peerServices&wire.SFNodeCF != wire.SFNodeCF {

		peerAddr := sp.Addr()
		err := sp.server.BanPeer(peerAddr, banman.NoCompactFilters)
		if err != nil {
			log.Errorf("Unable to ban peer %v: %v", peerAddr, err)
		}

		// Disconnect the peer even though BanPeer attempts to do so
		// because it has yet to be added.
		sp.Disconnect()

		return nil
	}

	// Update the address manager with the advertised services for outbound
	// connections in case they have changed. This is not done for inbound
	// connections to help prevent malicious behavior and is skipped when
	// running on the simulation test network since it is only intended to
	// connect to specified peers and actively avoids advertising and
	// connecting to discovered peers.
	if !sp.Inbound() {
		sp.server.addrManager.SetServices(sp.NA(), msg.Services)
	}

	return nil
}

// OnInv is invoked when a peer receives an inv bitcoin message and is
// used to examine the inventory being advertised by the remote peer and react
// accordingly.  We pass the message down to blockmanager which will call
// QueueMessage with any appropriate responses.
func (sp *ServerPeer) OnInv(p *peer.Peer, msg *wire.MsgInv) {
	log.Tracef("Got inv with %d items from %s", len(msg.InvList), p.Addr())
	newInv := wire.NewMsgInvSizeHint(uint(len(msg.InvList)))
	for _, invVect := range msg.InvList {
		if invVect.Type == wire.InvTypeTx {
			log.Tracef("Ignoring tx %s in inv from %v -- "+
				"SPV mode", invVect.Hash, sp)
			if sp.ProtocolVersion() >= wire.BIP0037Version {
				log.Infof("Peer %v is announcing "+
					"transactions -- disconnecting", sp)
				sp.Disconnect()
				return
			}
			continue
		}
		err := newInv.AddInvVect(invVect)
		if err != nil {
			log.Errorf("Failed to add inventory vector: %s", err)
			break
		}
	}

	if len(newInv.InvList) > 0 {
		sp.server.blockManager.QueueInv(newInv, sp)
	}
}

// OnHeaders is invoked when a peer receives a headers bitcoin
// message.  The message is passed down to the block manager.
func (sp *ServerPeer) OnHeaders(p *peer.Peer, msg *wire.MsgHeaders) {
	log.Tracef("Got headers with %d items from %s", len(msg.Headers),
		p.Addr())
	sp.server.blockManager.QueueHeaders(msg, sp)
}

// OnFeeFilter is invoked when a peer receives a feefilter bitcoin message and
// is used by remote peers to request that no transactions which have a fee rate
// lower than provided value are inventoried to them.  The peer will be
// disconnected if an invalid fee filter value is provided.
func (sp *ServerPeer) OnFeeFilter(_ *peer.Peer, msg *wire.MsgFeeFilter) {
	// Check that the passed minimum fee is a valid amount.
	if msg.MinFee < 0 || msg.MinFee > btcutil.MaxSatoshi {
		log.Debugf("Peer %v sent an invalid feefilter '%v' -- "+
			"disconnecting", sp, btcutil.Amount(msg.MinFee))
		sp.Disconnect()
		return
	}

	atomic.StoreInt64(&sp.feeFilter, msg.MinFee)
}

// OnReject is invoked when a peer receives a reject bitcoin message and is
// used to notify the server about a rejected transaction.
func (sp *ServerPeer) OnReject(_ *peer.Peer, msg *wire.MsgReject) {
	// TODO(roaseef): log?
}

// OnAddr is invoked when a peer receives an addr bitcoin message and is
// used to notify the server about advertised addresses.
func (sp *ServerPeer) OnAddr(_ *peer.Peer, msg *wire.MsgAddr) {
	// Ignore addresses when running on a private development network.  This
	// helps prevent the network from becoming another public test network
	// since it will not be able to learn about other peers that have not
	// specifically been provided.
	if isDevNetwork(sp.server.chainParams.Net) {
		return
	}

	// Ignore old style addresses which don't include a timestamp.
	if sp.ProtocolVersion() < wire.NetAddressTimeVersion {
		return
	}

	// A message that has no addresses is invalid.
	if len(msg.AddrList) == 0 {
		log.Errorf("Command [%s] from %s does not contain any "+
			"addresses", msg.Command(), sp.Addr())
		sp.Disconnect()
		return
	}

	addrs := make([]*wire.NetAddressV2, 0, len(msg.AddrList))
	for _, na := range msg.AddrList {
		// Don't add more address if we're disconnecting.
		if !sp.Connected() {
			return
		}

		// Skip any that don't advertise our required services.
		if na.Services&RequiredServices != RequiredServices {
			continue
		}

		// Set the timestamp to 5 days ago if it's more than 10 minutes
		// in the future so this address is one of the first to be
		// removed when space is needed.
		now := time.Now()
		if na.Timestamp.After(now.Add(time.Minute * 10)) {
			na.Timestamp = now.Add(-1 * time.Hour * 24 * 5)
		}

		// Convert the wire.NetAddress to wire.NetAddressV2 since that
		// is what is used by the addrmgr.
		currentNa := wire.NetAddressV2FromBytes(
			na.Timestamp, na.Services, na.IP, na.Port,
		)
		addrs = append(addrs, currentNa)
	}

	// Ignore any addr messages if none of them contained our required
	// services.
	if len(addrs) == 0 {
		return
	}

	// Add addresses to the set of known addresses for this peer.
	sp.addKnownAddresses(addrs)

	// Add addresses to server address manager.  The address manager handles
	// the details of things such as preventing duplicate addresses, max
	// addresses, and last seen updates.
	// XXX bitcoind gives a 2 hour time penalty here, do we want to do the
	// same?
	sp.server.addrManager.AddAddresses(addrs, sp.NA())
}

// OnAddrV2 is called when a peer receives an AddrV2 message from its peer.
func (sp *ServerPeer) OnAddrV2(_ *peer.Peer, msg *wire.MsgAddrV2) {
	// Ignore addresses when running on a private development network for
	// the same reason that OnAddr does.
	if isDevNetwork(sp.server.chainParams.Net) {
		return
	}

	// An empty AddrV2 message is invalid.
	if len(msg.AddrList) == 0 {
		log.Errorf("Command [%s] from %s does not contain any "+
			"addresses", msg.Command(), sp.Addr())
		sp.Disconnect()
		return
	}

	addrs := make([]*wire.NetAddressV2, 0, len(msg.AddrList))
	for _, na := range msg.AddrList {
		// Don't add more addresses if we're disconnecting.
		if !sp.Connected() {
			return
		}

		// Skip any that don't advertise our required services.
		if na.Services&RequiredServices != RequiredServices {
			continue
		}

		// Set the timestamp to 5 days ago if it's more than 10 minutes
		// in the future so this address is one of the first to be
		// removed when space is needed.
		now := time.Now()
		if na.Timestamp.After(now.Add(time.Minute * 10)) {
			na.Timestamp = now.Add(-1 * time.Hour * 24 * 5)
		}
		addrs = append(addrs, na)
	}

	// Ignore addrv2 message if no addresses contained our required
	// services.
	if len(addrs) == 0 {
		return
	}

	// Add the addresses to the set of known addresses for this peer.
	sp.addKnownAddresses(addrs)

	// Add addresses to the address manager.
	sp.server.addrManager.AddAddresses(addrs, sp.NA())
}

// OnRead is invoked when a peer receives a message and it is used to update
// the bytes received by the server.
func (sp *ServerPeer) OnRead(_ *peer.Peer, bytesRead int, msg wire.Message,
	err error) {

	sp.server.AddBytesReceived(uint64(bytesRead))

	// Send a message to each subscriber. Each message gets its own
	// goroutine to prevent blocking on the mutex lock.
	// TODO: Flood control.
	sp.mtxSubscribers.RLock()
	defer sp.mtxSubscribers.RUnlock()
	for subscription := range sp.recvSubscribers {
		go func(subscription spMsgSubscription) {
			select {
			case <-subscription.quitChan:
			case subscription.msgChan <- spMsg{
				msg: msg,
				sp:  sp,
			}:
			}
		}(subscription)
	}
	for subscription := range sp.recvSubscribers2 {
		// Quickly determine if this subscription has been canceled, if
		// so delete it.
		select {
		case <-subscription.quitChan:
			delete(sp.recvSubscribers2, subscription)
			continue
		default:
		}

		go func(subscription msgSubscription) {
			select {
			case <-subscription.quitChan:
			case subscription.msgChan <- msg:
			}
		}(subscription)
	}
}

// subscribeRecvMsg handles adding OnRead subscriptions to the server peer.
func (sp *ServerPeer) subscribeRecvMsg(subscription spMsgSubscription) {
	sp.mtxSubscribers.Lock()
	defer sp.mtxSubscribers.Unlock()
	sp.recvSubscribers[subscription] = struct{}{}
}

// unsubscribeRecvMsgs handles removing OnRead subscriptions from the server
// peer.
func (sp *ServerPeer) unsubscribeRecvMsgs(subscription spMsgSubscription) {
	sp.mtxSubscribers.Lock()
	defer sp.mtxSubscribers.Unlock()
	delete(sp.recvSubscribers, subscription)
}

// A compile-time check to ensure that ServerPeer implements the query.Peer
// interface.
var _ query.Peer = (*ServerPeer)(nil)

// SubscribeRecvMsg adds a OnRead subscription to the peer. All bitcoin
// messages received from this peer will be sent on the returned channel. A
// closure is also returned, that should be called to cancel the subscription.
//
// NOTE: Part of the query.Peer interface.
func (sp *ServerPeer) SubscribeRecvMsg() (<-chan wire.Message, func()) {
	// We won't have to buffer this channel, since we'll always send on it
	// from a new goroutine.
	msgChan := make(chan wire.Message)
	quitChan := make(chan struct{})

	sub := msgSubscription{
		msgChan:  msgChan,
		quitChan: quitChan,
	}

	sp.mtxSubscribers.Lock()
	defer sp.mtxSubscribers.Unlock()
	sp.recvSubscribers2[sub] = struct{}{}

	return msgChan, func() {
		close(quitChan)
	}
}

// OnDisconnect returns a channel that will be closed when this peer is
// disconnected.
//
// NOTE: Part of the query.Peer interface.
func (sp *ServerPeer) OnDisconnect() <-chan struct{} {
	return sp.quit
}

// OnWrite is invoked when a peer sends a message and it is used to update
// the bytes sent by the server.
func (sp *ServerPeer) OnWrite(_ *peer.Peer, bytesWritten int, msg wire.Message, err error) {
	sp.server.AddBytesSent(uint64(bytesWritten))
}

// Config is a struct detailing the configuration of the chain service.
type Config struct {
	// DataDir is the directory that neutrino will store all header
	// information within.
	DataDir string

	// Database is an *open* database instance that we'll use to storm
	// indexes of the chain.
	Database walletdb.DB

	// ChainParams is the chain that we're running on.
	ChainParams chaincfg.Params

	// ConnectPeers is a slice of hosts that should be connected to on
	// startup, and be established as persistent peers.
	//
	// NOTE: If specified, we'll *only* connect to this set of peers and
	// won't attempt to automatically seek outbound peers.
	ConnectPeers []string

	// AddPeers is a slice of hosts that should be connected to on startup,
	// and be maintained as persistent peers.
	AddPeers []string

	// Dialer is an optional function closure that will be used to
	// establish outbound TCP connections. If specified, then the
	// connection manager will use this in place of net.Dial for all
	// outbound connection attempts.
	Dialer func(addr net.Addr) (net.Conn, error)

	// NameResolver is an optional function closure that will be used to
	// lookup the IP of any host. If specified, then the address manager,
	// along with regular outbound connection attempts will use this
	// instead.
	NameResolver func(host string) ([]net.IP, error)

	// FilterCacheSize indicates the size (in bytes) of filters the cache will
	// hold in memory at most.
	FilterCacheSize uint64

	// BlockCache is an LRU block cache. If none is provided then the a new
	// one will be instantiated.
	BlockCache *lru.Cache

	// BlockCacheSize indicates the size (in bytes) of blocks the block
	// cache will hold in memory at most. If a BlockCache is provided then
	// BlockCacheSize is ignored.
	BlockCacheSize uint64

	// persistToDisk indicates whether the filter should also be written
	// to disk in addition to the memory cache. For "normal" wallets, they'll
	// almost never need to re-match a filter once it's been fetched unless
	// they're doing something like a key import.
	PersistToDisk bool

	// AssertFilterHeader is an optional field that allows the creator of
	// the ChainService to ensure that if any chain data exists, it's
	// compliant with the expected filter header state. If neutrino starts
	// up and this filter header state has diverged, then it'll remove the
	// current on disk filter headers to sync them anew.
	AssertFilterHeader *headerfs.FilterHeader

	// BroadcastTimeout is the amount of time we'll wait before giving up on
	// a transaction broadcast attempt. Broadcasting transactions consists
	// of three steps:
	//
	// 1. Neutrino sends an inv for the transaction.
	// 2. The recipient node determines if the inv is known, and if it's
	//    not, replies with a getdata message.
	// 3. Neutrino sends the raw transaction.
	BroadcastTimeout time.Duration
}

// peerSubscription holds a peer subscription which we'll notify about any
// connected peers.
type peerSubscription struct {
	peers  chan<- query.Peer
	cancel <-chan struct{}
}

// ChainService is instantiated with functional options.
type ChainService struct { // nolint:maligned
	// The following variables must only be used atomically.
	// Putting the uint64s first makes them 64-bit aligned for 32-bit systems.
	bytesReceived uint64 // Total bytes received from all peers since start.
	bytesSent     uint64 // Total bytes sent by all peers since start.
	started       int32
	shutdown      int32

	FilterDB         filterdb.FilterDatabase
	BlockHeaders     headerfs.BlockHeaderStore
	RegFilterHeaders *headerfs.FilterHeaderStore
	persistToDisk    bool

	FilterCache *lru.Cache
	BlockCache  *lru.Cache

	// queryPeers will be called to send messages to one or more peers,
	// expecting a response.
	queryPeers func(wire.Message, func(*ServerPeer, wire.Message,
		chan<- struct{}), ...QueryOption)

	chainParams          chaincfg.Params
	addrManager          *addrmgr.AddrManager
	connManager          *connmgr.ConnManager
	blockManager         *blockManager
	blockSubscriptionMgr *blockntfns.SubscriptionManager
	newPeers             chan *ServerPeer
	donePeers            chan *ServerPeer
	query                chan interface{}
	firstPeerConnect     chan struct{}
	peerHeightsUpdate    chan updatePeerHeightsMsg
	wg                   sync.WaitGroup
	quit                 chan struct{}
	timeSource           blockchain.MedianTimeSource
	services             wire.ServiceFlag
	utxoScanner          *UtxoScanner
	broadcaster          *pushtx.Broadcaster
	banStore             banman.Store
	workManager          *query.WorkManager

	// peerSubscribers is a slice of active peer subscriptions, that we
	// will notify each time a new peer is connected.
	peerSubscribers []*peerSubscription

	// TODO: Add a map for more granular exclusion?
	mtxCFilter sync.Mutex

	userAgentName    string
	userAgentVersion string

	nameResolver func(string) ([]net.IP, error)
	dialer       func(net.Addr) (net.Conn, error)

	broadcastTimeout time.Duration
}

// NewChainService returns a new chain service configured to connect to the
// bitcoin network type specified by chainParams.  Use start to begin syncing
// with peers.
func NewChainService(cfg Config) (*ChainService, error) {
	// Use the default broadcast timeout if one isn't provided.
	if cfg.BroadcastTimeout == 0 {
		cfg.BroadcastTimeout = pushtx.DefaultBroadcastTimeout
	}

	// First, we'll sort out the methods that we'll use to established
	// outbound TCP connections, as well as perform any DNS queries.
	//
	// If the dialler was specified, then we'll use that in place of the
	// default net.Dial function.
	var (
		nameResolver func(string) ([]net.IP, error)
		dialer       func(net.Addr) (net.Conn, error)
	)
	if cfg.Dialer != nil {
		dialer = cfg.Dialer
	} else {
		dialer = func(addr net.Addr) (net.Conn, error) {
			return net.Dial(addr.Network(), addr.String())
		}
	}

	// Similarly, if the user specified as function to use for name
	// resolution, then we'll use that everywhere as well.
	if cfg.NameResolver != nil {
		nameResolver = cfg.NameResolver
	} else {
		nameResolver = net.LookupIP
	}

	// When creating the addr manager, we'll check to see if the user has
	// provided their own resolution function. If so, then we'll use that
	// instead as this may be proxying requests over an anonymizing
	// network.
	amgr := addrmgr.New(cfg.DataDir, nameResolver)

	s := ChainService{
		chainParams:       cfg.ChainParams,
		addrManager:       amgr,
		newPeers:          make(chan *ServerPeer, MaxPeers),
		donePeers:         make(chan *ServerPeer, MaxPeers),
		query:             make(chan interface{}),
		quit:              make(chan struct{}),
		firstPeerConnect:  make(chan struct{}),
		peerHeightsUpdate: make(chan updatePeerHeightsMsg),
		timeSource:        blockchain.NewMedianTime(),
		services:          Services,
		userAgentName:     UserAgentName,
		userAgentVersion:  UserAgentVersion,
		nameResolver:      nameResolver,
		dialer:            dialer,
		persistToDisk:     cfg.PersistToDisk,
		broadcastTimeout:  cfg.BroadcastTimeout,
	}
	s.workManager = query.New(&query.Config{
		ConnectedPeers: s.ConnectedPeers,
		NewWorker:      query.NewWorker,
		Ranking:        query.NewPeerRanking(),
	})

	// We set the queryPeers method to point to queryChainServicePeers,
	// passing a reference to the newly created ChainService.
	s.queryPeers = func(msg wire.Message, f func(*ServerPeer,
		wire.Message, chan<- struct{}), qo ...QueryOption) {

		queryChainServicePeers(&s, msg, f, qo...)
	}

	var err error

	s.FilterDB, err = filterdb.New(cfg.Database, cfg.ChainParams)
	if err != nil {
		return nil, err
	}

	filterCacheSize := DefaultFilterCacheSize
	if cfg.FilterCacheSize != 0 {
		filterCacheSize = cfg.FilterCacheSize
	}
	s.FilterCache = lru.NewCache(filterCacheSize)

	if cfg.BlockCache != nil {
		s.BlockCache = cfg.BlockCache
	} else {
		blockCacheSize := DefaultBlockCacheSize
		if cfg.BlockCacheSize != 0 {
			blockCacheSize = cfg.BlockCacheSize
		}
		s.BlockCache = lru.NewCache(blockCacheSize)
	}

	s.BlockHeaders, err = headerfs.NewBlockHeaderStore(
		cfg.DataDir, cfg.Database, &cfg.ChainParams,
	)
	if err != nil {
		return nil, err
	}
	s.RegFilterHeaders, err = headerfs.NewFilterHeaderStore(
		cfg.DataDir, cfg.Database, headerfs.RegularFilter,
		&cfg.ChainParams, cfg.AssertFilterHeader,
	)
	if err != nil {
		return nil, err
	}

	bm, err := newBlockManager(&blockManagerCfg{
		ChainParams:      s.chainParams,
		BlockHeaders:     s.BlockHeaders,
		RegFilterHeaders: s.RegFilterHeaders,
		TimeSource:       s.timeSource,
		QueryDispatcher:  s.workManager,
		BanPeer:          s.BanPeer,
		GetBlock:         s.GetBlock,
		firstPeerSignal:  s.firstPeerConnect,
		queryAllPeers:    s.queryAllPeers,
	})
	if err != nil {
		return nil, err
	}
	s.blockManager = bm
	s.blockSubscriptionMgr = blockntfns.NewSubscriptionManager(s.blockManager)

	// Only setup a function to return new addresses to connect to when not
	// running in connect-only mode.  Private development networks are always in
	// connect-only mode since it is only intended to connect to specified peers
	// and actively avoid advertising and connecting to discovered peers in
	// order to prevent it from becoming a public test network.
	var newAddressFunc func() (net.Addr, error)
	if !isDevNetwork(s.chainParams.Net) {
		newAddressFunc = func() (net.Addr, error) {
			// Gather our set of currently connected peers to avoid
			// connecting to them again.
			connectedPeers := make(map[string]struct{})
			for _, peer := range s.Peers() {
				peerAddr := addrmgr.NetAddressKey(peer.NA())
				connectedPeers[peerAddr] = struct{}{}
			}

			for tries := 0; tries < 100; tries++ {
				select {
				case <-s.quit:
					return nil, ErrShuttingDown
				default:
				}

				addr := s.addrManager.GetAddress()
				if addr == nil {
					break
				}

				// Ignore peers that we've already banned.
				addrString := addrmgr.NetAddressKey(addr.NetAddress())
				if s.IsBanned(addrString) {
					log.Debugf("Ignoring banned peer: %v", addrString)
					continue
				}

				// Skip any addresses that correspond to our set
				// of currently connected peers.
				if _, ok := connectedPeers[addrString]; ok {
					continue
				}

				// The peer behind this address should support
				// all of our required services.
				if addr.Services()&RequiredServices != RequiredServices {
					continue
				}

				// Address will not be invalid, local or unroutable
				// because addrmanager rejects those on addition.
				// Just check that we don't already have an address
				// in the same group so that we are not connecting
				// to the same network segment at the expense of
				// others.
				key := addrmgr.GroupKey(addr.NetAddress())
				if s.OutboundGroupCount(key) != 0 {
					continue
				}

				// only allow recent nodes (10mins) after we failed 30
				// times
				if tries < 30 && time.Since(addr.LastAttempt()) < 10*time.Minute {
					continue
				}

				// allow nondefault ports after 50 failed tries.
				if tries < 50 && fmt.Sprintf("%d", addr.NetAddress().Port) !=
					s.chainParams.DefaultPort {

					continue
				}

				// Mark an attempt for the valid address.
				s.addrManager.Attempt(addr.NetAddress())
				return s.addrStringToNetAddr(addrString)
			}

			return nil, errors.New("no valid connect address")
		}
	}

	cmgrCfg := &connmgr.Config{
		RetryDuration:  ConnectionRetryInterval,
		TargetOutbound: uint32(TargetOutbound),
		OnConnection:   s.outboundPeerConnected,
		Dial:           dialer,
	}
	if len(cfg.ConnectPeers) == 0 {
		cmgrCfg.GetNewAddress = newAddressFunc
	}

	// Create a connection manager.
	if MaxPeers < TargetOutbound {
		TargetOutbound = MaxPeers
	}
	cmgr, err := connmgr.New(cmgrCfg)
	if err != nil {
		return nil, err
	}
	s.connManager = cmgr

	s.utxoScanner = NewUtxoScanner(&UtxoScannerConfig{
		BestSnapshot: s.BestBlock,
		GetBlockHash: s.GetBlockHash,
		GetBlock:     s.GetBlock,
		BlockFilterMatches: func(ro *rescanOptions,
			blockHash *chainhash.Hash) (bool, error) {

			matches, _, err := blockFilterMatches(
				&RescanChainSource{&s}, ro, blockHash,
			)

			return matches, err
		},
	})

	s.broadcaster = pushtx.NewBroadcaster(&pushtx.Config{
		Broadcast: func(tx *wire.MsgTx) error {
			return s.sendTransaction(tx)
		},
		SubscribeBlocks: func() (*blockntfns.Subscription, error) {
			return s.blockSubscriptionMgr.NewSubscription(0)
		},
		RebroadcastInterval: pushtx.DefaultRebroadcastInterval,
	})

	s.banStore, err = banman.NewStore(cfg.Database)
	if err != nil {
		return nil, fmt.Errorf("unable to initialize ban store: %v", err)
	}

	// Start up persistent peers.
	permanentPeers := cfg.ConnectPeers
	if len(permanentPeers) == 0 {
		permanentPeers = cfg.AddPeers
	}

	for _, addr := range permanentPeers {
		addr := addr

		s.wg.Add(1)
		go func() {
			defer s.wg.Done()

			// Since netwok access might not be established yet, we
			// loop until we are able to look up the permanent
			// peer.
			var tcpAddr net.Addr
			for {
				var err error
				tcpAddr, err = s.addrStringToNetAddr(addr)
				if err != nil {
					log.Warnf("unable to lookup IP for "+
						"%v: %v", addr, err)

					select {
					// Try again in 5 seconds.
					case <-time.After(ConnectionRetryInterval):
					case <-s.quit:
						return
					}
					continue
				}

				break
			}

			s.connManager.Connect(&connmgr.ConnReq{
				Addr:      tcpAddr,
				Permanent: true,
			})
		}()
	}

	return &s, nil
}

// BestBlock retrieves the most recent block's height and hash where we
// have both the header and filter header ready.
func (s *ChainService) BestBlock() (*headerfs.BlockStamp, error) {
	bestHeader, bestHeight, err := s.BlockHeaders.ChainTip()
	if err != nil {
		return nil, err
	}

	_, filterHeight, err := s.RegFilterHeaders.ChainTip()
	if err != nil {
		return nil, err
	}

	// Filter headers might lag behind block headers, so we can can fetch a
	// previous block header if the filter headers are not caught up.
	if filterHeight < bestHeight {
		bestHeight = filterHeight
		bestHeader, err = s.BlockHeaders.FetchHeaderByHeight(
			bestHeight,
		)
		if err != nil {
			return nil, err
		}
	}

	return &headerfs.BlockStamp{
		Height:    int32(bestHeight),
		Hash:      bestHeader.BlockHash(),
		Timestamp: bestHeader.Timestamp,
	}, nil
}

// GetBlockHash returns the block hash at the given height.
func (s *ChainService) GetBlockHash(height int64) (*chainhash.Hash, error) {
	header, err := s.BlockHeaders.FetchHeaderByHeight(uint32(height))
	if err != nil {
		return nil, err
	}
	hash := header.BlockHash()
	return &hash, err
}

// GetBlockHeader returns the block header for the given block hash, or an
// error if the hash doesn't exist or is unknown.
func (s *ChainService) GetBlockHeader(
	blockHash *chainhash.Hash) (*wire.BlockHeader, error) {

	header, _, err := s.BlockHeaders.FetchHeader(blockHash)
	return header, err
}

// GetBlockHeight gets the height of a block by its hash. An error is returned
// if the given block hash is unknown.
func (s *ChainService) GetBlockHeight(hash *chainhash.Hash) (int32, error) {
	_, height, err := s.BlockHeaders.FetchHeader(hash)
	if err != nil {
		return 0, err
	}
	return int32(height), nil
}

// BanPeer disconnects and bans a peer due to a specific reason for a duration
// of BanDuration.
func (s *ChainService) BanPeer(addr string, reason banman.Reason) error {
	log.Warnf("Banning peer %v: duration=%v, reason=%v", addr, BanDuration,
		reason)

	// We'll want to disconnect the peer after we return regardless of
	// whether we ban the peer or not. We do this to prevent a possible race
	// condition where we end up reconnecting with the peer slightly
	// before the ban succeeds.
	defer func() {
		// We do so in a goroutine to prevent blocking if the server is
		// handling a query or a new/stale peer.
		go func() {
			if sp := s.PeerByAddr(addr); sp != nil {
				sp.Disconnect()
			}
		}()
	}()

	ipNet, err := banman.ParseIPNet(addr, nil)
	if err != nil {
		return fmt.Errorf("unable to parse IP network for peer %v: %v",
			addr, err)
	}
	return s.banStore.BanIPNet(ipNet, reason, BanDuration)
}

// IsBanned returns true if the peer is banned, and false otherwise.
func (s *ChainService) IsBanned(addr string) bool {
	ipNet, err := banman.ParseIPNet(addr, nil)
	if err != nil {
		log.Errorf("Unable to parse IP network for peer %v: %v", addr,
			err)
		return false
	}
	banStatus, err := s.banStore.Status(ipNet)
	if err != nil {
		log.Errorf("Unable to determine ban status for peer %v: %v",
			addr, err)
		return false
	}

	// Log how much time left the peer will remain banned for, if any.
	if time.Now().Before(banStatus.Expiration) {
		log.Debugf("Peer %v is banned for another %v", addr,
			time.Until(banStatus.Expiration))
	}

	return banStatus.Banned
}

// AddPeer adds a new peer that has already been connected to the server.
func (s *ChainService) AddPeer(sp *ServerPeer) {
	select {
	case s.newPeers <- sp:
	case <-s.quit:
		return
	}
}

// AddBytesSent adds the passed number of bytes to the total bytes sent counter
// for the server.  It is safe for concurrent access.
func (s *ChainService) AddBytesSent(bytesSent uint64) {
	atomic.AddUint64(&s.bytesSent, bytesSent)
}

// AddBytesReceived adds the passed number of bytes to the total bytes received
// counter for the server.  It is safe for concurrent access.
func (s *ChainService) AddBytesReceived(bytesReceived uint64) {
	atomic.AddUint64(&s.bytesReceived, bytesReceived)
}

// NetTotals returns the sum of all bytes received and sent across the network
// for all peers.  It is safe for concurrent access.
func (s *ChainService) NetTotals() (uint64, uint64) {
	return atomic.LoadUint64(&s.bytesReceived),
		atomic.LoadUint64(&s.bytesSent)
}

// peerHandler is used to handle peer operations such as adding and removing
// peers to and from the server, banning peers, and broadcasting messages to
// peers.  It must be run in a goroutine.
func (s *ChainService) peerHandler() {
	state := &peerState{
		persistentPeers: make(map[int32]*ServerPeer),
		outboundPeers:   make(map[int32]*ServerPeer),
		outboundGroups:  make(map[string]int),
	}

	if !DisableDNSSeed {
		// Add peers discovered through DNS to the address manager.
		connmgr.SeedFromDNS(&s.chainParams, RequiredServices,
			s.nameResolver, func(addrs []*wire.NetAddressV2) {
				var validAddrs []*wire.NetAddressV2
				for _, addr := range addrs {
					addr.Services = RequiredServices

					validAddrs = append(validAddrs, addr)
				}

				if len(validAddrs) == 0 {
					return
				}

				// Bitcoind uses a lookup of the dns seeder
				// here. This is rather strange since the
				// values looked up by the DNS seed lookups
				// will vary quite a lot.  to replicate this
				// behaviour we put all addresses as having
				// come from the first one.
				s.addrManager.AddAddresses(
					validAddrs, validAddrs[0],
				)
			})
	}

out:
	for {
		select {
		// New peers connected to the server.
		case p := <-s.newPeers:
			s.handleAddPeerMsg(state, p)

		// Disconnected peers.
		case p := <-s.donePeers:
			s.handleDonePeerMsg(state, p)

		// Block accepted in mainchain or orphan, update peer height.
		case umsg := <-s.peerHeightsUpdate:
			s.handleUpdatePeerHeights(state, umsg)

		case qmsg := <-s.query:
			s.handleQuery(state, qmsg)

		case <-s.quit:
			// Disconnect all peers on server shutdown.
			state.forAllPeers(func(sp *ServerPeer) {
				log.Tracef("Shutdown peer %s", sp)
				sp.Disconnect()
			})
			break out
		}
	}

	// Drain channels before exiting so nothing is left waiting around
	// to send.
cleanup:
	for {
		select {
		case <-s.newPeers:
		case <-s.donePeers:
		case <-s.peerHeightsUpdate:
		case <-s.query:
		default:
			break cleanup
		}
	}
	s.wg.Done()
	log.Tracef("Peer handler done")
}

// addrStringToNetAddr takes an address in the form of 'host:port' or 'host'
// and returns a net.Addr which maps to the original address with any host
// names resolved to IP addresses and a default port added, if not specified,
// from the ChainService's network parameters.
func (s *ChainService) addrStringToNetAddr(addr string) (net.Addr, error) {
	host, strPort, err := net.SplitHostPort(addr)
	if err != nil {
		switch err.(type) {
		case *net.AddrError:
			host = addr
			strPort = s.ChainParams().DefaultPort
		default:
			return nil, err
		}
	}

	// Tor addresses cannot be resolved to an IP, so just return onionAddr
	// instead.
	if strings.HasSuffix(host, ".onion") {
		return &onionAddr{addr: addr}, nil
	}

	// Attempt to look up an IP address associated with the parsed host.
	ips, err := s.nameResolver(host)
	if err != nil {
		return nil, err
	}

	if len(ips) == 0 {
		return nil, fmt.Errorf("no addresses found for %s", host)
	}

	port, err := strconv.Atoi(strPort)
	if err != nil {
		return nil, err
	}

	return &net.TCPAddr{
		IP:   ips[0],
		Port: port,
	}, nil
}

// handleUpdatePeerHeight updates the heights of all peers who were known to
// announce a block we recently accepted.
func (s *ChainService) handleUpdatePeerHeights(state *peerState, umsg updatePeerHeightsMsg) {
	state.forAllPeers(func(sp *ServerPeer) {
		// The origin peer should already have the updated height.
		if sp == umsg.originPeer {
			return
		}

		// This is a pointer to the underlying memory which doesn't
		// change.
		latestBlkHash := sp.LastAnnouncedBlock()

		// Skip this peer if it hasn't recently announced any new blocks.
		if latestBlkHash == nil {
			return
		}

		// If the peer has recently announced a block, and this block
		// matches our newly accepted block, then update their block
		// height.
		if *latestBlkHash == *umsg.newHash {
			sp.UpdateLastBlockHeight(umsg.newHeight)
			sp.UpdateLastAnnouncedBlock(nil)
		}
	})
}

// handleAddPeerMsg deals with adding new peers.  It is invoked from the
// peerHandler goroutine.
func (s *ChainService) handleAddPeerMsg(state *peerState, sp *ServerPeer) bool {
	if sp == nil || !sp.Connected() {
		return false
	}

	// Ignore new peers if we're shutting down.
	if atomic.LoadInt32(&s.shutdown) != 0 {
		log.Infof("New peer %s ignored - server is shutting down", sp)
		sp.Disconnect()
		return false
	}

	// Disconnect banned peers.
	if s.IsBanned(sp.Addr()) {
		sp.Disconnect()
		return false
	}

	// TODO: Check for max peers from a single IP.

	// Limit max number of total peers.
	if state.Count() >= MaxPeers {
		log.Infof("Max peers reached [%d] - disconnecting peer %s",
			MaxPeers, sp)
		sp.Disconnect()
		// TODO: how to handle permanent peers here?
		// they should be rescheduled.
		return false
	}

	// Add the new peer and start it.
	log.Debugf("New peer %s", sp)
	state.outboundGroups[addrmgr.GroupKey(sp.NA())]++
	if sp.persistent {
		state.persistentPeers[sp.ID()] = sp
	} else {
		state.outboundPeers[sp.ID()] = sp
	}

	// Close firstPeerConnect channel so blockManager will be notified.
	if s.firstPeerConnect != nil {
		close(s.firstPeerConnect)
		s.firstPeerConnect = nil
	}

	// Update the address' last seen time if the peer has acknowledged our
	// version and has sent us its version as well.
	if sp.VerAckReceived() && sp.VersionKnown() && sp.NA() != nil {
		s.addrManager.Connected(sp.NA())
	}

	// Signal the block manager this peer is a new sync candidate.
	s.blockManager.NewPeer(sp)

	// Update the address manager and request known addresses from the
	// remote peer for outbound connections. This is skipped when running on
	// a development network since it is only intended to connect to
	// specified peers and actively avoids advertising and connecting to
	// discovered peers.
	if !isDevNetwork(s.chainParams.Net) {
		// Request known addresses if the server address manager needs
		// more and the peer has a protocol version new enough to
		// include a timestamp with addresses.
		hasTimestamp := sp.ProtocolVersion() >= wire.NetAddressTimeVersion
		if s.addrManager.NeedMoreAddresses() && hasTimestamp {
			sp.QueueMessage(wire.NewMsgGetAddr(), nil)
		}

		// Add the address to the addr manager anew, and also mark it as
		// a good address.
		s.addrManager.AddAddresses([]*wire.NetAddressV2{sp.NA()}, sp.NA())
		s.addrManager.Good(sp.NA())
	}

	// We'll go through each peer subscriber and notify it about the added
	// peer.
	n := 0
	for i, sub := range s.peerSubscribers {
		select {
		// Quickly check whether this subscription has been canceled.
		case <-sub.cancel:
			// Avoid GC leak.
			s.peerSubscribers[i] = nil
			continue
		default:
		}

		// Keep non-canceled subscribers around.
		s.peerSubscribers[n] = sub
		n++

		// Send a notification in a goroutine to avoid blocking the
		// peerHandler.
		s.wg.Add(1)
		go s.notifyConnectedPeer(sub, sp)
	}

	// Re-align the slice to only active subscribers.
	s.peerSubscribers = s.peerSubscribers[:n]

	return true
}

// notifyConnectedPeer sends the given peer to the peerSubsription.
//
// NOTE: MUST be run as a goroutine.
func (s *ChainService) notifyConnectedPeer(
	sub *peerSubscription, sp *ServerPeer) {

	defer s.wg.Done()

	select {
	case sub.peers <- sp:
	case <-sub.cancel:
	case <-s.quit:
	}
}

// handleDonePeerMsg deals with peers that have signalled they are done.  It is
// invoked from the peerHandler goroutine.
func (s *ChainService) handleDonePeerMsg(state *peerState, sp *ServerPeer) {
	// If the peer is being tracked internally, i.e., we received their
	// VerAck, we'll need to remove them.
	var list map[int32]*ServerPeer
	if sp.persistent {
		list = state.persistentPeers
	} else {
		list = state.outboundPeers
	}
	if _, ok := list[sp.ID()]; ok {
		state.outboundGroups[addrmgr.GroupKey(sp.NA())]--
		delete(list, sp.ID())

		log.Debugf("Removed peer %s", sp)
	}

	// Only request a new connection if the peer being disconnected is not
	// persistent and we still need more peer connections. There's no need
	// to do so if the peer is persistent since the connection manager will
	// attempt to reconnect.
	if sp.persistent {
		s.connManager.Disconnect(sp.connReq.ID())
		return
	}

	s.connManager.Remove(sp.connReq.ID())
	if state.Count() < MaxPeers {
		go s.connManager.NewConnReq()
	}
}

// disconnectPeer attempts to drop the connection of a tageted peer in the
// passed peer list. Targets are identified via usage of the passed
// `compareFunc`, which should return `true` if the passed peer is the target
// peer. This function returns true on success and false if the peer is unable
// to be located. If the peer is found, and the passed callback: `whenFound'
// isn't nil, we call it with the peer as the argument before it is removed
// from the peerList, and is disconnected from the server.
func disconnectPeer(peerList map[int32]*ServerPeer,
	compareFunc func(*ServerPeer) bool, whenFound func(*ServerPeer)) bool {

	for addr, peer := range peerList {
		if compareFunc(peer) {
			if whenFound != nil {
				whenFound(peer)
			}

			// This is ok because we are not continuing
			// to iterate so won't corrupt the loop.
			delete(peerList, addr)
			peer.Disconnect()
			return true
		}
	}
	return false
}

// SendTransaction broadcasts the transaction to all currently active peers so
// it can be propagated to other nodes and eventually mined. An error won't be
// returned if the transaction already exists within the mempool. Any
// transaction broadcast through this method will be rebroadcast upon every
// change of the tip of the chain.
func (s *ChainService) SendTransaction(tx *wire.MsgTx) error {
	// TODO(roasbeef): pipe through querying interface
	return s.broadcaster.Broadcast(tx)
}

// NewPeerConfig returns the configuration for the given ServerPeer.
func NewPeerConfig(sp *ServerPeer) *peer.Config {
	return &peer.Config{
		Listeners: peer.MessageListeners{
			OnVersion:   sp.OnVersion,
			OnVerAck:    sp.OnVerAck,
			OnInv:       sp.OnInv,
			OnHeaders:   sp.OnHeaders,
			OnReject:    sp.OnReject,
			OnFeeFilter: sp.OnFeeFilter,
			OnAddr:      sp.OnAddr,
			OnAddrV2:    sp.OnAddrV2,
			OnRead:      sp.OnRead,
			OnWrite:     sp.OnWrite,

			// Note: The reference client currently bans peers that send alerts
			// not signed with its key.  We could verify against their key, but
			// since the reference client is currently unwilling to support
			// other implementations' alert messages, we will not relay theirs.
			OnAlert: nil,
		},
		NewestBlock:      sp.newestBlock,
		HostToNetAddress: sp.server.addrManager.HostToNetAddress,
		UserAgentName:    sp.server.userAgentName,
		UserAgentVersion: sp.server.userAgentVersion,
		ChainParams:      &sp.server.chainParams,
		Services:         sp.server.services,
		ProtocolVersion:  wire.AddrV2Version,
		DisableRelayTx:   true,
	}
}

// outboundPeerConnected is invoked by the connection manager when a new
// outbound connection is established.  It initializes a new outbound server
// peer instance, associates it with the relevant state such as the connection
// request instance and the connection itself, and finally notifies the address
// manager of the attempt.
func (s *ChainService) outboundPeerConnected(c *connmgr.ConnReq, conn net.Conn) {
	// In the event that we have to disconnect the peer, we'll choose the
	// appropriate method to do so based on whether the connection request
	// is for a persistent peer or not.
	var disconnect func()
	if c.Permanent {
		disconnect = func() {
			s.connManager.Disconnect(c.ID())
		}
	} else {
		disconnect = func() {
			// Since we're completely removing the request for this
			// peer, we'll need to request a new one.
			s.connManager.Remove(c.ID())
			go s.connManager.NewConnReq()
		}
	}

	// If the peer is banned, then we'll disconnect them.
	peerAddr := c.Addr.String()
	if s.IsBanned(peerAddr) {
		disconnect()
		return
	}

	// If we're already connected to this peer, then we'll close out the new
	// connection and keep the old.
	if s.PeerByAddr(peerAddr) != nil {
		disconnect()
		return
	}

	sp := NewServerPeer(s, c.Permanent)
	p, err := peer.NewOutboundPeer(NewPeerConfig(sp), peerAddr)
	if err != nil {
		log.Debugf("Cannot create outbound peer %s: %s", c.Addr, err)
		disconnect()
		return
	}
	sp.Peer = p
	sp.connReq = c
	sp.AssociateConnection(conn)
	go s.peerDoneHandler(sp)
}

// peerDoneHandler handles peer disconnects by notifiying the server that it's
// done along with other performing other desirable cleanup.
func (s *ChainService) peerDoneHandler(sp *ServerPeer) {
	sp.WaitForDisconnect()

	select {
	case s.donePeers <- sp:
	case <-s.quit:
		return
	}

	// Only tell block manager we are gone if we ever told it we existed.
	if sp.VersionKnown() {
		s.blockManager.DonePeer(sp)
	}
	close(sp.quit)
}

// UpdatePeerHeights updates the heights of all peers who have have announced
// the latest connected main chain block, or a recognized orphan. These height
// updates allow us to dynamically refresh peer heights, ensuring sync peer
// selection has access to the latest block heights for each peer.
func (s *ChainService) UpdatePeerHeights(latestBlkHash *chainhash.Hash,
	latestHeight int32, updateSource *ServerPeer) {

	select {
	case s.peerHeightsUpdate <- updatePeerHeightsMsg{
		newHash:    latestBlkHash,
		newHeight:  latestHeight,
		originPeer: updateSource,
	}:
	case <-s.quit:
		return
	}
}

// ChainParams returns a copy of the ChainService's chaincfg.Params.
func (s *ChainService) ChainParams() chaincfg.Params {
	return s.chainParams
}

// Start begins connecting to peers and syncing the blockchain.
func (s *ChainService) Start() error {
	// Already started?
	if atomic.AddInt32(&s.started, 1) != 1 {
		return nil
	}

	// Start the address manager and block manager, both of which are
	// needed by peers.
	s.addrManager.Start()
	s.blockManager.Start()
	s.blockSubscriptionMgr.Start()
	if err := s.workManager.Start(); err != nil {
		return fmt.Errorf("unable to start work manager: %v", err)
	}

	if err := s.utxoScanner.Start(); err != nil {
		return fmt.Errorf("unable to start utxo scanner: %v", err)
	}

	if err := s.broadcaster.Start(); err != nil {
		return fmt.Errorf("unable to start transaction broadcaster: %v",
			err)
	}

	go s.connManager.Start()

	// Start the peer handler which in turn starts the address and block
	// managers.
	s.wg.Add(1)
	go s.peerHandler()

	return nil
}

// Stop gracefully shuts down the server by stopping and disconnecting all
// peers and the main listener.
func (s *ChainService) Stop() error {
	// Make sure this only happens once.
	if atomic.AddInt32(&s.shutdown, 1) != 1 {
		return nil
	}

	var returnErr error
	s.connManager.Stop()
	s.broadcaster.Stop()
	if err := s.utxoScanner.Stop(); err != nil {
		log.Errorf("error stopping utxo scanner: %v", err)
		returnErr = err
	}
	if err := s.workManager.Stop(); err != nil {
		log.Errorf("error stopping work manager: %v", err)
		returnErr = err
	}
	s.blockSubscriptionMgr.Stop()
	if err := s.blockManager.Stop(); err != nil {
		log.Errorf("error stopping block manager: %v", err)
		returnErr = err
	}
	if err := s.addrManager.Stop(); err != nil {
		log.Errorf("error stopping address manager: %v", err)
		returnErr = err
	}

	// Signal the remaining goroutines to quit.
	close(s.quit)
	s.wg.Wait()
	return returnErr
}

// IsCurrent lets the caller know whether the chain service's block manager
// thinks its view of the network is current.
func (s *ChainService) IsCurrent() bool {
	return s.blockManager.IsFullySynced()
}

// PeerByAddr lets the caller look up a peer address in the service's peer
// table, if connected to that peer address.
func (s *ChainService) PeerByAddr(addr string) *ServerPeer {
	for _, peer := range s.Peers() {
		if peer.Addr() == addr {
			return peer
		}
	}
	return nil
}

// RescanChainSource is a wrapper type around the ChainService struct that will
// be used to satisfy the rescan.ChainSource interface.
type RescanChainSource struct {
	*ChainService
}

// A compile-time check to ensure that RescanChainSource implements the
// rescan.ChainSource interface.
var _ ChainSource = (*RescanChainSource)(nil)

// GetBlockHeaderByHeight returns the header of the block with the given height.
func (s *RescanChainSource) GetBlockHeaderByHeight(
	height uint32) (*wire.BlockHeader, error) {

	return s.BlockHeaders.FetchHeaderByHeight(height)
}

// GetBlockHeader returns the header of the block with the given hash.
func (s *RescanChainSource) GetBlockHeader(
	hash *chainhash.Hash) (*wire.BlockHeader, uint32, error) {

	return s.BlockHeaders.FetchHeader(hash)
}

// GetFilterHeaderByHeight returns the filter header of the block with the given
// height.
func (s *RescanChainSource) GetFilterHeaderByHeight(
	height uint32) (*chainhash.Hash, error) {

	return s.RegFilterHeaders.FetchHeaderByHeight(height)
}

// Subscribe returns a block subscription that delivers block notifications in
// order. The bestHeight parameter can be used to signal that a backlog of
// notifications should be delivered from this height. When providing a height
// of 0, a backlog will not be delivered.
func (s *RescanChainSource) Subscribe(
	bestHeight uint32) (*blockntfns.Subscription, error) {

	return s.blockSubscriptionMgr.NewSubscription(bestHeight)
}

// cachedAddr is an empty struct used to satisfy the cache.Value interface.
type cachedAddr struct{}

// Size returns the size of cachedAddr, which is 1.
func (c *cachedAddr) Size() (uint64, error) {
	return 1, nil
}

// onionAddr implements the net.Addr interface and represents a tor address.
// This code is identical to btcd's unexported onionAddr. It is used so that
// neutrino can connect to v2 addresses without relying on the OnionCat
// encoding. It also enables connecting to v3 addresses.
type onionAddr struct {
	addr string
}

// String returns the onion address.
func (o *onionAddr) String() string {
	return o.addr
}

// Network returns "onion".
func (o *onionAddr) Network() string {
	return "onion"
}

// Ensure onionAddr implements the net.Addr interface.
var _ net.Addr = (*onionAddr)(nil)


text:
#ifndef __ZMQ_OPTIONS_HPP_INCLUDED__
#define __ZMQ_OPTIONS_HPP_INCLUDED__

#include <string>
#include <vector>
#include <set>

#include "stddef.h"
#include "stdint.hpp"
#include "tcp_address.hpp"

#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
#include <sys/types.h>
#endif
#ifdef ZMQ_HAVE_LOCAL_PEERCRED
#include <sys/ucred.h>
#endif

//  Normal base 256 key is 32 bytes
#define CURVE_KEYSIZE       32
//  Key encoded using Z85 is 40 bytes
#define CURVE_KEYSIZE_Z85   40

namespace zmq
{
    struct options_t
    {
        options_t ();

        int set_curve_key(uint8_t * destination, const void * optval_, size_t optvallen_);

        int setsockopt (int option_, const void *optval_, size_t optvallen_);
        int getsockopt (int option_, void *optval_, size_t *optvallen_) const;

        bool is_valid (int option_) const;

        //  High-water marks for message pipes.
        int sndhwm;
        int rcvhwm;

        //  I/O thread affinity.
        uint64_t affinity;

        //  Socket identity
        unsigned char identity_size;
        unsigned char identity [256];

        //  Maximum transfer rate [kb/s]. Default 100kb/s.
        int rate;

        //  Reliability time interval [ms]. Default 10 seconds.
        int recovery_ivl;

        // Sets the time-to-live field in every multicast packet sent.
        int multicast_hops;

        // Sets the maximum transport data unit size in every multicast
        // packet sent.
        int multicast_maxtpdu;

        // SO_SNDBUF and SO_RCVBUF to be passed to underlying transport sockets.
        int sndbuf;
        int rcvbuf;

        // Type of service (containing DSCP and ECN socket options)
        int tos;

        //  Socket type.
        int type;

        //  Linger time, in milliseconds.
        int linger;

        //  Maximum interval in milliseconds beyond which userspace will
        //  timeout connect().
        //  Default 0 (unused)
        int connect_timeout;

        //  Maximum interval in milliseconds beyond which TCP will timeout
        //  retransmitted packets.
        //  Default 0 (unused)
        int tcp_maxrt;

        //  Minimum interval between attempts to reconnect, in milliseconds.
        //  Default 100ms
        int reconnect_ivl;

        //  Maximum interval between attempts to reconnect, in milliseconds.
        //  Default 0 (unused)
        int reconnect_ivl_max;

        //  Maximum backlog for pending connections.
        int backlog;

        //  Maximal size of message to handle.
        int64_t maxmsgsize;

        // The timeout for send/recv operations for this socket.
        int rcvtimeo;
        int sndtimeo;

        //  If true, IPv6 is enabled (as well as IPv4)
        bool ipv6;

        //  If 1, connecting pipes are not attached immediately, meaning a send()
        //  on a socket with only connecting pipes would block
        int immediate;

        //  If 1, (X)SUB socket should filter the messages. If 0, it should not.
        bool filter;

        //  If true, the subscription matching on (X)PUB and (X)SUB sockets
        //  is reversed. Messages are sent to and received by non-matching
        //  sockets.
        bool invert_matching;

        //  If true, the identity message is forwarded to the socket.
        bool recv_identity;

        // if true, router socket accepts non-zmq tcp connections
        bool raw_socket;
        bool raw_notify;        //  Provide connect notifications

        //  Address of SOCKS proxy
        std::string socks_proxy_address;

        //  TCP keep-alive settings.
        //  Defaults to -1 = do not change socket options
        int tcp_keepalive;
        int tcp_keepalive_cnt;
        int tcp_keepalive_idle;
        int tcp_keepalive_intvl;

        // TCP accept() filters
        typedef std::vector <tcp_address_mask_t> tcp_accept_filters_t;
        tcp_accept_filters_t tcp_accept_filters;

        // IPC accept() filters
#       if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
        bool zap_ipc_creds;
        typedef std::set <uid_t> ipc_uid_accept_filters_t;
        ipc_uid_accept_filters_t ipc_uid_accept_filters;
        typedef std::set <gid_t> ipc_gid_accept_filters_t;
        ipc_gid_accept_filters_t ipc_gid_accept_filters;
#       endif
#       if defined ZMQ_HAVE_SO_PEERCRED
        typedef std::set <pid_t> ipc_pid_accept_filters_t;
        ipc_pid_accept_filters_t ipc_pid_accept_filters;
#       endif

        //  Security mechanism for all connections on this socket
        int mechanism;

        //  If peer is acting as server for PLAIN or CURVE mechanisms
        int as_server;

        //  ZAP authentication domain
        std::string zap_domain;

        //  Security credentials for PLAIN mechanism
        std::string plain_username;
        std::string plain_password;

        //  Security credentials for CURVE mechanism
        uint8_t curve_public_key [CURVE_KEYSIZE];
        uint8_t curve_secret_key [CURVE_KEYSIZE];
        uint8_t curve_server_key [CURVE_KEYSIZE];

        //  Principals for GSSAPI mechanism
        std::string gss_principal;
        std::string gss_service_principal;

        //  If true, gss encryption will be disabled
        bool gss_plaintext;

        //  ID of the socket.
        int socket_id;

        //  If true, socket conflates outgoing/incoming messages.
        //  Applicable to dealer, push/pull, pub/sub socket types.
        //  Cannot receive multi-part messages.
        //  Ignores hwm
        bool conflate;

        //  If connection handshake is not done after this many milliseconds,
        //  close socket.  Default is 30 secs.  0 means no handshake timeout.
        int handshake_ivl;

        bool connected;
        //  If remote peer receives a PING message and doesn't receive another
        //  message within the ttl value, it should close the connection
        //  (measured in tenths of a second)
        uint16_t heartbeat_ttl;
        //  Time in milliseconds between sending heartbeat PING messages.
        int heartbeat_interval;
        //  Time in milliseconds to wait for a PING response before disconnecting
        int heartbeat_timeout;

#       if defined ZMQ_HAVE_VMCI
        uint64_t vmci_buffer_size;
        uint64_t vmci_buffer_min_size;
        uint64_t vmci_buffer_max_size;
        int vmci_connect_timeout;
#       endif

        //  When creating a new ZMQ socket, if this option is set the value
        //  will be used as the File Descriptor instead of allocating a new
        //  one via the socket () system call.
        int use_fd;
    };
}

#endif


text:
use std::cmp::Ordering;
use serde::Serialize;
use chrono::{DateTime, Utc, TimeZone};
use chrono::serde::ts_milliseconds_option;

use crate::utils::Json;

#[derive(Serialize, Clone, Debug, Eq, PartialEq)]
pub struct Entry {
	pub title: String,
	pub guid: String,
	#[serde(rename="feedName")]
	pub feed_name: Option<String>,
	pub description: Option<String>,
	pub link: Option<String>,
	pub color: Option<String>,
	#[serde(rename="imageURL")]
	pub image_url: Option<String>,
	#[serde(with = "ts_milliseconds_option")]
	pub timestamp: Option<DateTime<Utc>>,
	pub extra: Option<Json>,
}

#[allow(dead_code)]
impl Entry {
	pub fn new(title: &str, guid: &str) -> Entry {
		Entry {
			title: title.to_string(),
			guid: guid.to_string(),
			feed_name: None,
			description: None,
			link: None,
			color: None,
			image_url: None,
			timestamp: None,
			extra: None,
		}
	}

	pub fn feed_name(mut self, feed_name: &str) -> Entry {
		self.feed_name = Some(feed_name.to_string());
		self
	}

	pub fn description(mut self, description: &str) -> Entry {
		self.description = Some(description.to_string());
		self
	}

	pub fn link(mut self, link: &str) -> Entry {
		self.link = Some(link.to_string());
		self
	}

	pub fn color(mut self, color: &str) -> Entry {
		self.color = Some(color.to_string());
		self
	}

	pub fn image_url(mut self, image_url: &str) -> Entry {
		self.image_url = Some(image_url.to_string());
		self
	}

	pub fn timestamp<Tz: TimeZone>(mut self, timestamp: DateTime<Tz>) -> Entry {
		self.timestamp = Some(timestamp.with_timezone(&Utc));
		self
	}

	pub fn extra(mut self, extra: Json) -> Entry {
		self.extra = Some(extra);
		self
	}

	pub fn set_feed_name(mut self, feed_name: Option<String>) -> Entry {
		self.feed_name = feed_name;
		self
	}

	pub fn set_description(mut self, description: Option<String>) -> Entry {
		self.description = description;
		self
	}

	pub fn set_link(mut self, link: Option<String>) -> Entry {
		self.link = link;
		self
	}

	pub fn set_color(mut self, color: Option<String>) -> Entry {
		self.color = color;
		self
	}

	pub fn set_image_url(mut self, image_url: Option<String>) -> Entry {
		self.image_url = image_url;
		self
	}

	pub fn set_timestamp<Tz: TimeZone>(mut self, timestamp: Option<DateTime<Tz>>) -> Entry {
		self.timestamp = timestamp.map(|ts| ts.with_timezone(&Utc));
		self
	}

	pub fn set_extra(mut self, extra: Option<Json>) -> Entry {
		self.extra = extra;
		self
	}
}

// Newest to oldest
impl Ord for Entry {
	fn cmp(&self, other: &Self) -> Ordering {
		match (&self.timestamp, &other.timestamp) {
			(None,    None   ) => Ordering::Equal,
			(Some(_), None   ) => Ordering::Greater,
			(None,    Some(_)) => Ordering::Less,
			(Some(s), Some(o)) => o.cmp(s),
		}
	}
}

impl PartialOrd for Entry {
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		Some(self.cmp(other))
	}
}


text:
                        <返回

                            添加好友

            <search-input search="searchfriend(content)" show-text="手机号"></search-input>

                    <addfirenditem ng-repeat="item in friendlist" item="item"></addfirenditem>

没有查找到该用户


text:
@interface PhotoSelectorManager : NSObject

+ (void)photoSelectorForTarget:(UIViewController *)target finished:(void(^)(NSArray *images))finished;

@end


text:
<?php

class Controller_Auth_Api extends Controller_Site_Api
{
	protected $check_not_auth_action = array(
		'get_login',
	);

	public function before()
	{
		parent::before();

		$this->auth_check_api(true);
		$this->set_current_user();
	}

	/**
	 * Api login
	 *
	 * @access  public
	 * @return  Response (html)
	 */
	public function get_login()
	{
		if ($this->format != 'html') throw new HttpNotFoundException();

		$response = '';
		try
		{
			$destination = Input::get('destination', '');

			$val = Validation::forge();
			$val->add_model(Model_MemberAuth::forge());
			$options = array('1' => '次回から自動的にログイン');
			$val->add('rememberme', '', array('type' => 'checkbox', 'options' => $options))->add_rule('checkbox_val', $options);

			$response = View::forge('auth/_parts/login', array('val' => $val, 'destination' => $destination));
			$status_code = 200;

			return Response::forge($response, $status_code);
		}
		catch(FuelException $e)
		{
			$status_code = 400;
		}

		$this->response($response, $status_code);
	}
}


text:
#include "hb-test.h"

/* Unit tests for hb-blob.h */

#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) && defined(HAVE_MMAP)

# define TEST_MMAP 1

#ifdef HAVE_SYS_MMAN_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <sys/mman.h>
#endif /* HAVE_SYS_MMAN_H */

#endif

static void
test_blob_empty (void)
{
  hb_blob_t *blob;
  unsigned int len;
  const char *data;
  char *data_writable;

  g_assert (hb_blob_is_immutable (hb_blob_get_empty ()));
  g_assert (hb_blob_get_empty () != NULL);
  g_assert (hb_blob_get_empty () == hb_blob_create (NULL, 0, HB_MEMORY_MODE_READONLY, NULL, NULL));
  g_assert (hb_blob_get_empty () == hb_blob_create ("asdf", 0, HB_MEMORY_MODE_READONLY, NULL, NULL));
  g_assert (hb_blob_get_empty () == hb_blob_create (NULL, -1, HB_MEMORY_MODE_READONLY, NULL, NULL));
  g_assert (hb_blob_get_empty () == hb_blob_create ("asdfg", -1, HB_MEMORY_MODE_READONLY, NULL, NULL));

  blob = hb_blob_get_empty ();
  g_assert (blob == hb_blob_get_empty ());

  len = hb_blob_get_length (blob);
  g_assert_cmpint (len, ==, 0);

  data = hb_blob_get_data (blob, NULL);
  g_assert (data == NULL);

  data = hb_blob_get_data (blob, &len);
  g_assert (data == NULL);
  g_assert_cmpint (len, ==, 0);

  data_writable = hb_blob_get_data_writable (blob, NULL);
  g_assert (data_writable == NULL);

  data_writable = hb_blob_get_data_writable (blob, &len);
  g_assert (data_writable == NULL);
  g_assert_cmpint (len, ==, 0);
}

static const char test_data[] = "test\0data";

static const char *blob_names[] = {
  "duplicate",
  "readonly",
  "writable"
#ifdef TEST_MMAP
   , "readonly-may-make-writable"
#endif
};

typedef struct
{
  hb_blob_t *blob;
  int freed;
  char *data;
  unsigned int len;
} fixture_t;

static void
free_up (fixture_t *fixture)
{
  g_assert_cmpint (fixture->freed, ==, 0);
  fixture->freed++;
}

static void
free_up_free (fixture_t *fixture)
{
  free_up (fixture);
  free (fixture->data);
}

#ifdef TEST_MMAP
static uintptr_t
get_pagesize (void)
{
  uintptr_t pagesize = -1;

#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
  pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
  pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
#elif defined(HAVE_GETPAGESIZE)
  pagesize = (uintptr_t) getpagesize ();
#endif

  g_assert (pagesize != (uintptr_t) -1);

  return pagesize;
}

static void
free_up_munmap (fixture_t *fixture)
{
  free_up (fixture);
  munmap (fixture->data, get_pagesize ());
}
#endif

#include <errno.h>
static void
fixture_init (fixture_t *fixture, gconstpointer user_data)
{
  hb_memory_mode_t mm = (hb_memory_mode_t) GPOINTER_TO_INT (user_data);
  unsigned int len;
  const char *data;
  hb_destroy_func_t free_func;

  switch (GPOINTER_TO_INT (user_data))
  {
    case HB_MEMORY_MODE_DUPLICATE:
      data = test_data;
      len = sizeof (test_data);
      free_func = (hb_destroy_func_t) free_up;
      break;

    case HB_MEMORY_MODE_READONLY:
      data = test_data;
      len = sizeof (test_data);
      free_func = (hb_destroy_func_t) free_up;
      break;

    case HB_MEMORY_MODE_WRITABLE:
      data = malloc (sizeof (test_data));
      memcpy ((char *) data, test_data, sizeof (test_data));
      len = sizeof (test_data);
      free_func = (hb_destroy_func_t) free_up_free;
      break;

#ifdef TEST_MMAP
    case HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE:
    {
      uintptr_t pagesize = get_pagesize ();

      data = mmap (NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
      g_assert (data != (char *) -1);
      memcpy ((char *) data, test_data, sizeof (test_data));
      mprotect ((char *) data, pagesize, PROT_READ);
      len = sizeof (test_data);
      free_func = (hb_destroy_func_t) free_up_munmap;
      break;
    }
#endif

    default:
      g_assert_not_reached ();
  }

  fixture->freed = 0;
  fixture->data = (char *) data;
  fixture->len = len;
  fixture->blob = hb_blob_create (data, len, mm, fixture, free_func);
}

static void
fixture_finish (fixture_t *fixture, gconstpointer user_data)
{
  hb_blob_destroy (fixture->blob);
  g_assert_cmpint (fixture->freed, ==, 1);
}

static void
test_blob (fixture_t *fixture, gconstpointer user_data)
{
  hb_blob_t *b = fixture->blob;
  hb_memory_mode_t mm = GPOINTER_TO_INT (user_data);
  unsigned int len;
  const char *data;
  char *data_writable;
  unsigned int i;

  g_assert (b);

  len = hb_blob_get_length (b);
  g_assert_cmpint (len, ==, fixture->len);

  data = hb_blob_get_data (b, &len);
  g_assert_cmpint (len, ==, fixture->len);
  if (mm == HB_MEMORY_MODE_DUPLICATE) {
    g_assert (data != fixture->data);
    g_assert_cmpint (fixture->freed, ==, 1);
    mm = HB_MEMORY_MODE_WRITABLE;
  } else {
    g_assert (data == fixture->data);
    g_assert_cmpint (fixture->freed, ==, 0);
  }

  data_writable = hb_blob_get_data_writable (b, &len);
  g_assert_cmpint (len, ==, fixture->len);
  g_assert (data_writable);
  g_assert (0 == memcmp (data_writable, fixture->data, fixture->len));
  if (mm == HB_MEMORY_MODE_READONLY) {
    g_assert (data_writable != data);
    g_assert_cmpint (fixture->freed, ==, 1);
  } else {
    g_assert (data_writable == data);
  }

  data = hb_blob_get_data (b, &len);
  g_assert_cmpint (len, ==, fixture->len);
  g_assert (data == data_writable);

  memset (data_writable, 0, fixture->len);

  /* Now, make it immutable and watch get_data_writable() fail */

  g_assert (!hb_blob_is_immutable (b));
  hb_blob_make_immutable (b);
  g_assert (hb_blob_is_immutable (b));

  data_writable = hb_blob_get_data_writable (b, &len);
  g_assert (!data_writable);
  g_assert_cmpint (len, ==, 0);

  data = hb_blob_get_data (b, &len);
  g_assert_cmpint (len, ==, fixture->len);
  for (i = 0; i < len; i++)
    g_assert ('\0' == data[i]);
}

static void
test_blob_subblob (fixture_t *fixture, gconstpointer user_data)
{
  hb_blob_t *b = fixture->blob;
  hb_memory_mode_t mm = GPOINTER_TO_INT (user_data);
  unsigned int len;
  const char *data;
  char *data_writable;
  unsigned int i;

  if (mm == HB_MEMORY_MODE_DUPLICATE) {
    g_assert_cmpint (fixture->freed, ==, 1);
    fixture->data = (char *) hb_blob_get_data (b, NULL);
  } else {
    g_assert_cmpint (fixture->freed, ==, 0);
  }
  fixture->blob = hb_blob_create_sub_blob (b, 1, fixture->len - 2);
  hb_blob_destroy (b);
  b = fixture->blob;

  /* A sub-blob is always created READONLY. */

  g_assert (b);

  len = hb_blob_get_length (b);
  g_assert_cmpint (len, ==, fixture->len - 2);

  data = hb_blob_get_data (b, &len);
  g_assert_cmpint (len, ==, fixture->len - 2);
  g_assert (data == fixture->data + 1);

  data_writable = hb_blob_get_data_writable (b, &len);
  g_assert_cmpint (len, ==, fixture->len - 2);
  g_assert (data_writable);
  if (mm == HB_MEMORY_MODE_READONLY)
    g_assert (0 == memcmp (data_writable, fixture->data + 1, fixture->len - 2));
  g_assert (data_writable != data);
  g_assert_cmpint (fixture->freed, ==, 1);

  data = hb_blob_get_data (b, &len);
  g_assert_cmpint (len, ==, fixture->len - 2);
  g_assert (data == data_writable);

  memset (data_writable, 0, fixture->len - 2);

  /* Now, make it immutable and watch get_data_writable() fail */

  g_assert (!hb_blob_is_immutable (b));
  hb_blob_make_immutable (b);
  g_assert (hb_blob_is_immutable (b));

  data_writable = hb_blob_get_data_writable (b, &len);
  g_assert (!data_writable);
  g_assert_cmpint (len, ==, 0);

  data = hb_blob_get_data (b, &len);
  g_assert_cmpint (len, ==, fixture->len - 2);
  for (i = 0; i < len; i++)
    g_assert ('\0' == data[i]);
}

int
main (int argc, char **argv)
{
  unsigned int i;

  hb_test_init (&argc, &argv);

  hb_test_add (test_blob_empty);

  for (i = 0; i < G_N_ELEMENTS (blob_names); i++)
  {
    const void *blob_type = GINT_TO_POINTER (i);
    const char *blob_name = blob_names[i];

    hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob);
    hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob_subblob);
  }

  /*
   * create_sub_blob
   */

  return hb_test_run ();
}


text:
package avrora.sim.util;

import avrora.sim.mcu.Microcontroller.Pin.Input;
import avrora.sim.mcu.Microcontroller.Pin.InputListener;
import avrora.sim.mcu.Microcontroller.Pin.Output;
import java.util.LinkedList;

/**
 *
 * @author S. Willenborg
 */
public class LCX138 {

    public final OPin A0 = new OPin("A0");
    public final OPin A1 = new OPin("A1");
    public final OPin A2 = new OPin("A2");

    public final OPin E1 = new OPin("E1");
    public final OPin E2 = new OPin("E2");
    public final OPin E3 = new OPin("E3");

    public final IPin O0 = new IPin("O0", 0);
    public final IPin O1 = new IPin("O1", 1);
    public final IPin O2 = new IPin("O2", 2);
    public final IPin O3 = new IPin("O3", 3);
    public final IPin O4 = new IPin("O4", 4);
    public final IPin O5 = new IPin("O5", 5);
    public final IPin O6 = new IPin("O6", 6);
    public final IPin O7 = new IPin("O7", 7);

    private int state = -1;

    public LCX138() {
        update();
    }

    private void update() {
        if (!E1.value && !E2.value && E3.value) {
            state = (A0.value ? 1 : 0) | (A1.value ? 2 : 0) | (A2.value ? 4 : 0);
        } else {
            state = -1;
        }
        O0.update();
        O1.update();
        O2.update();
        O3.update();
        O4.update();
        O5.update();
        O6.update();
        O7.update();

    }
    public class OPin implements Output {
        final String name;
        boolean value = false;

        public OPin(String name) {
            this.name = name;
        }

        @Override
        public void write(boolean level) {
            value = level;
            update();
        }
    }

    public class IPin implements Input {
        final String name;
        final int index;
        boolean cur_level = true;
        final LinkedList<InputListener> listeners = new LinkedList<>();

        public IPin(String name, int index) {
            this.name = name;
            this.index = index;
        }

        @Override
        public boolean read() {
            return cur_level;
        }

        private void update() {
             boolean new_level = (state != index);
             if (new_level != cur_level) {
                cur_level = new_level;
                for (InputListener listener : listeners) {
                    listener.onInputChanged(this, new_level);
                }
            }
        }

        @Override
        public void registerListener(InputListener listener) {
            if (!listeners.contains(listener)) {
                listeners.add(listener);
            }
        }

        @Override
        public void unregisterListener(InputListener listener) {
            if (listeners.contains(listener)) {
                listeners.remove(listener);
            }
        }

    }
}


text:
source $(dirname $0)/../fns.sh

brew_tap 'dart-lang/dart'
brew_install_or_upgrade 'dart'


text:
#include "mitkUnstructuredGridVtkMapper3D.h"
#include "mitkColorProperty.h"
#include "mitkDataNode.h"
#include "mitkProperties.h"
#include "mitkTransferFunctionProperty.h"
//#include "mitkLookupTableProperty.h"
#include "mitkGridRepresentationProperty.h"
#include "mitkGridVolumeMapperProperty.h"
#include "mitkVtkInterpolationProperty.h"
#include "mitkVtkScalarModeProperty.h"

#include "mitkDataStorage.h"

#include "mitkSurfaceVtkMapper3D.h"

#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>
#include <vtkVolume.h>
#include <vtkVolumeProperty.h>

#include <vtkPlanes.h>

const mitk::UnstructuredGrid *mitk::UnstructuredGridVtkMapper3D::GetInput()
{
  return static_cast<const mitk::UnstructuredGrid *>(GetDataNode()->GetData());
}

mitk::UnstructuredGridVtkMapper3D::UnstructuredGridVtkMapper3D()
{
  m_VtkTriangleFilter = vtkDataSetTriangleFilter::New();

  m_Assembly = vtkAssembly::New();

  m_Volume = vtkVolume::New();
  m_Actor = vtkActor::New();
  m_ActorWireframe = vtkActor::New();

  m_VtkDataSetMapper = vtkUnstructuredGridMapper::New();
  m_VtkDataSetMapper->SetResolveCoincidentTopologyToPolygonOffset();
  m_VtkDataSetMapper->SetResolveCoincidentTopologyPolygonOffsetParameters(0, 1);
  m_Actor->SetMapper(m_VtkDataSetMapper);

  m_VtkDataSetMapper2 = vtkUnstructuredGridMapper::New();
  m_VtkDataSetMapper2->SetResolveCoincidentTopologyToPolygonOffset();
  m_VtkDataSetMapper2->SetResolveCoincidentTopologyPolygonOffsetParameters(1, 1);
  m_ActorWireframe->SetMapper(m_VtkDataSetMapper2);
  m_ActorWireframe->GetProperty()->SetRepresentationToWireframe();

  m_Assembly->AddPart(m_Actor);
  m_Assembly->AddPart(m_ActorWireframe);
  m_Assembly->AddPart(m_Volume);

  m_VtkVolumeRayCastMapper = 0;
  m_VtkPTMapper = 0;
  m_VtkVolumeZSweepMapper = 0;

  // m_GenerateNormals = false;
}

mitk::UnstructuredGridVtkMapper3D::~UnstructuredGridVtkMapper3D()
{
  if (m_VtkTriangleFilter != 0)
    m_VtkTriangleFilter->Delete();

  if (m_VtkVolumeRayCastMapper != 0)
    m_VtkVolumeRayCastMapper->Delete();

  if (m_VtkVolumeZSweepMapper != 0)
    m_VtkVolumeZSweepMapper->Delete();

  if (m_VtkPTMapper != 0)
    m_VtkPTMapper->Delete();

  if (m_VtkDataSetMapper != 0)
    m_VtkDataSetMapper->Delete();

  if (m_VtkDataSetMapper2 != 0)
    m_VtkDataSetMapper2->Delete();

  if (m_Assembly != 0)
    m_Assembly->Delete();

  if (m_Actor != 0)
    m_Actor->Delete();

  if (m_ActorWireframe != 0)
    m_ActorWireframe->Delete();

  if (m_Volume != 0)
    m_Volume->Delete();
}

vtkProp *mitk::UnstructuredGridVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/)
{
  return m_Assembly;
}

void mitk::UnstructuredGridVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer)
{
  mitk::DataNode::ConstPointer node = this->GetDataNode();

  BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer);
  bool needGenerateData = ls->IsGenerateDataRequired(renderer, this, GetDataNode());

  if (needGenerateData)
  {
    ls->UpdateGenerateDataTime();

    m_Assembly->VisibilityOn();

    m_ActorWireframe->GetProperty()->SetAmbient(1.0);
    m_ActorWireframe->GetProperty()->SetDiffuse(0.0);
    m_ActorWireframe->GetProperty()->SetSpecular(0.0);

    mitk::TransferFunctionProperty::Pointer transferFuncProp;
    if (node->GetProperty(transferFuncProp, "TransferFunction"))
    {
      mitk::TransferFunction::Pointer transferFunction = transferFuncProp->GetValue();
      if (transferFunction->GetColorTransferFunction()->GetSize() < 2)
      {
        mitk::UnstructuredGrid::Pointer input = const_cast<mitk::UnstructuredGrid *>(this->GetInput());
        if (input.IsNull())
          return;

        vtkUnstructuredGrid *grid = input->GetVtkUnstructuredGrid(this->GetTimestep());
        if (grid == 0)
          return;

        double *scalarRange = grid->GetScalarRange();
        vtkColorTransferFunction *colorFunc = transferFunction->GetColorTransferFunction();
        colorFunc->RemoveAllPoints();
        colorFunc->AddRGBPoint(scalarRange[0], 1, 0, 0);
        colorFunc->AddRGBPoint((scalarRange[0] + scalarRange[1]) / 2.0, 0, 1, 0);
        colorFunc->AddRGBPoint(scalarRange[1], 0, 0, 1);
      }
    }
  }

  bool visible = true;
  GetDataNode()->GetVisibility(visible, renderer, "visible");

  if (!visible)
  {
    m_Assembly->VisibilityOff();
    return;
  }

  //
  // get the TimeGeometry of the input object
  //
  mitk::UnstructuredGrid::Pointer input = const_cast<mitk::UnstructuredGrid *>(this->GetInput());

  //
  // set the input-object at time t for the mapper
  //
  vtkUnstructuredGrid *grid = input->GetVtkUnstructuredGrid(this->GetTimestep());
  if (grid == 0)
  {
    m_Assembly->VisibilityOff();
    return;
  }

  m_Assembly->VisibilityOn();

  m_VtkTriangleFilter->SetInputData(grid);
  m_VtkDataSetMapper->SetInput(grid);
  m_VtkDataSetMapper2->SetInput(grid);

  bool clip = false;
  node->GetBoolProperty("enable clipping", clip);
  mitk::DataNode::Pointer bbNode = renderer->GetDataStorage()->GetNamedDerivedNode("Clipping Bounding Object", node);
  if (clip && bbNode.IsNotNull())
  {
    m_VtkDataSetMapper->SetBoundingObject(dynamic_cast<mitk::BoundingObject *>(bbNode->GetData()));
    m_VtkDataSetMapper2->SetBoundingObject(dynamic_cast<mitk::BoundingObject *>(bbNode->GetData()));
  }
  else
  {
    m_VtkDataSetMapper->SetBoundingObject(0);
    m_VtkDataSetMapper2->SetBoundingObject(0);
  }

  //
  // apply properties read from the PropertyList
  //
  ApplyProperties(0, renderer);
}

void mitk::UnstructuredGridVtkMapper3D::ResetMapper(BaseRenderer * /*renderer*/)
{
  m_Assembly->VisibilityOff();
}

void mitk::UnstructuredGridVtkMapper3D::ApplyProperties(vtkActor * /*actor*/, mitk::BaseRenderer *renderer)
{
  mitk::DataNode::Pointer node = this->GetDataNode();
  ApplyColorAndOpacityProperties(renderer, m_Actor);
  ApplyColorAndOpacityProperties(renderer, m_ActorWireframe);

  vtkVolumeProperty *volProp = m_Volume->GetProperty();
  vtkProperty *property = m_Actor->GetProperty();
  vtkProperty *wireframeProp = m_ActorWireframe->GetProperty();

  mitk::SurfaceVtkMapper3D::ApplyMitkPropertiesToVtkProperty(node, property, renderer);
  mitk::SurfaceVtkMapper3D::ApplyMitkPropertiesToVtkProperty(node, wireframeProp, renderer);

  mitk::TransferFunctionProperty::Pointer transferFuncProp;
  if (node->GetProperty(transferFuncProp, "TransferFunction", renderer))
  {
    mitk::TransferFunction::Pointer transferFunction = transferFuncProp->GetValue();

    volProp->SetColor(transferFunction->GetColorTransferFunction());
    volProp->SetScalarOpacity(transferFunction->GetScalarOpacityFunction());
    volProp->SetGradientOpacity(transferFunction->GetGradientOpacityFunction());

    m_VtkDataSetMapper->SetLookupTable(transferFunction->GetColorTransferFunction());
    m_VtkDataSetMapper2->SetLookupTable(transferFunction->GetColorTransferFunction());
  }

  bool isVolumeRenderingOn = false;
  node->GetBoolProperty("volumerendering", isVolumeRenderingOn, renderer);

  if (isVolumeRenderingOn)
  {
    m_Assembly->RemovePart(m_Actor);
    m_Assembly->RemovePart(m_ActorWireframe);
    m_Assembly->AddPart(m_Volume);

    mitk::GridVolumeMapperProperty::Pointer mapperProp;
    if (node->GetProperty(mapperProp, "volumerendering.mapper", renderer))
    {
      mitk::GridVolumeMapperProperty::IdType type = mapperProp->GetValueAsId();
      switch (type)
      {
        case mitk::GridVolumeMapperProperty::RAYCAST:
          if (m_VtkVolumeRayCastMapper == 0)
          {
            m_VtkVolumeRayCastMapper = vtkUnstructuredGridVolumeRayCastMapper::New();
            m_VtkVolumeRayCastMapper->SetInputConnection(m_VtkTriangleFilter->GetOutputPort());
          }
          m_Volume->SetMapper(m_VtkVolumeRayCastMapper);
          break;
        case mitk::GridVolumeMapperProperty::PT:
          if (m_VtkPTMapper == 0)
          {
            m_VtkPTMapper = vtkProjectedTetrahedraMapper::New();
            m_VtkPTMapper->SetInputConnection(m_VtkTriangleFilter->GetOutputPort());
          }
          m_Volume->SetMapper(m_VtkPTMapper);
          break;
        case mitk::GridVolumeMapperProperty::ZSWEEP:
          if (m_VtkVolumeZSweepMapper == 0)
          {
            m_VtkVolumeZSweepMapper = vtkUnstructuredGridVolumeZSweepMapper::New();
            m_VtkVolumeZSweepMapper->SetInputConnection(m_VtkTriangleFilter->GetOutputPort());
          }
          m_Volume->SetMapper(m_VtkVolumeZSweepMapper);
          break;
      }
    }
  }
  else
  {
    m_Assembly->RemovePart(m_Volume);
    m_Assembly->AddPart(m_Actor);
    m_Assembly->RemovePart(m_ActorWireframe);

    mitk::GridRepresentationProperty::Pointer gridRepProp;
    if (node->GetProperty(gridRepProp, "grid representation", renderer))
    {
      mitk::GridRepresentationProperty::IdType type = gridRepProp->GetValueAsId();
      switch (type)
      {
        case mitk::GridRepresentationProperty::POINTS:
          property->SetRepresentationToPoints();
          break;
        case mitk::GridRepresentationProperty::WIREFRAME:
          property->SetRepresentationToWireframe();
          break;
        case mitk::GridRepresentationProperty::SURFACE:
          property->SetRepresentationToSurface();
          break;
      }

      //      if (type == mitk::GridRepresentationProperty::WIREFRAME_SURFACE)
      //      {
      //        m_Assembly->AddPart(m_ActorWireframe);
      //      }
    }
  }

  //   mitk::LevelWindow levelWindow;
  //   if(node->GetLevelWindow(levelWindow, renderer, "levelWindow"))
  //   {
  //     m_VtkVolumeRayCastMapper->SetScalarRange(levelWindow.GetMin(),levelWindow.GetMax());
  //   }
  //   else
  //   if(node->GetLevelWindow(levelWindow, renderer))
  //   {
  //     m_VtkVolumeRayCastMapper->SetScalarRange(levelWindow.GetMin(),levelWindow.GetMax());
  //   }
  //
  //   mitk::VtkRepresentationProperty* representationProperty;
  //   node->GetProperty(representationProperty, "material.representation", renderer);
  //   if ( representationProperty != NULL )
  //     m_Volume->GetProperty()->SetRepresentation( representationProperty->GetVtkRepresentation() );
  //
  //   mitk::VtkInterpolationProperty* interpolationProperty;
  //   node->GetProperty(interpolationProperty, "material.interpolation", renderer);
  //   if ( interpolationProperty != NULL )
  //     m_Volume->GetProperty()->SetInterpolation( interpolationProperty->GetVtkInterpolation() );
  //

  mitk::VtkScalarModeProperty *scalarMode = 0;
  if (node->GetProperty(scalarMode, "scalar mode", renderer))
  {
    if (m_VtkVolumeRayCastMapper)
      m_VtkVolumeRayCastMapper->SetScalarMode(scalarMode->GetVtkScalarMode());
    if (m_VtkPTMapper)
      m_VtkPTMapper->SetScalarMode(scalarMode->GetVtkScalarMode());
    if (m_VtkVolumeZSweepMapper)
      m_VtkVolumeZSweepMapper->SetScalarMode(scalarMode->GetVtkScalarMode());

    m_VtkDataSetMapper->SetScalarMode(scalarMode->GetVtkScalarMode());
    m_VtkDataSetMapper2->SetScalarMode(scalarMode->GetVtkScalarMode());
  }
  else
  {
    if (m_VtkVolumeRayCastMapper)
      m_VtkVolumeRayCastMapper->SetScalarModeToDefault();
    if (m_VtkPTMapper)
      m_VtkPTMapper->SetScalarModeToDefault();
    if (m_VtkVolumeZSweepMapper)
      m_VtkVolumeZSweepMapper->SetScalarModeToDefault();

    m_VtkDataSetMapper->SetScalarModeToDefault();
    m_VtkDataSetMapper2->SetScalarModeToDefault();
  }

  bool scalarVisibility = true;
  node->GetBoolProperty("scalar visibility", scalarVisibility, renderer);
  m_VtkDataSetMapper->SetScalarVisibility(scalarVisibility ? 1 : 0);
  m_VtkDataSetMapper2->SetScalarVisibility(scalarVisibility ? 1 : 0);

  //   double scalarRangeLower = std::numeric_limits<double>::min();
  //   double scalarRangeUpper = std::numeric_limits<double>::max();
  //   mitk::DoubleProperty* lowerRange = 0;
  //   if (node->GetProperty(lowerRange, "scalar range min", renderer))
  //   {
  //     scalarRangeLower = lowerRange->GetValue();
  //   }
  //   mitk::DoubleProperty* upperRange = 0;
  //   if (node->GetProperty(upperRange, "scalar range max", renderer))
  //   {
  //     scalarRangeUpper = upperRange->GetValue();
  //   }
  //   m_VtkDataSetMapper->SetScalarRange(scalarRangeLower, scalarRangeUpper);
  //   m_VtkDataSetMapper2->SetScalarRange(scalarRangeLower, scalarRangeUpper);

  //   bool colorMode = false;
  //   node->GetBoolProperty("color mode", colorMode);
  //   m_VtkVolumeRayCastMapper->SetColorMode( (colorMode ? 1 : 0) );

  //   double scalarsMin = 0;
  //   node->GetDoubleProperty("ScalarsRangeMinimum", scalarsMin, renderer);

  //   double scalarsMax = 1.0;
  //   node->GetProperty("ScalarsRangeMaximum", scalarsMax, renderer);

  //   m_VtkVolumeRayCastMapper->SetScalarRange(scalarsMin,scalarsMax);
}

void mitk::UnstructuredGridVtkMapper3D::SetDefaultProperties(mitk::DataNode *node,
                                                             mitk::BaseRenderer *renderer,
                                                             bool overwrite)
{
  SurfaceVtkMapper3D::SetDefaultPropertiesForVtkProperty(node, renderer, overwrite);

  node->AddProperty("grid representation", GridRepresentationProperty::New(), renderer, overwrite);
  node->AddProperty("volumerendering", BoolProperty::New(false), renderer, overwrite);
  node->AddProperty("volumerendering.mapper", GridVolumeMapperProperty::New(), renderer, overwrite);
  node->AddProperty("scalar mode", VtkScalarModeProperty::New(0), renderer, overwrite);
  node->AddProperty("scalar visibility", BoolProperty::New(true), renderer, overwrite);
  // node->AddProperty("scalar range min", DoubleProperty::New(std::numeric_limits<double>::min()), renderer,
  // overwrite);
  // node->AddProperty("scalar range max", DoubleProperty::New(std::numeric_limits<double>::max()), renderer,
  // overwrite);
  node->AddProperty("outline polygons", BoolProperty::New(false), renderer, overwrite);
  node->AddProperty("color", ColorProperty::New(1.0f, 1.0f, 1.0f), renderer, overwrite);
  node->AddProperty("line width", IntProperty::New(1), renderer, overwrite);

  if (overwrite || node->GetProperty("TransferFunction", renderer) == 0)
  {
    // add a default transfer function
    mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New();
    // tf->GetColorTransferFunction()->RemoveAllPoints();
    node->SetProperty("TransferFunction", mitk::TransferFunctionProperty::New(tf.GetPointer()));
  }

  Superclass::SetDefaultProperties(node, renderer, overwrite);
}