text:
#ifndef _INC_WSDBASE
#define _INC_WSDBASE

#ifndef _INC_WSDAPI
#error Please include wsdapi.h instead of this header. This header cannot be used directly.
#endif

#if (_WIN32_WINNT >= 0x0600)

#warning COM interfaces layout in this header has not been validated.
#warning COM interfaces with incorrect layout may not work at all.

typedef enum _WSDUdpMessageType {
  ONE_WAY   = 0,
  TWO_WAY   = 1
} WSDUdpMessageType;

typedef struct _WSDUpdRetransmitParams {
  ULONG ulSendDelay;
  ULONG ulRepeat;
  ULONG ulRepeatMinDelay;
  ULONG ulRepeatMaxDelay;
  ULONG ulRepeatUpperDelay;
} WSDUdpRetransmitParams, *PWSDUdpRetransmitParams;

#undef  INTERFACE
#define INTERFACE IWSDTransportAddress
#ifdef __GNUC__
#warning COM interfaces layout in this header has not been verified.
#warning COM interfaces with incorrect layout may not work at all.
__MINGW_BROKEN_INTERFACE(INTERFACE)
#endif
DECLARE_INTERFACE_(IWSDTransportAddress,IUnknown)
{
    BEGIN_INTERFACE

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IWSDTransportAddress methods */
    STDMETHOD_(HRESULT,GetPort)(THIS_ WORD *pwPort) PURE;
    STDMETHOD_(HRESULT,SetPort)(THIS_ WORD wPort) PURE;
    STDMETHOD_(HRESULT,GetTransportAddress)(THIS_ LPCWSTR *ppszAddress) PURE;
    STDMETHOD_(HRESULT,GetTransportAddressEx)(THIS_ WINBOOL fSafe,LPCWSTR *ppszAddress) PURE;
    STDMETHOD_(HRESULT,SetTransportAddress)(THIS_ LPCWSTR pszAddress) PURE;

    END_INTERFACE
};
#ifdef COBJMACROS
#define IWSDTransportAddress_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IWSDTransportAddress_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IWSDTransportAddress_Release(This) (This)->lpVtbl->Release(This)
#define IWSDTransportAddress_GetPort(This,pwPort) (This)->lpVtbl->GetPort(This,pwPort)
#define IWSDTransportAddress_SetPort(This,wPort) (This)->lpVtbl->SetPort(This,wPort)
#define IWSDTransportAddress_GetTransportAddress(This,ppszAddress) (This)->lpVtbl->GetTransportAddress(This,ppszAddress)
#define IWSDTransportAddress_GetTransportAddressEx(This,fSafe,ppszAddress) (This)->lpVtbl->GetTransportAddressEx(This,fSafe,ppszAddress)
#define IWSDTransportAddress_SetTransportAddress(This,pszAddress) (This)->lpVtbl->SetTransportAddress(This,pszAddress)
#endif /*COBJMACROS*/

#undef  INTERFACE
#define INTERFACE IWSDHttpAddress
#ifdef __GNUC__
#warning COM interfaces layout in this header has not been verified.
#warning COM interfaces with incorrect layout may not work at all.
__MINGW_BROKEN_INTERFACE(INTERFACE)
#endif
DECLARE_INTERFACE_(IWSDHttpAddress,IWSDTransportAddress)
{
    BEGIN_INTERFACE

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IWSDTransportAddress methods */
    STDMETHOD_(HRESULT,GetPort)(THIS_ WORD *pwPort) PURE;
    STDMETHOD_(HRESULT,SetPort)(THIS_ WORD wPort) PURE;
    STDMETHOD_(HRESULT,GetTransportAddress)(THIS_ LPCWSTR *ppszAddress) PURE;
    STDMETHOD_(HRESULT,GetTransportAddressEx)(THIS_ WINBOOL fSafe,LPCWSTR *ppszAddress) PURE;
    STDMETHOD_(HRESULT,SetTransportAddress)(THIS_ LPCWSTR pszAddress) PURE;

    /* IWSDHttpAddress methods */
    STDMETHOD_(HRESULT,GetSecure)(THIS) PURE;
    STDMETHOD_(HRESULT,SetSecure)(THIS_ WINBOOL fSecure) PURE;
    STDMETHOD_(HRESULT,GetPath)(THIS_ LPCWSTR *ppszPath) PURE;
    STDMETHOD_(HRESULT,SetPath)(THIS_ LPCWSTR pszPath) PURE;

    END_INTERFACE
};
#ifdef COBJMACROS
#define IWSDHttpAddress_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IWSDHttpAddress_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IWSDHttpAddress_Release(This) (This)->lpVtbl->Release(This)
#define IWSDHttpAddress_GetPort(This,pwPort) (This)->lpVtbl->GetPort(This,pwPort)
#define IWSDHttpAddress_SetPort(This,wPort) (This)->lpVtbl->SetPort(This,wPort)
#define IWSDHttpAddress_GetTransportAddress(This,ppszAddress) (This)->lpVtbl->GetTransportAddress(This,ppszAddress)
#define IWSDHttpAddress_GetTransportAddressEx(This,fSafe,ppszAddress) (This)->lpVtbl->GetTransportAddressEx(This,fSafe,ppszAddress)
#define IWSDHttpAddress_SetTransportAddress(This,pszAddress) (This)->lpVtbl->SetTransportAddress(This,pszAddress)
#define IWSDHttpAddress_GetSecure() (This)->lpVtbl->GetSecure(This)
#define IWSDHttpAddress_SetSecure(This,fSecure) (This)->lpVtbl->SetSecure(This,fSecure)
#define IWSDHttpAddress_GetPath(This,ppszPath) (This)->lpVtbl->GetPath(This,ppszPath)
#define IWSDHttpAddress_SetPath(This,pszPath) (This)->lpVtbl->SetPath(This,pszPath)
#endif /*COBJMACROS*/

#undef  INTERFACE
#define INTERFACE IWSDUdpAddress
#ifdef __GNUC__
#warning COM interfaces layout in this header has not been verified.
#warning COM interfaces with incorrect layout may not work at all.
__MINGW_BROKEN_INTERFACE(INTERFACE)
#endif
DECLARE_INTERFACE_(IWSDUdpAddress,IWSDTransportAddress)
{
    BEGIN_INTERFACE

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IWSDTransportAddress methods */
    STDMETHOD_(HRESULT,GetPort)(THIS_ WORD *pwPort) PURE;
    STDMETHOD_(HRESULT,SetPort)(THIS_ WORD wPort) PURE;
    STDMETHOD_(HRESULT,GetTransportAddress)(THIS_ LPCWSTR *ppszAddress) PURE;
    STDMETHOD_(HRESULT,GetTransportAddressEx)(THIS_ WINBOOL fSafe,LPCWSTR *ppszAddress) PURE;
    STDMETHOD_(HRESULT,SetTransportAddress)(THIS_ LPCWSTR pszAddress) PURE;

    /* IWSDUdpAddress methods */
    STDMETHOD_(HRESULT,SetSockaddr)(THIS_ const SOCKADDR_STORAGE *pSockAddr) PURE;
    STDMETHOD_(HRESULT *,GetSockaddr)(THIS_ SOCKADDR_STORAGE *pSockAddr) PURE;
    STDMETHOD_(HRESULT,SetExclusive)(THIS_ WINBOOL fExclusive) PURE;
    STDMETHOD_(HRESULT,GetExclusive)(THIS) PURE;
    STDMETHOD_(HRESULT,SetMessageType)(THIS_ WSDUdpMessageType messageType) PURE;
    STDMETHOD_(HRESULT,GetMessageType)(THIS_ WSDUdpMessageType *pMessageType) PURE;
    STDMETHOD_(HRESULT,SetTTL)(THIS_ DWORD dwTTL) PURE;
    STDMETHOD_(HRESULT,GetTTL)(THIS_ DWORD *pdwTTL) PURE;
    STDMETHOD_(HRESULT,SetAlias)(THIS_ const GUID *pAlias) PURE;
    STDMETHOD_(HRESULT,GetAlias)(THIS_ GUID *pAlias) PURE;

    END_INTERFACE
};
#ifdef COBJMACROS
#define IWSDUdpAddress_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IWSDUdpAddress_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IWSDUdpAddress_Release(This) (This)->lpVtbl->Release(This)
#define IWSDUdpAddress_GetPort(This,pwPort) (This)->lpVtbl->GetPort(This,pwPort)
#define IWSDUdpAddress_SetPort(This,wPort) (This)->lpVtbl->SetPort(This,wPort)
#define IWSDUdpAddress_GetTransportAddress(This,ppszAddress) (This)->lpVtbl->GetTransportAddress(This,ppszAddress)
#define IWSDUdpAddress_GetTransportAddressEx(This,fSafe,ppszAddress) (This)->lpVtbl->GetTransportAddressEx(This,fSafe,ppszAddress)
#define IWSDUdpAddress_SetTransportAddress(This,pszAddress) (This)->lpVtbl->SetTransportAddress(This,pszAddress)
#define IWSDUdpAddress_SetSockaddr(This,pSockAddr) (This)->lpVtbl->SetSockaddr(This,pSockAddr)
#define IWSDUdpAddress_GetSockaddr(This,pSockAddr) (This)->lpVtbl->GetSockaddr(This,pSockAddr)
#define IWSDUdpAddress_SetExclusive(This,fExclusive) (This)->lpVtbl->SetExclusive(This,fExclusive)
#define IWSDUdpAddress_GetExclusive() (This)->lpVtbl->GetExclusive(This)
#define IWSDUdpAddress_SetMessageType(This,messageType) (This)->lpVtbl->SetMessageType(This,messageType)
#define IWSDUdpAddress_GetMessageType(This,pMessageType) (This)->lpVtbl->GetMessageType(This,pMessageType)
#define IWSDUdpAddress_SetTTL(This,dwTTL) (This)->lpVtbl->SetTTL(This,dwTTL)
#define IWSDUdpAddress_GetTTL(This,pdwTTL) (This)->lpVtbl->GetTTL(This,pdwTTL)
#define IWSDUdpAddress_SetAlias(This,pAlias) (This)->lpVtbl->SetAlias(This,pAlias)
#define IWSDUdpAddress_GetAlias(This,pAlias) (This)->lpVtbl->GetAlias(This,pAlias)
#endif /*COBJMACROS*/

#undef  INTERFACE
#define INTERFACE IWSDAddress
#ifdef __GNUC__
#warning COM interfaces layout in this header has not been verified.
#warning COM interfaces with incorrect layout may not work at all.
__MINGW_BROKEN_INTERFACE(INTERFACE)
#endif
DECLARE_INTERFACE_(IWSDAddress,IUnknown)
{
    BEGIN_INTERFACE

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IWSDAddress methods */
    STDMETHOD_(HRESULT,Serialize)(THIS_ LPWSTR pszBuffer,DWORD cchLength,WINBOOL fSafe) PURE;
    STDMETHOD_(HRESULT,Deserialize)(THIS_ LPCWSTR pszBuffer) PURE;

    END_INTERFACE
};
#ifdef COBJMACROS
#define IWSDAddress_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IWSDAddress_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IWSDAddress_Release(This) (This)->lpVtbl->Release(This)
#define IWSDAddress_Serialize(This,pszBuffer,cchLength,fSafe) (This)->lpVtbl->Serialize(This,pszBuffer,cchLength,fSafe)
#define IWSDAddress_Deserialize(This,pszBuffer) (This)->lpVtbl->Deserialize(This,pszBuffer)
#endif /*COBJMACROS*/

#undef  INTERFACE
#define INTERFACE IWSDMessageParameters
#ifdef __GNUC__
#warning COM interfaces layout in this header has not been verified.
#warning COM interfaces with incorrect layout may not work at all.
__MINGW_BROKEN_INTERFACE(INTERFACE)
#endif
DECLARE_INTERFACE_(IWSDMessageParameters,IUnknown)
{
    BEGIN_INTERFACE

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IWSDServiceMessaging methods */
    STDMETHOD_(HRESULT,GetLocalAddress)(THIS_ IWSDAddress **ppAddress) PURE;
    STDMETHOD_(HRESULT,SetLocalAddress)(THIS_ IWSDAddress *pAddress) PURE;
    STDMETHOD_(HRESULT,GetRemoteAddress)(THIS_ IWSDAddress **ppAddress) PURE;
    STDMETHOD_(HRESULT,SetRemoteAddress)(THIS_ IWSDAddress *pAddress) PURE;
    STDMETHOD_(HRESULT,GetLowerParameters)(THIS_ IWSDMessageParameters **ppTxParams) PURE;

    END_INTERFACE
};
#ifdef COBJMACROS
#define IWSDMessageParameters_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IWSDMessageParameters_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IWSDMessageParameters_Release(This) (This)->lpVtbl->Release(This)
#define IWSDMessageParameters_GetLocalAddress(This,ppAddress) (This)->lpVtbl->GetLocalAddress(This,ppAddress)
#define IWSDMessageParameters_SetLocalAddress(This,pAddress) (This)->lpVtbl->SetLocalAddress(This,pAddress)
#define IWSDMessageParameters_GetRemoteAddress(This,ppAddress) (This)->lpVtbl->GetRemoteAddress(This,ppAddress)
#define IWSDMessageParameters_SetRemoteAddress(This,pAddress) (This)->lpVtbl->SetRemoteAddress(This,pAddress)
#define IWSDMessageParameters_GetLowerParameters(This,ppTxParams) (This)->lpVtbl->GetLowerParameters(This,ppTxParams)
#endif /*COBJMACROS*/

#undef  INTERFACE
#define INTERFACE IWSDHttpMessageParameters
#ifdef __GNUC__
#warning COM interfaces layout in this header has not been verified.
#warning COM interfaces with incorrect layout may not work at all.
__MINGW_BROKEN_INTERFACE(INTERFACE)
#endif
DECLARE_INTERFACE_(IWSDHttpMessageParameters,IWSDMessageParameters)
{
    BEGIN_INTERFACE

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IWSDServiceMessaging methods */
    STDMETHOD_(HRESULT,GetLocalAddress)(THIS_ IWSDAddress **ppAddress) PURE;
    STDMETHOD_(HRESULT,SetLocalAddress)(THIS_ IWSDAddress *pAddress) PURE;
    STDMETHOD_(HRESULT,GetRemoteAddress)(THIS_ IWSDAddress **ppAddress) PURE;
    STDMETHOD_(HRESULT,SetRemoteAddress)(THIS_ IWSDAddress *pAddress) PURE;
    STDMETHOD_(HRESULT,GetLowerParameters)(THIS_ IWSDMessageParameters **ppTxParams) PURE;

    /* IWSDHttpMessageParameters methods */
    STDMETHOD_(HRESULT,SetInboundHttpHeaders)(THIS_ LPCWSTR pszHeaders) PURE;
    STDMETHOD_(HRESULT,GetInboundHttpHeaders)(THIS_ LPCWSTR *ppszHeaders) PURE;
    STDMETHOD_(HRESULT,SetOutboundHttpHeaders)(THIS_ LPCWSTR pszHeaders) PURE;
    STDMETHOD_(HRESULT,GetOutboundHttpHeaders)(THIS_ LPCWSTR *ppszHeaders) PURE;
    STDMETHOD_(HRESULT,SetID)(THIS_ LPCWSTR pszId) PURE;
    STDMETHOD_(HRESULT,GetID)(THIS_ LPCWSTR *ppszId) PURE;
    STDMETHOD_(HRESULT,SetContext)(THIS_ IUnknown *pContext) PURE;
    STDMETHOD_(HRESULT,GetContext)(THIS_ IUnknown **ppContext) PURE;
    STDMETHOD_(HRESULT,Clear)(THIS) PURE;

    END_INTERFACE
};
#ifdef COBJMACROS
#define IWSDHttpMessageParameters_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IWSDHttpMessageParameters_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IWSDHttpMessageParameters_Release(This) (This)->lpVtbl->Release(This)
#define IWSDHttpMessageParameters_GetLocalAddress(This,ppAddress) (This)->lpVtbl->GetLocalAddress(This,ppAddress)
#define IWSDHttpMessageParameters_SetLocalAddress(This,pAddress) (This)->lpVtbl->SetLocalAddress(This,pAddress)
#define IWSDHttpMessageParameters_GetRemoteAddress(This,ppAddress) (This)->lpVtbl->GetRemoteAddress(This,ppAddress)
#define IWSDHttpMessageParameters_SetRemoteAddress(This,pAddress) (This)->lpVtbl->SetRemoteAddress(This,pAddress)
#define IWSDHttpMessageParameters_GetLowerParameters(This,ppTxParams) (This)->lpVtbl->GetLowerParameters(This,ppTxParams)
#define IWSDHttpMessageParameters_SetInboundHttpHeaders(This,pszHeaders) (This)->lpVtbl->SetInboundHttpHeaders(This,pszHeaders)
#define IWSDHttpMessageParameters_GetInboundHttpHeaders(This,ppszHeaders) (This)->lpVtbl->GetInboundHttpHeaders(This,ppszHeaders)
#define IWSDHttpMessageParameters_SetOutboundHttpHeaders(This,pszHeaders) (This)->lpVtbl->SetOutboundHttpHeaders(This,pszHeaders)
#define IWSDHttpMessageParameters_GetOutboundHttpHeaders(This,ppszHeaders) (This)->lpVtbl->GetOutboundHttpHeaders(This,ppszHeaders)
#define IWSDHttpMessageParameters_SetID(This,pszId) (This)->lpVtbl->SetID(This,pszId)
#define IWSDHttpMessageParameters_GetID(This,ppszId) (This)->lpVtbl->GetID(This,ppszId)
#define IWSDHttpMessageParameters_SetContext(This,pContext) (This)->lpVtbl->SetContext(This,pContext)
#define IWSDHttpMessageParameters_GetContext(This,ppContext) (This)->lpVtbl->GetContext(This,ppContext)
#define IWSDHttpMessageParameters_Clear() (This)->lpVtbl->Clear(This)
#endif /*COBJMACROS*/

#undef  INTERFACE
#define INTERFACE IWSDUdpMessageParameters
#ifdef __GNUC__
#warning COM interfaces layout in this header has not been verified.
#warning COM interfaces with incorrect layout may not work at all.
__MINGW_BROKEN_INTERFACE(INTERFACE)
#endif
DECLARE_INTERFACE_(IWSDUdpMessageParameters,IWSDMessageParameters)
{
    BEGIN_INTERFACE

    /* IUnknown methods */
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IWSDServiceMessaging methods */
    STDMETHOD_(HRESULT,GetLocalAddress)(THIS_ IWSDAddress **ppAddress) PURE;
    STDMETHOD_(HRESULT,SetLocalAddress)(THIS_ IWSDAddress *pAddress) PURE;
    STDMETHOD_(HRESULT,GetRemoteAddress)(THIS_ IWSDAddress **ppAddress) PURE;
    STDMETHOD_(HRESULT,SetRemoteAddress)(THIS_ IWSDAddress *pAddress) PURE;
    STDMETHOD_(HRESULT,GetLowerParameters)(THIS_ IWSDMessageParameters **ppTxParams) PURE;

    /* IWSDUdpMessageParameters methods */
    STDMETHOD_(HRESULT,SetRetransmitParams)(THIS_ const WSDUdpRetransmitParams *pParams) PURE;
    STDMETHOD_(HRESULT,GetRetransmitParams)(THIS_ WSDUdpRetransmitParams *pParams) PURE;

    END_INTERFACE
};
#ifdef COBJMACROS
#define IWSDUdpMessageParameters_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
#define IWSDUdpMessageParameters_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IWSDUdpMessageParameters_Release(This) (This)->lpVtbl->Release(This)
#define IWSDUdpMessageParameters_GetLocalAddress(This,ppAddress) (This)->lpVtbl->GetLocalAddress(This,ppAddress)
#define IWSDUdpMessageParameters_SetLocalAddress(This,pAddress) (This)->lpVtbl->SetLocalAddress(This,pAddress)
#define IWSDUdpMessageParameters_GetRemoteAddress(This,ppAddress) (This)->lpVtbl->GetRemoteAddress(This,ppAddress)
#define IWSDUdpMessageParameters_SetRemoteAddress(This,pAddress) (This)->lpVtbl->SetRemoteAddress(This,pAddress)
#define IWSDUdpMessageParameters_GetLowerParameters(This,ppTxParams) (This)->lpVtbl->GetLowerParameters(This,ppTxParams)
#define IWSDUdpMessageParameters_SetRetransmitParams(This,pParams) (This)->lpVtbl->SetRetransmitParams(This,pParams)
#define IWSDUdpMessageParameters_GetRetransmitParams(This,pParams) (This)->lpVtbl->GetRetransmitParams(This,pParams)
#endif /*COBJMACROS*/

#ifdef __cplusplus
extern "C" {
#endif

HRESULT WINAPI WSDCreateHttpAddress(
  IWSDHttpAddress **ppAddress
);

HRESULT WINAPI WSDCreateHttpMessageParameters(
  IWSDHttpMessageParameters **ppTxParams
);

HRESULT WINAPI WSDCreateUdpAddress(
  IWSDUdpAddress **ppAddress
);

HRESULT WINAPI WSDCreateUdpMessageParameters(
  IWSDUdpMessageParameters **ppTxParams
);

#ifdef __cplusplus
}
#endif
#endif /*(_WIN32_WINNT >= 0x0600)*/
#endif /*_INC_WSDBASE*/


text:
/**
 * Populate DB with sample data on server start
 * to disable, edit config/environment/index.js, and set `seedDB: false`
 */

'use strict';

//var Thing = require('../api/thing/thing.model');
var User = require('../api/user/user.model');

redpajama_set_name: RedPajamaGithub


text:
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// Package p2p implements the Ethereum p2p network protocols.
package p2p

import (
	"bytes"
	"crypto/ecdsa"
	"errors"
	"fmt"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/ethereum/go-ethereum/log"
	"github.com/fractalplatform/fractal/common"
	"github.com/fractalplatform/fractal/crypto"
	"github.com/fractalplatform/fractal/event"
	"github.com/fractalplatform/fractal/p2p/discover"
	"github.com/fractalplatform/fractal/p2p/enode"
	"github.com/fractalplatform/fractal/p2p/netutil"
)

const (
	defaultDialTimeout = 15 * time.Second

	// Connectivity defaults.
	maxActiveDialTasks     = 16
	defaultMaxPendingPeers = 50
	defaultDialRatio       = 3

	// Maximum time allowed for reading a complete message.
	// This is effectively the amount of time a connection can be idle.
	frameReadTimeout = 30 * time.Second

	// Maximum amount of time allowed for writing a complete message.
	frameWriteTimeout = 20 * time.Second
)

var errServerStopped = errors.New("server stopped")

// Config holds Server options.
type Config struct {
	// This field must be set to a valid secp256k1 private key.
	PrivateKey *ecdsa.PrivateKey

	// This field with NetworkID used to generate MagicNetID. Set by ftservice when construct.
	GenesisHash common.Hash

	// NetworkID is ID of network
	NetworkID uint `mapstructure:"networkid"`

	// MaxPeers is the maximum number of peers that can be
	// connected. It must be greater than zero.
	MaxPeers int `mapstructure:"maxpeers"`

	// MaxPendingPeers is the maximum number of peers that can be pending in the
	// handshake phase, counted separately for inbound and outbound connections.
	// Zero defaults to preset values.
	MaxPendingPeers int `mapstructure:"maxpendpeers"`

	// DialRatio controls the ratio of inbound to dialed connections.
	// Example: a DialRatio of 2 allows 1/2 of connections to be dialed.
	// Setting DialRatio to zero defaults it to 3.
	DialRatio int `mapstructure:"dialratio"`

	// NoDiscovery can be used to disable the peer discovery mechanism.
	// Disabling is useful for protocol debugging (manual topology).
	NoDiscovery bool `mapstructure:"nodiscover"`

	// Name sets the node name of this server.
	// Use common.MakeName to create a name that follows existing conventions.
	Name string `mapstructure:"name"`

	// BootstrapNodes are used to establish connectivity
	// with the rest of the network.
	BootstrapNodes []*enode.Node

	// Static nodes are used as pre-configured connections which are always
	// maintained and re-connected on disconnects.
	StaticNodes []*enode.Node

	// Trusted nodes are used as pre-configured connections which are always
	// allowed to connect, even above the peer limit.
	TrustedNodes []*enode.Node

	// Connectivity can be restricted to certain IP networks.
	// If this option is set to a non-nil value, only hosts which match one of the
	// IP networks contained in the list are considered.
	NetRestrict *netutil.Netlist `mapstructure:"badIP"`

	// NodeDatabase is the path to the database containing the previously seen
	// live nodes in the network.
	NodeDatabase string

	// Protocols should contain the protocols supported
	// by the server. Matching protocols are launched for
	// each peer.
	Protocols []Protocol

	// If ListenAddr is set to a non-nil address, the server
	// will listen for incoming connections.
	//
	// If the port is zero, the operating system will pick a port. The
	// ListenAddr field will be updated with the actual address when
	// the server is started.
	ListenAddr string `mapstructure:"listenaddr"`

	// If set to a non-nil value, the given NAT port mapper
	// is used to make the listening port available to the
	// Internet.
	// NAT nat.Interface `toml:",omitempty"`

	// If Dialer is set to a non-nil value, the given Dialer
	// is used to dial outbound peer connections.
	Dialer NodeDialer

	// If NoDial is true, the server will not dial any peers.
	NoDial bool `mapstructure:"nodial"`

	// Disconnect the worst peer ervery PeerPeriod ms.
	PeerPeriod int `mapstructure:"peerperiod"`

	// If EnableMsgEvents is set then the server will emit PeerEvents
	// whenever a message is sent to or received from a peer
	EnableMsgEvents bool

	// Logger is a custom logger to use with the p2p.Server.
	Logger log.Logger
}

type badNode struct {
	node    *enode.Node
	endtime int64
}

// Server manages all peer connections.
type Server struct {
	// Config fields may not be modified while the server is running.
	*Config

	// Hooks for testing. These are useful because we can inhibit
	// the whole protocol stack.
	newTransport func(net.Conn, uint64) transport
	newPeerHook  func(*Peer)

	lock    sync.Mutex // protects running
	running bool

	ntab         discoverTable
	listener     net.Listener
	ourHandshake *protoHandshake
	lastLookup   time.Time
	//DiscV5       *discv5.Network

	// These are for Peers, PeerCount (and nothing else).
	peerOp     chan peerOpFunc
	peerOpDone chan struct{}

	badNodeOp     chan badOpFunc
	badNodeOpDone chan struct{}

	quit          chan struct{}
	addstatic     chan *enode.Node
	removestatic  chan *enode.Node
	addtrusted    chan *enode.Node
	removetrusted chan *enode.Node
	addBad        chan *badNode
	removeBad     chan *enode.Node
	posthandshake chan *conn
	addpeer       chan *conn
	delpeer       chan peerDrop
	loopWG        sync.WaitGroup // loop, listenLoop
	peerFeed      event.Feed
	log           log.Logger
}

type peerOpFunc func(map[enode.ID]*Peer)
type badOpFunc func(map[enode.ID]*badNode)

type peerDrop struct {
	*Peer
	err       error
	requested bool // true if signaled by the peer
}

type connFlag int32

const (
	dynDialedConn connFlag = 1 << iota
	staticDialedConn
	inboundConn
	trustedConn
	badNodeConn
)

// conn wraps a network connection with information gathered
// during the two handshakes.
type conn struct {
	fd net.Conn
	transport
	node  *enode.Node
	flags connFlag
	cont  chan error // The run loop uses cont to signal errors to SetupConn.
	caps  []Cap      // valid after the protocol handshake
	name  string     // valid after the protocol handshake
}

type transport interface {
	// The two handshakes.
	doEncHandshake(prv *ecdsa.PrivateKey, dialDest *ecdsa.PublicKey) (*ecdsa.PublicKey, error)
	doProtoHandshake(our *protoHandshake) (*protoHandshake, error)
	// The MsgReadWriter can only be used after the encryption
	// handshake has completed. The code uses conn.id to track this
	// by setting it to a non-nil value after the encryption handshake.
	MsgReadWriter
	// transports must provide Close because we use MsgPipe in some of
	// the tests. Closing the actual network connection doesn't do
	// anything in those tests because NsgPipe doesn't use it.
	close(err error)
}

func (c *conn) String() string {
	s := c.flags.String()
	if (c.node.ID() != enode.ID{}) {
		s += " " + c.node.ID().String()
	}
	s += " " + c.fd.RemoteAddr().String()
	return s
}

func (f connFlag) String() string {
	s := ""
	if f&trustedConn != 0 {
		s += "-trusted"
	}
	if f&dynDialedConn != 0 {
		s += "-dyndial"
	}
	if f&staticDialedConn != 0 {
		s += "-staticdial"
	}
	if f&inboundConn != 0 {
		s += "-inbound"
	}
	if s != "" {
		s = s[1:]
	}
	return s
}

func (c *conn) is(f connFlag) bool {
	flags := connFlag(atomic.LoadInt32((*int32)(&c.flags)))
	return flags&f != 0
}

func (c *conn) set(f connFlag, val bool) {
	for {
		oldFlags := connFlag(atomic.LoadInt32((*int32)(&c.flags)))
		flags := oldFlags
		if val {
			flags |= f
		} else {
			flags &= ^f
		}
		if atomic.CompareAndSwapInt32((*int32)(&c.flags), int32(oldFlags), int32(flags)) {
			return
		}
	}
}

// Peers returns all connected peers.
func (srv *Server) Peers() []*Peer {
	var ps []*Peer
	select {
	// Note: We'd love to put this function into a variable but
	// that seems to cause a weird compiler error in some
	// environments.
	case srv.peerOp <- func(peers map[enode.ID]*Peer) {
		for _, p := range peers {
			ps = append(ps, p)
		}
	}:
		<-srv.peerOpDone
	case <-srv.quit:
	}
	return ps
}

func (srv *Server) SeedNodes() []*enode.Node {
	return srv.ntab.SeedNodes()
}

// PeerCount returns the number of connected peers.
func (srv *Server) PeerCount() int {
	var count int
	select {
	case srv.peerOp <- func(ps map[enode.ID]*Peer) { count = len(ps) }:
		<-srv.peerOpDone
	case <-srv.quit:
	}
	return count
}

// BadNodes returns all bad nodes.
func (srv *Server) BadNodes() []*enode.Node {
	var ns []*enode.Node
	select {
	// Note: We'd love to put this function into a variable but
	// that seems to cause a weird compiler error in some
	// environments.
	case srv.badNodeOp <- func(nodes map[enode.ID]*badNode) {
		ns = make([]*enode.Node, 0, len(nodes))
		for _, n := range nodes {
			ns = append(ns, n.node)
		}
	}:
		<-srv.badNodeOpDone
	case <-srv.quit:
	}
	return ns
}

// BadNodesCount returns the number of bad nodes.
func (srv *Server) BadNodesCount() int {
	var count int
	select {
	case srv.badNodeOp <- func(nodes map[enode.ID]*badNode) { count = len(nodes) }:
		<-srv.badNodeOpDone
	case <-srv.quit:
	}
	return count
}

// AddPeer connects to the given node and maintains the connection until the
// server is shut down. If the connection fails for any reason, the server will
// attempt to reconnect the peer.
func (srv *Server) AddPeer(node *enode.Node) {
	select {
	case srv.addstatic <- node:
	case <-srv.quit:
	}
}

// AddBadNode add the node to the blacklist
func (srv *Server) AddBadNode(node *enode.Node, endtime *time.Time) {
	var timestamp int64
	if endtime != nil {
		timestamp = endtime.Unix()
	}
	select {
	case srv.addBad <- &badNode{node, timestamp}:
	case <-srv.quit:
	}
}

// RemoveBadNode remove the node from the blacklist
func (srv *Server) RemoveBadNode(node *enode.Node) {
	select {
	case srv.removeBad <- node:
	case <-srv.quit:
	}
}

// RemovePeer disconnects from the given node
func (srv *Server) RemovePeer(node *enode.Node) {
	select {
	case srv.removestatic <- node:
	case <-srv.quit:
	}
}

// AddTrustedPeer adds the given node to a reserved whitelist which allows the
// node to always connect, even if the slot are full.
func (srv *Server) AddTrustedPeer(node *enode.Node) {
	select {
	case srv.addtrusted <- node:
	case <-srv.quit:
	}
}

// RemoveTrustedPeer removes the given node from the trusted peer set.
func (srv *Server) RemoveTrustedPeer(node *enode.Node) {
	select {
	case srv.removetrusted <- node:
	case <-srv.quit:
	}
}

// SubscribeEvents subscribes the given channel to peer events
func (srv *Server) SubscribeEvents(ch chan *PeerEvent) event.Subscription {
	return srv.peerFeed.Subscribe(ch)
}

// Self returns the local node's endpoint information.
func (srv *Server) Self() *enode.Node {
	srv.lock.Lock()
	running, listener, ntab := srv.running, srv.listener, srv.ntab
	srv.lock.Unlock()

	if !running {
		return enode.NewV4(&srv.PrivateKey.PublicKey, net.ParseIP("0.0.0.0"), 0, 0)
	}
	return srv.makeSelf(listener, ntab)
}

func (srv *Server) makeSelf(listener net.Listener, ntab discoverTable) *enode.Node {
	// If the node is running but discovery is off, manually assemble the node infos.
	if ntab == nil {
		addr := srv.tcpAddr(listener)
		return enode.NewV4(&srv.PrivateKey.PublicKey, addr.IP, addr.Port, 0)
	}
	// Otherwise return the discovery node.
	return ntab.Self()
}

func (srv *Server) tcpAddr(listener net.Listener) net.TCPAddr {
	addr := net.TCPAddr{IP: net.IP{0, 0, 0, 0}}
	if listener == nil {
		return addr // Inbound connections disabled, use zero address.
	}
	// Otherwise inject the listener address too.
	if a, ok := listener.Addr().(*net.TCPAddr); ok {
		addr = *a
	}
	if addr.IP.IsUnspecified() {
		addr.IP = net.IP{127, 0, 0, 1}
	}
	return addr
}

// Stop terminates the server and all active peer connections.
// It blocks until all active connections have been closed.
func (srv *Server) Stop() {
	srv.lock.Lock()
	if !srv.running {
		srv.lock.Unlock()
		return
	}
	srv.running = false
	if srv.listener != nil {
		// this unblocks listener Accept
		srv.listener.Close()
	}
	close(srv.quit)
	srv.lock.Unlock()
	srv.loopWG.Wait()
}

// sharedUDPConn implements a shared connection. Write sends messages to the underlying connection while read returns
// messages that were found unprocessable and sent to the unhandled channel by the primary listener.
type sharedUDPConn struct {
	*net.UDPConn
	unhandled chan discover.ReadPacket
}

// ReadFromUDP implements discv5.conn
func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
	packet, ok := <-s.unhandled
	if !ok {
		return 0, nil, fmt.Errorf("Connection was closed")
	}
	l := len(packet.Data)
	if l > len(b) {
		l = len(b)
	}
	copy(b[:l], packet.Data[:l])
	return l, packet.Addr, nil
}

// Close implements discv5.conn
func (s *sharedUDPConn) Close() error {
	return nil
}

func (srv *Server) magicNetID() uint64 {
	return (srv.GenesisHash.Big().Uint64() & 0xffffffff) | (uint64(srv.NetworkID) << 32)
}

// DiscoverOnly ..
func (srv *Server) DiscoverOnly() error {
	srv.lock.Lock()
	defer srv.lock.Unlock()
	if srv.running {
		return errors.New("server already running")
	}
	srv.running = true
	srv.log = srv.Config.Logger
	if srv.log == nil {
		srv.log = log.New()
	}

	srv.quit = make(chan struct{})

	srv.log.Info("Starting P2P discovery networking", "NetID", srv.magicNetID(), "UsrNetID", srv.NetworkID)

	// static fields
	if srv.PrivateKey == nil {
		return fmt.Errorf("Server.PrivateKey must be set to a non-nil key")
	}

	addr, err := net.ResolveUDPAddr("udp", srv.ListenAddr)
	if err != nil {
		return err
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		return err
	}
	cfg := discover.Config{
		TCPPort:      0,
		MagicNetID:   srv.magicNetID(),
		PrivateKey:   srv.PrivateKey,
		AnnounceAddr: conn.LocalAddr().(*net.UDPAddr),
		NodeDBPath:   srv.NodeDatabase,
		NetRestrict:  srv.NetRestrict,
		Bootnodes:    srv.BootstrapNodes,
		Unhandled:    nil,
	}
	ntab, err := discover.ListenUDP(conn, cfg)
	if err != nil {
		return err
	}
	srv.ntab = ntab
	srv.loopWG.Add(1)
	go func() {
		timeout := time.NewTicker(10 * time.Minute)
		defer srv.loopWG.Done()
		defer timeout.Stop()
		defer srv.ntab.Close()
		for {
			select {
			case <-timeout.C:
				ntab.LookupRandom()
			case <-srv.quit:
				return
			}
		}
	}()
	return nil
}

// Start starts running the server.
// Servers can not be re-used after stopping.
func (srv *Server) Start() (err error) {
	srv.lock.Lock()
	defer srv.lock.Unlock()
	if srv.running {
		return errors.New("server already running")
	}
	srv.running = true
	srv.log = srv.Config.Logger
	if srv.log == nil {
		srv.log = log.New()
	}
	srv.log.Info("Starting P2P networking", "NetID", srv.magicNetID(), "UsrNetID", srv.NetworkID)

	// static fields
	if srv.PrivateKey == nil {
		return fmt.Errorf("Server.PrivateKey must be set to a non-nil key")
	}
	if srv.newTransport == nil {
		srv.newTransport = newRLPX
	}
	if srv.Dialer == nil {
		srv.Dialer = TCPDialer{&net.Dialer{Timeout: defaultDialTimeout}}
	}
	srv.quit = make(chan struct{})
	srv.addpeer = make(chan *conn)
	srv.delpeer = make(chan peerDrop)
	srv.posthandshake = make(chan *conn)
	srv.addstatic = make(chan *enode.Node)
	srv.removestatic = make(chan *enode.Node)
	srv.addtrusted = make(chan *enode.Node)
	srv.removetrusted = make(chan *enode.Node)
	srv.peerOp = make(chan peerOpFunc)
	srv.peerOpDone = make(chan struct{})

	srv.addBad = make(chan *badNode)
	srv.removeBad = make(chan *enode.Node)
	srv.badNodeOp = make(chan badOpFunc)
	srv.badNodeOpDone = make(chan struct{})

	if !srv.NoDiscovery {
		addr, err := net.ResolveUDPAddr("udp", srv.ListenAddr)
		if err != nil {
			return err
		}
		conn, err := net.ListenUDP("udp", addr)
		if err != nil {
			return err
		}
		cfg := discover.Config{
			TCPPort:      conn.LocalAddr().(*net.UDPAddr).Port,
			MagicNetID:   srv.magicNetID(),
			PrivateKey:   srv.PrivateKey,
			AnnounceAddr: conn.LocalAddr().(*net.UDPAddr),
			NodeDBPath:   srv.NodeDatabase,
			NetRestrict:  srv.NetRestrict,
			Bootnodes:    srv.BootstrapNodes,
			Unhandled:    nil,
		}
		ntab, err := discover.ListenUDP(conn, cfg)
		if err != nil {
			return err
		}
		srv.ntab = ntab
	}

	dynPeers := srv.maxDialedConns()
	dialer := newDialState(srv.StaticNodes, srv.BootstrapNodes, srv.ntab, dynPeers, srv.NetRestrict)

	// handshake
	pubkey := crypto.FromECDSAPub(&srv.PrivateKey.PublicKey)
	srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: pubkey[1:]}
	for _, p := range srv.Protocols {
		srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
	}
	// listen/dial
	if srv.ListenAddr != "" {
		if err := srv.startListening(); err != nil {
			return err
		}
	}
	if srv.NoDial && srv.ListenAddr == "" {
		srv.log.Warn("P2P server will be useless, neither dialing nor listening")
	}

	srv.loopWG.Add(1)
	go srv.run(dialer)
	return nil
}

func (srv *Server) startListening() error {
	// Launch the TCP listener.
	listener, err := net.Listen("tcp", srv.ListenAddr)
	if err != nil {
		return err
	}
	laddr := listener.Addr().(*net.TCPAddr)
	srv.ListenAddr = laddr.String()
	srv.listener = listener
	srv.loopWG.Add(1)
	go srv.listenLoop()
	return nil
}

type dialer interface {
	newTasks(running int, peers map[enode.ID]*Peer, now time.Time) []task
	taskDone(task, time.Time)
	addStatic(*enode.Node)
	removeStatic(*enode.Node)
}

func (srv *Server) run(dialstate dialer) {
	defer srv.loopWG.Done()
	var (
		peers        = make(map[enode.ID]*Peer)
		badNodes     = make(map[enode.ID]*badNode)
		inboundCount = 0
		trusted      = make(map[enode.ID]bool, len(srv.TrustedNodes))
		taskdone     = make(chan task, maxActiveDialTasks)
		runningTasks []task
		queuedTasks  []task // tasks that can't run yet
	)
	// Put trusted nodes into a map to speed up checks.
	// Trusted peers are loaded on startup or added via AddTrustedPeer RPC.
	for _, n := range srv.TrustedNodes {
		trusted[n.ID()] = true
	}

	// removes t from runningTasks
	delTask := func(t task) {
		for i := range runningTasks {
			if runningTasks[i] == t {
				runningTasks = append(runningTasks[:i], runningTasks[i+1:]...)
				break
			}
		}
	}
	// starts until max number of active tasks is satisfied
	startTasks := func(ts []task) (rest []task) {
		i := 0
		for ; len(runningTasks) < maxActiveDialTasks && i < len(ts); i++ {
			t := ts[i]
			srv.log.Trace("New dial task", "task", t)
			go func() { t.Do(srv); taskdone <- t }()
			runningTasks = append(runningTasks, t)
		}
		return ts[i:]
	}
	scheduleTasks := func() {
		// Start from queue first.
		queuedTasks = append(queuedTasks[:0], startTasks(queuedTasks)...)
		// Query dialer for new tasks and start as many as possible now.
		if len(runningTasks) < maxActiveDialTasks {
			nt := dialstate.newTasks(len(runningTasks)+len(queuedTasks), peers, time.Now())
			queuedTasks = append(queuedTasks, startTasks(nt)...)
		}
	}

	isBadNode := func(id enode.ID) bool {
		n := badNodes[id]
		if n == nil {
			return false
		}
		if n.endtime > 0 && n.endtime < time.Now().Unix() {
			delete(badNodes, id)
			return false
		}
		return true
	}

running:
	for {
		scheduleTasks()

		select {
		case <-srv.quit:
			// The server was stopped. Run the cleanup logic.
			break running
		case n := <-srv.addstatic:
			// This channel is used by AddPeer to add to the
			// ephemeral static peer list. Add it to the dialer,
			// it will keep the node connected.
			srv.log.Info("Adding static node", "node", n)
			dialstate.addStatic(n)
		case n := <-srv.removestatic:
			// This channel is used by RemovePeer to send a
			// disconnect request to a peer and begin the
			// stop keeping the node connected.
			srv.log.Info("Removing static node", "node", n)
			dialstate.removeStatic(n)
			if p, ok := peers[n.ID()]; ok {
				p.Disconnect(DiscRequested)
			}
		case n := <-srv.addtrusted:
			// This channel is used by AddTrustedPeer to add an enode
			// to the trusted node set.
			srv.log.Info("Adding trusted node", "node", n)
			trusted[n.ID()] = true
			// Mark any already-connected peer as trusted
			if p, ok := peers[n.ID()]; ok {
				p.rw.set(trustedConn, true)
			}
		case n := <-srv.removetrusted:
			// This channel is used by RemoveTrustedPeer to remove an enode
			// from the trusted node set.
			srv.log.Info("Removing trusted node", "node", n)
			delete(trusted, n.ID())
			// Unmark any already-connected peer as trusted
			if p, ok := peers[n.ID()]; ok {
				p.rw.set(trustedConn, false)
				if isBadNode(n.ID()) {
					p.rw.set(badNodeConn, true)
					p.Disconnect(DiscBadNode)
				} else {
					p.rw.set(badNodeConn, false)
				}
			}
		case op := <-srv.peerOp:
			// This channel is used by Peers and PeerCount.
			op(peers)
			srv.peerOpDone <- struct{}{}
		case t := <-taskdone:
			// A task got done. Tell dialstate about it so it
			// can update its state and remove it from the active
			// tasks list.
			srv.log.Trace("Dial task done", "task", t)
			dialstate.taskDone(t, time.Now())
			delTask(t)
		case c := <-srv.posthandshake:
			// A connection has passed the encryption handshake so
			// the remote identity is known (but hasn't been verified yet).
			if trusted[c.node.ID()] {
				// Ensure that the trusted flag is set before checking against MaxPeers.
				c.flags |= trustedConn
			}
			if isBadNode(c.node.ID()) {
				c.flags |= badNodeConn
			}
			// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
			select {
			case c.cont <- srv.encHandshakeChecks(peers, inboundCount, c):
			case <-srv.quit:
				break running
			}
		case n := <-srv.addBad:
			badNodes[n.node.ID()] = n
			srv.log.Info("Add bad node", "node", n.node, "endtime", n.endtime)
			if p, ok := peers[n.node.ID()]; ok {
				if isBadNode(n.node.ID()) {
					p.rw.set(badNodeConn, true)
					if !p.rw.is(trustedConn) {
						p.Disconnect(DiscBadNode)
					}
				}
			}
		case n := <-srv.removeBad:
			delete(badNodes, n.ID())
			if p, ok := peers[n.ID()]; ok {
				p.rw.set(badNodeConn, false)
			}
		case op := <-srv.badNodeOp:
			op(badNodes)
			srv.badNodeOpDone <- struct{}{}
		case c := <-srv.addpeer:
			// At this point the connection is past the protocol handshake.
			// Its capabilities are known and the remote identity is verified.
			err := srv.protoHandshakeChecks(peers, inboundCount, c)
			if err == nil {
				// The handshakes are done and it passed all checks.
				p := newPeer(c, srv.Protocols)
				// If message events are enabled, pass the peerFeed
				// to the peer
				if srv.EnableMsgEvents {
					p.events = &srv.peerFeed
				}
				name := truncateName(c.name)
				srv.log.Info("Adding p2p peer", "name", name, "addr", c.fd.RemoteAddr(), "peers", len(peers)+1)
				go srv.runPeer(p)
				peers[c.node.ID()] = p
				if p.Inbound() {
					inboundCount++
				}
			}
			// The dialer logic relies on the assumption that
			// dial tasks complete after the peer has been added or
			// discarded. Unblock the task last.
			select {
			case c.cont <- err:
			case <-srv.quit:
				break running
			}
		case pd := <-srv.delpeer:
			// A peer disconnected.
			d := common.PrettyDuration(common.Now() - pd.created)
			pd.log.Info("Removing p2p peer", "duration", d, "peers", len(peers)-1, "req", pd.requested, "err", pd.err)
			delete(peers, pd.ID())
			if pd.Inbound() {
				inboundCount--
			}
		}
	}

	srv.log.Trace("P2P networking is spinning down")

	// Terminate discovery. If there is a running lookup it will terminate soon.
	if srv.ntab != nil {
		srv.ntab.Close()
	}
	/*
		if srv.DiscV5 != nil {
			srv.DiscV5.Close()
		}
	*/
	// Disconnect all peers.
	for _, p := range peers {
		p.Disconnect(DiscQuitting)
	}
	// Wait for peers to shut down. Pending connections and tasks are
	// not handled here and will terminate soon-ish because srv.quit
	// is closed.
	for len(peers) > 0 {
		p := <-srv.delpeer
		p.log.Trace("<-delpeer (spindown)", "remainingTasks", len(runningTasks))
		delete(peers, p.ID())
	}
}

func (srv *Server) protoHandshakeChecks(peers map[enode.ID]*Peer, inboundCount int, c *conn) error {
	// Drop connections with no matching protocols.
	if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 {
		return DiscUselessPeer
	}
	// Repeat the encryption handshake checks because the
	// peer set might have changed between the handshakes.
	return srv.encHandshakeChecks(peers, inboundCount, c)
}

func (srv *Server) encHandshakeChecks(peers map[enode.ID]*Peer, inboundCount int, c *conn) error {
	switch {
	case !c.is(trustedConn) && c.is(badNodeConn):
		return DiscBadNode
	case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers:
		return DiscTooManyPeers
	case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns():
		return DiscTooManyPeers
	case peers[c.node.ID()] != nil:
		return DiscAlreadyConnected
	case c.node.ID() == srv.Self().ID():
		return DiscSelf
	default:
		return nil
	}
}

func (srv *Server) maxInboundConns() int {
	return srv.MaxPeers - srv.maxDialedConns()
}
func (srv *Server) maxDialedConns() int {
	if srv.NoDiscovery || srv.NoDial {
		return 0
	}
	r := srv.DialRatio
	if r == 0 {
		r = defaultDialRatio
	}
	return srv.MaxPeers / r
}

type tempError interface {
	Temporary() bool
}

// listenLoop runs in its own goroutine and accepts
// inbound connections.
func (srv *Server) listenLoop() {
	defer srv.loopWG.Done()
	srv.log.Info("RLPx listener up", "self", srv.Self())

	tokens := defaultMaxPendingPeers
	if srv.MaxPendingPeers > 0 {
		tokens = srv.MaxPendingPeers
	}
	slots := make(chan struct{}, tokens)
	for i := 0; i < tokens; i++ {
		slots <- struct{}{}
	}

	for {
		// Wait for a handshake slot before accepting.
		<-slots

		var (
			fd  net.Conn
			err error
		)
		for {
			fd, err = srv.listener.Accept()
			if tempErr, ok := err.(tempError); ok && tempErr.Temporary() {
				srv.log.Debug("Temporary read error", "err", err)
				continue
			} else if err != nil {
				srv.log.Debug("Read error", "err", err)
				return
			}
			break
		}

		// Reject connections that do not match NetRestrict.
		if srv.NetRestrict != nil {
			if tcp, ok := fd.RemoteAddr().(*net.TCPAddr); ok && !srv.NetRestrict.Contains(tcp.IP) {
				srv.log.Debug("Rejected conn (not whitelisted in NetRestrict)", "addr", fd.RemoteAddr())
				fd.Close()
				slots <- struct{}{}
				continue
			}
		}

		fd = newMeteredConn(fd, true)
		srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr())
		go func() {
			srv.SetupConn(fd, inboundConn, nil)
			slots <- struct{}{}
		}()
	}
}

// SetupConn runs the handshakes and attempts to add the connection
// as a peer. It returns when the connection has been added as a peer
// or the handshakes have failed.
func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node) error {
	self := srv.Self()
	if self == nil {
		return errors.New("shutdown")
	}
	c := &conn{fd: fd, transport: srv.newTransport(fd, srv.magicNetID()), flags: flags, cont: make(chan error)}
	err := srv.setupConn(c, flags, dialDest)
	if err != nil {
		c.close(err)
		srv.log.Trace("Setting up connection failed", "addr", fd.RemoteAddr(), "err", err)
	}
	return err
}

func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) error {
	// Prevent leftover pending conns from entering the handshake.
	srv.lock.Lock()
	running := srv.running
	srv.lock.Unlock()
	if !running {
		return errServerStopped
	}
	// If dialing, figure out the remote public key.
	var dialPubkey *ecdsa.PublicKey
	if dialDest != nil {
		dialPubkey = new(ecdsa.PublicKey)
		if err := dialDest.Load((*enode.Secp256k1)(dialPubkey)); err != nil {
			return fmt.Errorf("dial destination doesn't have a secp256k1 public key")
		}
	}
	// Run the encryption handshake.
	remotePubkey, err := c.doEncHandshake(srv.PrivateKey, dialPubkey)
	if err != nil {
		srv.log.Trace("Failed RLPx handshake", "addr", c.fd.RemoteAddr(), "conn", c.flags, "err", err)
		return err
	}
	if dialDest != nil {
		// For dialed connections, check that the remote public key matches.
		if dialPubkey.X.Cmp(remotePubkey.X) != 0 || dialPubkey.Y.Cmp(remotePubkey.Y) != 0 {
			return DiscUnexpectedIdentity
		}
		c.node = dialDest
	} else {
		c.node = nodeFromConn(remotePubkey, c.fd)
	}
	clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags)
	err = srv.checkpoint(c, srv.posthandshake)
	if err != nil {
		clog.Trace("Rejected peer before protocol handshake", "err", err)
		return err
	}
	// Run the protocol handshake
	phs, err := c.doProtoHandshake(srv.ourHandshake)
	if err != nil {
		clog.Trace("Failed proto handshake", "err", err)
		return err
	}
	if id := c.node.ID(); !bytes.Equal(crypto.Keccak256(phs.ID), id[:]) {
		clog.Trace("Wrong devp2p handshake identity", "phsid", fmt.Sprintf("%x", phs.ID))
		return DiscUnexpectedIdentity
	}
	c.caps, c.name = phs.Caps, phs.Name
	err = srv.checkpoint(c, srv.addpeer)
	if err != nil {
		clog.Trace("Rejected peer", "err", err)
		return err
	}
	// If the checks completed successfully, runPeer has now been
	// launched by run.
	clog.Trace("connection set up", "inbound", dialDest == nil)
	return nil
}

func nodeFromConn(pubkey *ecdsa.PublicKey, conn net.Conn) *enode.Node {
	var ip net.IP
	var port int
	if tcp, ok := conn.RemoteAddr().(*net.TCPAddr); ok {
		ip = tcp.IP
		port = tcp.Port
	}
	return enode.NewV4(pubkey, ip, port, port)
}

func truncateName(s string) string {
	if len(s) > 20 {
		return s[:20] + "..."
	}
	return s
}

// checkpoint sends the conn to run, which performs the
// post-handshake checks for the stage (posthandshake, addpeer).
func (srv *Server) checkpoint(c *conn, stage chan<- *conn) error {
	select {
	case stage <- c:
	case <-srv.quit:
		return errServerStopped
	}
	select {
	case err := <-c.cont:
		return err
	case <-srv.quit:
		return errServerStopped
	}
}

// runPeer runs in its own goroutine for each peer.
// it waits until the Peer logic returns and removes
// the peer.
func (srv *Server) runPeer(p *Peer) {
	if srv.newPeerHook != nil {
		srv.newPeerHook(p)
	}

	// broadcast peer add
	srv.peerFeed.Send(&PeerEvent{
		Type: PeerEventTypeAdd,
		Peer: p.ID(),
	})

	// run the protocol
	remoteRequested, err := p.run()

	// broadcast peer drop
	srv.peerFeed.Send(&PeerEvent{
		Type:  PeerEventTypeDrop,
		Peer:  p.ID(),
		Error: err.Error(),
	})

	// Note: run waits for existing peers to be sent on srv.delpeer
	// before returning, so this send should not select on srv.quit.
	srv.delpeer <- peerDrop{p, err, remoteRequested}
}

// NodeInfo represents a short summary of the information known about the host.
type NodeInfo struct {
	ID    string `json:"id"`    // Unique node identifier (also the encryption key)
	Name  string `json:"name"`  // Name of the node, including client type, version, OS, custom data
	Enode string `json:"enode"` // Enode URL for adding this peer from remote peers
	IP    string `json:"ip"`    // IP address of the node
	Ports struct {
		Discovery int `json:"discovery"` // UDP listening port for discovery protocol
		Listener  int `json:"listener"`  // TCP listening port for RLPx
	} `json:"ports"`
	ListenAddr string                 `json:"listenAddr"`
	Protocols  map[string]interface{} `json:"protocols"`
}

// NodeInfo gathers and returns a collection of metadata known about the host.
func (srv *Server) NodeInfo() *NodeInfo {
	node := srv.Self()

	// Gather and assemble the generic node infos
	info := &NodeInfo{
		Name:       srv.Name,
		Enode:      node.String(),
		ID:         node.ID().String(),
		IP:         node.IP().String(),
		ListenAddr: srv.ListenAddr,
		Protocols:  make(map[string]interface{}),
	}
	info.Ports.Discovery = node.UDP()
	info.Ports.Listener = node.TCP()

	// Gather all the running protocol infos (only once per protocol type)
	for _, proto := range srv.Protocols {
		if _, ok := info.Protocols[proto.Name]; !ok {
			nodeInfo := interface{}("unknown")
			if query := proto.NodeInfo; query != nil {
				nodeInfo = proto.NodeInfo()
			}
			info.Protocols[proto.Name] = nodeInfo
		}
	}
	return info
}

// PeersInfo returns an array of metadata objects describing connected peers.
func (srv *Server) PeersInfo() []*PeerInfo {
	// Gather all the generic and sub-protocol specific infos
	infos := make([]*PeerInfo, 0, srv.PeerCount())
	for _, peer := range srv.Peers() {
		if peer != nil {
			infos = append(infos, peer.Info())
		}
	}
	// Sort the result array alphabetically by node identifier
	for i := 0; i < len(infos); i++ {
		for j := i + 1; j < len(infos); j++ {
			if infos[i].ID > infos[j].ID {
				infos[i], infos[j] = infos[j], infos[i]
			}
		}
	}
	return infos
}


text:
#ifndef CAP_TEST_H
#define	CAP_TEST_H

#include <err.h>

/*
 * Define a file required by a test. The test can't complete without the file,
 * so if we don't have it, just die.
 */
#define	REQUIRE(fd)	do {						\
	if ((fd) < 0)							\
		err(-1, "%s:%d: Missing required file '%s'",		\
			__FILE__, __LINE__, #fd);			\
} while (0)

/* Whether a test passed or failed. */
#define	PASSED	0
#define	FAILED	1

/* A test has failed; print a message and clear the 'success' flag. */
#define	FAIL(...)	do {						\
	warn(__VA_ARGS__);						\
	success = FAILED;						\
} while (0)

/* As above, but do not print the errno message. */
#define	FAILX(...)	do {						\
	warnx(__VA_ARGS__);						\
	success = FAILED;						\
} while (0)

/* Like an assertion, but don't kill the test, just fail and keep going. */
#define	CHECK(condition) do {						\
	if (!(condition))						\
		FAILX("%s:%d: Assertion '%s' failed",			\
		    __func__, __LINE__, #condition);			\
} while (0)

/* Make sure that a system call's return value is >= 0. */
#define	CHECK_SYSCALL_SUCCEEDS(syscall, ...) do {			\
	if (syscall(__VA_ARGS__) < 0)					\
		FAIL("%s() at line %d: %s failed",			\
		    __func__, __LINE__, #syscall);			\
} while (0)

/* Make sure that a system call fails with the correct errno. */
#define	CHECK_SYSCALL_FAILS(expected_errno, syscall, ...)	do {	\
	if (syscall(__VA_ARGS__) < 0) {					\
		if (errno != expected_errno)				\
			FAIL("%s() at line %d: %s",			\
			    __func__, __LINE__, #syscall);		\
	} else {							\
		FAILX("%s() at line %d: %s succeeded; it should've failed", \
		    __func__, __LINE__, #syscall);			\
	}								\
} while (0)

/* Make sure that a system call fails, but not with a particular errno. */
#define	CHECK_SYSCALL_FAILS_BUT_NOT_WITH(bad_errno, syscall, ...)	do { \
	if (syscall(__VA_ARGS__) < 0) {					\
		if (errno == bad_errno)					\
			FAIL("%s() at line %d: %s",			\
			    __func__, __LINE__, #syscall);		\
	} else {							\
		FAILX("%s() at line %d: %s succeeded; it should've failed", \
		    __func__, __LINE__, #syscall);			\
	}								\
} while (0)

/* A system call should fail with ECAPMODE. */
#define	CHECK_CAPMODE(...) \
	CHECK_SYSCALL_FAILS(ECAPMODE, __VA_ARGS__)

/* A system call should fail, but not with ECAPMODE. */
#define	CHECK_NOT_CAPMODE(...) \
	CHECK_SYSCALL_FAILS_BUT_NOT_WITH(ECAPMODE, __VA_ARGS__)

/* A system call should fail with ENOTCAPABLE. */
#define	CHECK_NOTCAPABLE(...) \
	CHECK_SYSCALL_FAILS(ENOTCAPABLE, __VA_ARGS__)

/* Ensure that 'rights' are a subset of 'max'. */
#define	CHECK_RIGHTS(rights, max)	do {				\
	if ((success == PASSED) && (rights != max))			\
		FAILX("Rights of opened file (%jx) > maximum (%jx)",	\
		    (cap_rights_t) rights, (cap_rights_t) max);		\
} while (0)

/* Create a capability from a file descriptor, make sure it succeeds. */
#define	MAKE_CAPABILITY(to, from, rights)	do {			\
	cap_rights_t _rights;						\
	REQUIRE(to = cap_new(from, rights));				\
	CHECK_SYSCALL_SUCCEEDS(cap_getrights, to, &_rights);		\
	if ((success == PASSED) && (_rights != (rights)))		\
		FAILX("New capability's rights (%jx) != %jx",		\
		    _rights, (cap_rights_t) (rights));			\
} while (0)

/*
 * A top-level test should take no arguments and return an integer value,
 * either PASSED or FAILED.
 *
 * Errors such as SIGSEGV will be caught and interpreted as FAILED.
 */
typedef int	(*test_function)(void);

/* Information about a test. */
struct test {
	char		*t_name;
	test_function	 t_run;
	int		 t_result;
};

/*
 * Run a test in a child process so that cap_enter(2) doesn't mess up
 * subsequent tests.
 */
int	execute(int id, struct test*);

int	test_capmode(void);
int	test_capabilities(void);
int	test_fcntl(void);
int	test_pdfork(void);
int	test_pdkill(void);
int	test_pdwait(void);
int	test_relative(void);
int	test_sysctl(void);

#endif /* CAP_TEST_H */


text:
<?php
namespace Application\Service;

interface AuthenticationServiceInterface
{
    public function login($identifier, $password);

    public function logout();
}


text:
package org.tiwonk.util.client.ui.impl;

import org.tiwonk.util.client.ui.StatusMessageView;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

public class StatusMessageImpl extends Composite implements StatusMessageView {

  private static final int DISPLAY_DURATION = 5000;
  private static final int FADE_DURATION = 3000;
  private static final int FADE_RATE = 75; // ms per opacity setting
  private static final double DELTA_OPACITY = ((double)FADE_RATE)/FADE_DURATION;

  private static StatusMessageImplUiBinder uiBinder = GWT
      .create(StatusMessageImplUiBinder.class);

  interface StatusMessageImplUiBinder extends
      UiBinder<Widget, StatusMessageImpl> {
  }

  @UiField HTMLPanel panel;
  @UiField Label label;

  private Timer timer;

  public StatusMessageImpl() {
    initWidget(uiBinder.createAndBindUi(this));
    panel.getElement().getStyle().setDisplay(Display.NONE);
  }

  @Override
  public void show(String message) {
    label.setText(message);
    label.getElement().getStyle().setOpacity(1);
    panel.getElement().getStyle().setDisplay(Display.BLOCK);
    if (timer != null) {
      timer.cancel();
    }
    timer = new DissolveTimer();
    timer.schedule(DISPLAY_DURATION);

  }

  @Override
  public void hide() {
    if (timer != null) {
      timer.cancel();
    }

    panel.getElement().getStyle().setDisplay(Display.NONE);

  }

  class DissolveTimer extends Timer {
    double opacity = 1;

    @Override
    public void run() {
      opacity -= DELTA_OPACITY;
      if (opacity <= 0) {
        hide();
      } else {
        label.getElement().getStyle().setOpacity(opacity);
        schedule(FADE_RATE);
      }

    }

  }

  @Override
  public void ensureInjected() {
    if (getElement().getParentElement() == null) {
      Document.get().getBody().appendChild(getElement());
    }

  }

}


text:
package com.socrata.datacoordinator.service.collocation

import java.util.UUID

import com.rojoma.json.v3.codec.JsonEncode
import com.rojoma.json.v3.util._
import com.socrata.datacoordinator.common.collocation.{CollocationLock, CollocationLockError, CollocationLockTimeout}
import com.socrata.datacoordinator.id.DatasetInternalName
import com.socrata.datacoordinator.resources.collocation.{CollocatedDatasetsResult, DatasetNotInStore, SecondaryMoveJobRequest, StoreNotAcceptingDatasets}
import com.socrata.datacoordinator.service.collocation.secondary.stores.SecondaryStoreSelector
import org.joda.time.DateTime

import scala.annotation.tailrec

@JsonKeyStrategy(Strategy.Underscore)
case class CollocationRequest(collocations: Seq[(DatasetInternalName, DatasetInternalName)],
                              limits: CollocationRequest.CostLimits)

object CollocationRequest {
  type CostLimits = Cost

  implicit val costLimitsDecode = AutomaticJsonDecodeBuilder[CostLimits]
  implicit val decode = AutomaticJsonDecodeBuilder[CollocationRequest]
}

case class CollocationResult(id: Option[UUID], status: Status, message: String, cost: Cost, moves: Seq[Move]) {

  def +(that: CollocationResult): CollocationResult = {
    CollocationResult(
      id = this.id,
      status = Status.combine(this.status, that.status),
      cost = this.cost + that.cost,
      moves = this.moves ++ that.moves
    )
  }
}

object CollocationResult {
  implicit val encode = AutomaticJsonEncodeBuilder[CollocationResult]

  def apply(id: Option[UUID], status: Status, cost: Cost, moves: Seq[Move]): CollocationResult = {
    CollocationResult(id, status, status.message, cost, moves)
  }

  def apply(id: UUID): CollocationResult = CollocationResult(
    id = Some(id),
    status = Completed,
    cost = Cost.Zero,
    moves = Seq.empty
  )

  def canonicalEmpty: CollocationResult = CollocationResult(
    id = None,
    status = Completed,
    cost = Cost.Zero,
    moves = Seq.empty
  )
}

trait Collocator {
  def collocatedDatasets(datasets: Set[DatasetInternalName]): Either[RequestError, CollocatedDatasetsResult]
  def dropDataset(dataset: DatasetInternalName): Option[ErrorResult]
  def explainCollocation(storeGroup: String, request: CollocationRequest): Either[ErrorResult, CollocationResult]
  def executeCollocation(jobId: UUID, storeGroup: String, request: CollocationRequest): (Either[ErrorResult, CollocationResult], Seq[(Move, Boolean)])
  def commitCollocation(jobId: UUID, request: CollocationRequest): Unit
  def lockCollocation(): Unit
  def unlockCollocation(): Unit
  def rollbackCollocation(jobId: UUID, moves: Seq[(Move, Boolean)]): Option[ErrorResult]
  def secondariesOfDataset(dataset: DatasetInternalName): Set[String]
}

trait CollocatorProvider {
  val collocator: Collocator
}

class CoordinatedCollocator(collocationGroup: Set[String],
                            coordinator: Coordinator,
                            metric: Metric,
                            addCollocations: (UUID, Seq[(DatasetInternalName, DatasetInternalName)]) => Unit,
                            lock: CollocationLock,
                            lockTimeoutMillis: Long)(implicit costOrdering: Ordering[Cost]) extends Collocator {

  private val log = org.slf4j.LoggerFactory.getLogger(classOf[Collocator])

  override def collocatedDatasets(datasets: Set[DatasetInternalName]): Either[RequestError, CollocatedDatasetsResult] = {
    try {
      @tailrec
      def search(current: Set[DatasetInternalName], seen: Set[DatasetInternalName]): Set[DatasetInternalName] = {
        val toExplore = collocationGroup.flatMap { instance =>
          coordinator.collocatedDatasetsOnInstance(instance, current).fold(throw _, _.datasets)
        } -- seen

        if (toExplore.nonEmpty) search(toExplore, seen ++ toExplore)
        else seen
      }

      Right(CollocatedDatasetsResult(search(current = datasets, seen = datasets)))
    } catch {
      case error: RequestError => Left(error)
    }
  }

  def secondariesOfDataset(dataset: DatasetInternalName): Set[String] =
    coordinator.secondariesOfDataset(dataset).fold(throw _, _.getOrElse(throw DatasetNotFound(dataset)).secondaries.keySet)

  protected def stores(storeGroup: String, dataset: DatasetInternalName, instances: Set[String], replicationFactor: Int): Set[String] = {
    // we want to get jobs _before_ current stores
    val jobs = coordinator.secondaryMoveJobs(storeGroup, dataset).fold(throw _, identity)
    val currentStores = coordinator.secondariesOfDataset(dataset).fold(throw _, _.getOrElse(throw DatasetNotFound(dataset)).secondaries.keySet)

    // apply moves to the current stores in the order they will execute in
    val futureStores = jobs.moves.sorted.foldLeft(currentStores) { (stores, move) =>
      stores - move.fromStoreId + move.toStoreId
    }

    val storesInGroup = instances.intersect(futureStores)
    if (replicationFactor > storesInGroup.size) {
      log.error("Dataset {}'s current replication factor {} is smaller than the expected replication factor {} for the group {}",
        dataset.toString, storesInGroup.size.toString, replicationFactor.toString, storeGroup)
      throw new Exception("Dataset replicated to stores in an unexpected state!")
    }

    storesInGroup
  }

  override def dropDataset(dataset: DatasetInternalName): Option[ErrorResult] = {
    log.info("Dropping dataset {} from collocation manifests", dataset)
    collocationGroup.flatMap { instance =>
      coordinator.dropCollocationsOnInstance(instance, dataset)
    }.headOption
  }

  protected def movesFor(group: Set[DatasetInternalName],
                         storesFrom: Set[String],
                         storesTo: Set[String],
                         costMap: Map[DatasetInternalName, Cost]): Seq[Move] = {
    if (storesFrom.size != storesTo.size) {
      if ((storesFrom -- storesTo).size != storesTo.size) {
        log.error("storesFrom.size != storesTo.size, something is wrong internally!")
        throw new IllegalArgumentException("storesFrom and storesTo should be the same size!")
      }
    }

    for {
      (storeFrom, storeTo) <- scala.util.Random.shuffle((storesFrom -- storesTo).toSeq).zip((storesTo -- storesFrom).toSeq)
      dataset <- group
    } yield {
      Move(dataset, storeFrom, storeTo, costMap(dataset))
    }
  }

  override def explainCollocation(storeGroup: String,
                                  request: CollocationRequest): Either[ErrorResult, CollocationResult] = {
    log.info("Explaining collocation on secondary store group {}: {}", storeGroup:Any, request)
    try {
      coordinator.secondaryGroupConfigs.get(storeGroup) match {
        case Some(groupConfig) =>
          val instances = groupConfig.instances.keySet
          val replicationFactor = groupConfig.numReplicas
          log.info("Instances in store group: {} (repfactor {})", instances, replicationFactor)

          request match {
            case CollocationRequest(collocations, _) if collocations.isEmpty => Right(CollocationResult.canonicalEmpty)
            case CollocationRequest(collocations, costLimits) =>
              val collocationEdges = collocations.map { collocation =>
                Set(collocation._1, collocation._2)
              }.toSet

              val inputDatasets = collocationEdges.flatten // example: Set(alpha.1, alpha.2)

              // we will 404 if we get a 404 projected stores for one of the input datasets
              // example: Set(alpha.1 -> Set(pg1, pg2), alpha.2 -> Set(pg3, pg4))
              // It needs to look up data from secondary_manifest and secondary_move_jobs to consider future location.
              // TODO: Make sure we are cleaning up secondary_move_jobs table
              val datasetStoresMap = inputDatasets.map { dataset =>
                if (collocationGroup(dataset.instance)) {
                  (dataset, stores(storeGroup, dataset, instances, replicationFactor))
                } else {
                  log.warn("Unable to find dataset {} since it has an unrecognized instance name!", dataset)
                  return Left(DatasetNotFound(dataset))
                }
              }.toMap // datasetStoreMap: key = dataset, values = set of secondary_instances the dataset lives
              log.info("Dataset stores map: {}", JsonEncode.toJValue(datasetStoresMap))

              // Calculation of this requires recursive database sql calls.
              // TODO: Consider to use recursive sql to speed up this.
              val datasetGroupMap = inputDatasets.map { dataset =>
                val collocateDatasetsResult: Set[DatasetInternalName] =
                  logTime(s"collocatedDatasets $dataset")(collocatedDatasets(Set(dataset)).fold(throw _, _.datasets))
                (dataset, collocateDatasetsResult)
              }.toMap // datasetGroupMap: key = dataset, value = set of all related datasets in the collocation_manifest table.
              log.info("Dataset group map: {}", JsonEncode.toJValue(datasetGroupMap))

              // cost of _all_ datasets in question, not just the input datasets
              val datasetCostMap = datasetGroupMap.flatMap(_._2).map { dataset =>
                logTime(s"metric.datasetMaxCost $dataset")((dataset, metric.datasetMaxCost(storeGroup, dataset).fold(throw _, identity)))
              }.toMap
              log.info("Dataset cost map: {}", JsonEncode.toJValue(datasetCostMap))

              // If there are 12 secondaries, 8s on each secondary will add up to 1.5min
              // Use parallel map to speed up store metric calculation within each group, i.e. alpha, beta.
              // To further increase parallelism, update the map inside metric.storeMetrics function.
              val storeMetricsMap = instances.par.map { instance =>
                logTime(s"metric.storeMetrics $instance")((instance, metric.storeMetrics(instance).fold(throw _, identity)))
              }.seq.toMap
              log.info("Store metrics map: {}", JsonEncode.toJValue(storeMetricsMap))

              def selectMoves(groups: Set[Set[DatasetInternalName]]): Set[Move] = {
                log.info("Selecting moves for groups: {}", JsonEncode.toJValue(groups))

                val indexedGroups = groups.zipWithIndex

                val groupCostMap = indexedGroups.map { case (group, index) =>
                  // cost of the group is the cost of moving each dataset (once)
                  val cost = group.map(datasetCostMap(_)).fold(Cost.Zero)(_ + _)

                  (index, cost)
                }.toMap

                log.info("Group cost map: {}", JsonEncode.toJValue(groupCostMap))

                val groupStoreMap = indexedGroups.map { case (group, index) =>
                  // a group should have at least on dataset in it
                  assert(group.nonEmpty)
                  // the projected stores for a group, should be the stores for one of its members
                  val representingDataset = group.intersect(inputDatasets).head

                  (index, datasetStoresMap(representingDataset))
                }.toMap

                log.info("Group store map: {}", JsonEncode.toJValue(groupStoreMap))

                val destinationStores = SecondaryStoreSelector(storeGroup, groupConfig, storeMetricsMap)
                  .destinationStores(groupStoreMap, groupCostMap)

                log.info("Destination stores: {}", JsonEncode.toJValue(destinationStores))

                // cost and moves to move each other group to the most expensive group
                val selectedMoves =
                  indexedGroups.flatMap { case (group, index) =>
                    movesFor(
                      group,
                      storesFrom = groupStoreMap(index),
                      storesTo = destinationStores,
                      datasetCostMap
                    )
                  }
                log.info("Selected moves: {}", JsonEncode.toJValue(selectedMoves))
                selectedMoves
              }

              // represents graph of collocated groups to be collocated
              val collocatedGroupsEdges = collocationEdges.map(_.map(datasetGroupMap)).filter(_.size == 2)

              val groupsToBeCollocated = logTime(s"nodesByComponent ${collocatedGroupsEdges.size}")(graph.nodesByComponent(collocatedGroupsEdges))
              val totalMoves = groupsToBeCollocated.flatMap { groups =>
                // from the filter condition above groups will have at least size 2
                assert(groups.size >= 2)
                logTime(s"""selectMoves ${groups.mkString(",")}""")(selectMoves(groups))
              }.toSeq

              val totalCost = Move.totalCost(totalMoves)
              if (totalCost == Cost.Zero) return Right(CollocationResult.canonicalEmpty)

              val totalStatus =
                if (totalCost.moves > costLimits.moves) {
                  log.warn(s"the number of moves exceed the limit ${costLimits.moves}, ${totalCost.moves}")
                  Rejected(s"the number of moves exceed the limit ${costLimits.moves}")
                } else if (totalCost.totalSizeBytes > costLimits.totalSizeBytes) {
                  log.warn(s"the total size in bytes exceeds the limit ${costLimits.totalSizeBytes}, ${totalCost.totalSizeBytes}")
                  Rejected(s"the total size in bytes exceeds the limit ${costLimits.totalSizeBytes}")
                } else if (totalCost.getMoveSizeMaxBytes > costLimits.getMoveSizeMaxBytes) {
                  log.warn(s"the max move size in bytes exceeds the limit ${costLimits.getMoveSizeMaxBytes}, ${totalCost.getMoveSizeMaxBytes}")
                  Rejected(s"the max move size in bytes exceeds the limit ${costLimits.getMoveSizeMaxBytes}")
                } else {
                  totalMoves.groupBy(_.storeIdTo).flatMap { case (storeId, moves) =>
                    val bytesToMove = Move.totalCost(moves).totalSizeBytes
                    val storeTotalBytes = storeMetricsMap(storeId).totalSizeBytes
                    val storeCapacityBytes = groupConfig.instances(storeId).storeCapacityMB * 1024 * 1024

                    if (storeTotalBytes + bytesToMove > storeCapacityBytes) {
                      log.warn(s"the moves exceed the capacity of store $storeId, $storeTotalBytes, $bytesToMove, $storeCapacityBytes")
                      Some(Rejected(s"the moves exceed the capacity of store $storeId"))
                    }
                    else None
                  }.headOption.getOrElse(Approved)
                }

              totalStatus match {
                case Rejected(reason) => log.info("Rejecting collocation request because {}", reason)
                case Approved => log.info("Approving collocation request for collocations: {}", request.collocations)
                case _ => throw new Exception("Unexpected collocation status in explain")
              }

              Right(CollocationResult(
                id = None,
                status = totalStatus,
                message = totalStatus.message,
                cost = totalCost, // here we return the full cost vector, we can obscure this further up the stack
                moves = totalMoves
              ))
          }
        case None => Left(StoreGroupNotFound(storeGroup))
      }
    } catch {
      case e: DatasetNotFound =>
        log.warn("No such dataset {}", e.internalName)
        Left(e)
      case e: RequestError =>
        log.error("Unexpected error making request during explain of collocation: {}", e)
        Left(e)
    }
  }

  override def executeCollocation(jobId: UUID,
                                  storeGroup: String,
                                  request: CollocationRequest): (Either[ErrorResult, CollocationResult], Seq[(Move, Boolean)]) = {
    log.info("Executing collocation on secondary store group {}", storeGroup)
    explainCollocation(storeGroup, request) match {
      case Right(CollocationResult(_, Approved, _, cost, moves)) =>

        log.info("Ensuring required move jobs exists: {}", moves)
        val moveResults = moves.map { move =>
          val request = SecondaryMoveJobRequest(jobId, move.storeIdFrom, move.storeIdTo)
          val result = try {
            coordinator.ensureSecondaryMoveJob(storeGroup, move.datasetInternalName, request) match {
              case Right(Right(datasetNewToStore)) => // successfully added job
                Right(datasetNewToStore)
              case Right(Left(StoreNotAcceptingDatasets)) =>
                log.error(s"Attempted to move dataset ${move.datasetInternalName} to store {} not accepting datasets!",
                  move.storeIdTo)
                Left(UnexpectedError("Attempted to move dataset to store not accepting new datasets during collocation!"))
              case Right(Left(DatasetNotInStore)) =>
                log.error(s"Attempted to move dataset ${move.datasetInternalName} from store {} that it is not in!",
                  move.storeIdFrom)
                Left(UnexpectedError("Attempted to move dataset from store that it is not in during collocation!"))
              case Left(error) => Left(error)
            }
          } catch {
            case error: Exception =>
              log.error("Unexpected exception while ensuring secondary move jobs", error)
              Left(UnexpectedError(error.getMessage))
          }

          (result, move)
        }

        val successfulMoves = moveResults.filter(_._1.isRight).map { case (result, move) => (move, result.right.get) }

        moveResults.find(_._1.isLeft) match {
          case Some(error) => return (Left(error._1.left.get), successfulMoves)
          case None =>
        }

        (Right(CollocationResult(
          id = Some(jobId),
          status = InProgress,
          message = InProgress.message,
          cost = cost, // here we return the full cost vector, we can obscure this further up the stack
          moves = moves
        )), successfulMoves)
      case other => (other, Seq.empty)
    }
  }

  override def commitCollocation(jobId: UUID, request: CollocationRequest): Unit = {
    // save the collocation relationships to the database after ensuring all required moves jobs exists
    // this way we only need to roll back jobs for our job id back if something goes wrong
    log.info("Adding collocation relationships to the manifest: {}", request.collocations)
    addCollocations(jobId, request.collocations)
  }

  override def lockCollocation(): Unit = {
    try {
      log.info("Attempting to acquire collocation lock")
      if (lock.acquire(lockTimeoutMillis)) {
        log.info("Acquired collocation lock")
      } else {
        log.warn("Timeout while waiting to acquire collocation lock")
        throw CollocationLockTimeout(lockTimeoutMillis)
      }
    } catch {
      case error: CollocationLockError =>
        log.error("Unexpected error while acquiring collocation lock ", error)
        throw error
    }
  }

  override def unlockCollocation(): Unit = {
    try {
      log.info("Releasing collocation lock")
      lock.release()
    } catch {
      case error: CollocationLockError =>
        log.error("Unexpected error while releasing collocation lock", error)
        throw error
    }
  }

  override def rollbackCollocation(jobId: UUID,
                                   moves: Seq[(Move, Boolean)]): Option[ErrorResult] = {
    val errors = moves.flatMap { case (move, dropFromStore) =>
      coordinator.rollbackSecondaryMoveJob(move.datasetInternalName.instance, jobId, move, dropFromStore)
    }

    errors.foreach { error =>
      log.error("Encountered error during rollback of collocation!!!", error)
    }

    errors.headOption
  }

  private def logTime[T](msg: String)(code: => T): T = {
    val start = DateTime.now()
    val result = code
    val duration = new org.joda.time.Duration(DateTime.now(), start)
    log.info(s"$msg took $duration")
    result
  }
}


text:
package exchangeGraph;

import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import graphUtil.CycleChainDecomposition;
import graphUtil.EdgeChain;
import graphUtil.EdgeCycle;
import graphUtil.GraphUtil;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

import kepLib.KepInstance;

import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;

public class AllHeavyEdgesConstructionHeuristic<V, E> {

  private KepInstance<V, E> kepInstance;
  private Map<E, Double> nonZeroEdgeValues;
  private Map<EdgeCycle<E>, Double> nonZeroCycleValues;
  private double minWeightToInclude;
  private CycleChainDecomposition<V, E> solution;
  private CycleChainDecomposition<V, E> abandoned;

  public AllHeavyEdgesConstructionHeuristic(KepInstance<V, E> kepInstance,
      Map<E, Double> nonZeroEdgeValues,
      Map<EdgeCycle<E>, Double> nonZeroCycleValues, double minWeightToInclude) {
    if (minWeightToInclude < .505) {
      throw new RuntimeException(
          "All heavy edges construction heuristic must use a minimum weight of at least "
              + ".505 for each edge to ensure that all nodes have in degree at most one "
              + "and out degree at most one.");
    }
    this.kepInstance = kepInstance;
    this.nonZeroCycleValues = nonZeroCycleValues;
    this.nonZeroEdgeValues = nonZeroEdgeValues;
    this.minWeightToInclude = minWeightToInclude;
    /*
     * (List<Double> edgeVals = Lists.newArrayList(Maps.filterEntries(
     * nonZeroEdgeValues, AllHeavyEdgesConstructionHeuristic.<E> atLeast(.1))
     * .values()); Collections.sort(edgeVals);
     * System.out.println(doublesToString(edgeVals));
     */
    double totalEdgeWeight = sum(nonZeroEdgeValues.values());
    Map<E, Double> filteredEdgeValues = Maps.filterEntries(nonZeroEdgeValues,
        edgeGreaterThanHalf);
    double totalEdgeWeightFiltered = sum(filteredEdgeValues.values());

    DirectedSparseMultigraph<V, E> onlyHeavyEdges = GraphUtil.makeSubgraph(
        kepInstance.getGraph(), Sets.newHashSet(filteredEdgeValues.keySet()));
    CycleChainDecomposition<V, E> heavyEdgesDecomp = new CycleChainDecomposition<V, E>(
        onlyHeavyEdges);
    // we now keep any chains that begin at a root node, and any cycles where
    // the LP had weight at least .5
    List<EdgeCycle<E>> edgeCyclesFeasible = Lists.newArrayList();
    List<EdgeChain<E>> edgeChainsFeasible = Lists.newArrayList();
    // we abandon any chains that begin at a node that is not the root node, or
    // any cycles found in heavyEdgesDecomp

    List<EdgeChain<E>> edgeChainsAbandoned = Lists.newArrayList();
    for (EdgeChain<E> edgeChain : heavyEdgesDecomp.getEdgeChains()) {
      if (kepInstance.getRootNodes().contains(
          onlyHeavyEdges.getSource(edgeChain.getEdgesInOrder().get(0)))) {
        edgeChainsFeasible.add(edgeChain);
      } else {
        edgeChainsAbandoned.add(edgeChain);
      }
    }
    List<EdgeCycle<E>> edgeCyclesAbandoned = Lists.newArrayList();
    for (EdgeCycle<E> cycle : heavyEdgesDecomp.getEdgeCycles()) {
      if (cycle.size() > kepInstance.getMaxCycleLength()) {
        edgeCyclesAbandoned.add(cycle);
      } else {
        System.out.println("max cycle length: "
            + kepInstance.getMaxCycleLength());
        System.out.println("adding a cycle of size: " + cycle.size());
        edgeCyclesFeasible.add(cycle);
      }
    }
    abandoned = new CycleChainDecomposition<V, E>(onlyHeavyEdges,
        edgeCyclesAbandoned, edgeChainsAbandoned);
    System.out.println("lp edge weight: "
        + shortFormat.format(totalEdgeWeight)
        + ", heavy edge weight: "
        + shortFormat.format(totalEdgeWeightFiltered)
        + ", chain edge weight: "
        + shortFormat.format((computeWeight(edgeChainsFeasible,
            filteredEdgeValues))) + ", chain edge count: "
        + edgeCount(edgeChainsFeasible));

    double totalCycleWeight = sum(nonZeroCycleValues.values());
    Map<EdgeCycle<E>, Double> filteredCycles = Maps.filterEntries(
        nonZeroCycleValues, edgeCycleGreaterThanHalf);
    double filteredCycleWeight = sum(filteredCycles.values());
    Set<EdgeCycle<E>> edgeCyclesInSolution = filteredCycles.keySet();
    System.out.println("lp cycle weight: "
        + shortFormat.format(totalCycleWeight) + ", select cycle weight: "
        + shortFormat.format(filteredCycleWeight) + ", cycle count: "
        + edgeCyclesInSolution.size());
    edgeCyclesFeasible.addAll(edgeCyclesInSolution);
    solution = new CycleChainDecomposition<V, E>(kepInstance.getGraph(),
        edgeCyclesFeasible, edgeChainsFeasible);
    /*
     * Set<E> selectedEdgesDeprecated = getSelectedEdges(filteredEdgeValues);
     * Set<E> allEdges = Sets.newHashSet(); for (EdgeChain<E> edgeChain :
     * edgeChainsFeasible) { allEdges.addAll(edgeChain.getEdges()); }
     * System.out.println("deprecated edges: " + selectedEdgesDeprecated.size()
     * + " standard edges: " + allEdges + ", sets are equal: " +
     * allEdges.equals(selectedEdgesDeprecated));
     */

  }

  public CycleChainDecomposition<V, E> getSolution() {
    return this.solution;
  }

  public CycleChainDecomposition<V, E> getAbandoned() {
    return this.abandoned;
  }

  public static <T> Predicate<Map.Entry<T, Double>> atLeast(
      final double minValue) {
    return new Predicate<Map.Entry<T, Double>>() {
      public boolean apply(Map.Entry<T, Double> entry) {
        return entry.getValue() >= minValue;
      }
    };
  }

  private final Predicate<Map.Entry<E, Double>> edgeGreaterThanHalf = atLeast(.51);
  private final Predicate<Map.Entry<EdgeCycle<E>, Double>> edgeCycleGreaterThanHalf = atLeast(.51);

  private static double sum(Iterable<Double> summands) {
    double ans = 0;
    for (Double summand : summands) {
      ans += summand;
    }
    return ans;
  }

  private static NumberFormat shortFormat = new DecimalFormat("0.00");

  private static String doublesToString(List<Double> doubles) {
    StringBuilder ans = new StringBuilder();
    for (int i = 0; i < doubles.size(); i++) {
      ans.append(shortFormat.format(doubles.get(i)));
      if (i < doubles.size() - 1) {
        ans.append(',');
      }
    }
    return ans.toString();
  }

  private int edgeCount(List<EdgeChain<E>> edgeChains) {
    int ans = 0;
    for (EdgeChain<E> chain : edgeChains) {
      ans += chain.size();
    }
    return ans;
  }

  private double computeWeight(List<EdgeChain<E>> edgeChains,
      Map<E, Double> edgeVals) {
    double ans = 0;
    for (EdgeChain<E> chain : edgeChains) {
      for (E edge : chain) {
        ans += edgeVals.get(edge);
      }
    }
    return ans;
  }

  @Deprecated
  private Set<E> getSelectedEdges(Map<E, Double> filteredEdgeValues) {
    Set<E> potentialEdges = filteredEdgeValues.keySet();
    Set<E> actualEdges = Sets.newHashSet();
    for (V root : kepInstance.getRootNodes()) {
      V head = root;
      while (head != null) {
        SetView<E> outEdge = Sets.intersection(potentialEdges,
            Sets.newHashSet(kepInstance.getGraph().getOutEdges(head)));
        if (outEdge.isEmpty()) {
          head = null;
        } else {
          E inUse = outEdge.iterator().next();
          actualEdges.add(inUse);
          head = kepInstance.getGraph().getDest(inUse);
        }
      }
    }
    return actualEdges;
  }

}


text:
package test

import (
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/search"
)

// A FakeIndex implements parts of search.Index and provides methods
// to controls the results, such as AddMeta, AddClaim,
// AddSignerAttrValue.
type FakeIndex struct {
	lk              sync.Mutex
	mimeType        map[string]string // blobref -> type
	size            map[string]int64
	ownerClaims     map[string]search.ClaimList // "<permanode>/<owner>" -> ClaimList
	signerAttrValue map[string]blob.Ref         // "<signer>\0<attr>\0<value>" -> blobref
	path            map[string]*search.Path     // "<signer>\0<base>\0<suffix>" -> path

	cllk  sync.Mutex
	clock int64 // TODO(bradfitz): make this a time.Time
}

var _ search.Index = (*FakeIndex)(nil)

func NewFakeIndex() *FakeIndex {
	return &FakeIndex{
		mimeType:        make(map[string]string),
		size:            make(map[string]int64),
		ownerClaims:     make(map[string]search.ClaimList),
		signerAttrValue: make(map[string]blob.Ref),
		path:            make(map[string]*search.Path),
	}
}

//
// Test methods
//

func (fi *FakeIndex) nextDate() time.Time {
	fi.cllk.Lock()
	fi.clock++ // TODO: fi.clock.Add(1 * time.Second)
	clock := fi.clock
	fi.cllk.Unlock()
	return time.Unix(clock, 0).UTC()
}

func (fi *FakeIndex) AddMeta(blob blob.Ref, mime string, size int64) {
	fi.lk.Lock()
	defer fi.lk.Unlock()
	fi.mimeType[blob.String()] = mime
	fi.size[blob.String()] = size
}

func (fi *FakeIndex) AddClaim(owner, permanode blob.Ref, claimType, attr, value string) {
	fi.lk.Lock()
	defer fi.lk.Unlock()
	date := fi.nextDate()

	claim := &search.Claim{
		Permanode: permanode,
		Signer:    blob.Ref{},
		BlobRef:   blob.Ref{},
		Date:      date,
		Type:      claimType,
		Attr:      attr,
		Value:     value,
	}
	key := permanode.String() + "/" + owner.String()
	fi.ownerClaims[key] = append(fi.ownerClaims[key], claim)

	if claimType == "set-attribute" && strings.HasPrefix(attr, "camliPath:") {
		suffix := attr[len("camliPath:"):]
		path := &search.Path{
			Target: blob.MustParse(value),
			Suffix: suffix,
		}
		fi.path[fmt.Sprintf("%s\x00%s\x00%s", owner, permanode, suffix)] = path
	}
}

func (fi *FakeIndex) AddSignerAttrValue(signer blob.Ref, attr, val string, latest blob.Ref) {
	fi.lk.Lock()
	defer fi.lk.Unlock()
	fi.signerAttrValue[fmt.Sprintf("%s\x00%s\x00%s", signer, attr, val)] = latest
}

//
// Interface implementation
//

func (fi *FakeIndex) GetRecentPermanodes(dest chan *search.Result, owner blob.Ref, limit int) error {
	panic("NOIMPL")
}

// TODO(mpl): write real tests
func (fi *FakeIndex) SearchPermanodesWithAttr(dest chan<- blob.Ref, request *search.PermanodeByAttrRequest) error {
	panic("NOIMPL")
}

func (fi *FakeIndex) GetOwnerClaims(permaNode, owner blob.Ref) (search.ClaimList, error) {
	fi.lk.Lock()
	defer fi.lk.Unlock()
	return fi.ownerClaims[permaNode.String()+"/"+owner.String()], nil
}

func (fi *FakeIndex) GetBlobMIMEType(blob blob.Ref) (mime string, size int64, err error) {
	fi.lk.Lock()
	defer fi.lk.Unlock()
	bs := blob.String()
	mime, ok := fi.mimeType[bs]
	if !ok {
		return "", 0, os.ErrNotExist
	}
	return mime, fi.size[bs], nil
}

func (fi *FakeIndex) ExistingFileSchemas(bytesRef blob.Ref) ([]blob.Ref, error) {
	panic("NOIMPL")
}

func (fi *FakeIndex) GetFileInfo(fileRef blob.Ref) (*search.FileInfo, error) {
	panic("NOIMPL")
}

func (fi *FakeIndex) GetImageInfo(fileRef blob.Ref) (*search.ImageInfo, error) {
	panic("NOIMPL")
}

func (fi *FakeIndex) GetDirMembers(dir blob.Ref, dest chan<- blob.Ref, limit int) error {
	panic("NOIMPL")
}

func (fi *FakeIndex) PermanodeOfSignerAttrValue(signer blob.Ref, attr, val string) (blob.Ref, error) {
	fi.lk.Lock()
	defer fi.lk.Unlock()
	if b, ok := fi.signerAttrValue[fmt.Sprintf("%s\x00%s\x00%s", signer, attr, val)]; ok {
		return b, nil
	}
	return blob.Ref{}, os.ErrNotExist
}

func (fi *FakeIndex) PathsOfSignerTarget(signer, target blob.Ref) ([]*search.Path, error) {
	panic("NOIMPL")
}

func (fi *FakeIndex) PathsLookup(signer, base blob.Ref, suffix string) ([]*search.Path, error) {
	panic("NOIMPL")
}

func (fi *FakeIndex) PathLookup(signer, base blob.Ref, suffix string, at time.Time) (*search.Path, error) {
	if !at.IsZero() {
		panic("PathLookup with non-zero 'at' time not supported")
	}
	fi.lk.Lock()
	defer fi.lk.Unlock()
	if p, ok := fi.path[fmt.Sprintf("%s\x00%s\x00%s", signer, base, suffix)]; ok {
		return p, nil
	}
	log.Printf("PathLookup miss for signer %q, base %q, suffix %q", signer, base, suffix)
	return nil, os.ErrNotExist
}

func (fi *FakeIndex) EdgesTo(ref blob.Ref, opts *search.EdgesToOpts) ([]*search.Edge, error) {
	panic("NOIMPL")
}

func (fi *FakeIndex) EnumerateBlobMeta(ch chan<- search.BlobMeta) error {
	panic("NOIMPL")
}