text:
package lnwallet_test

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/boltdb/bolt"
	"github.com/lightningnetwork/lnd/chainntnfs"
	"github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/lnwallet"
	"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
	"github.com/roasbeef/btcd/chaincfg"
	"github.com/roasbeef/btcd/chaincfg/chainhash"
	"github.com/roasbeef/btcutil/txsort"
	_ "github.com/roasbeef/btcwallet/walletdb/bdb"

	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/rpctest"
	"github.com/roasbeef/btcd/txscript"
	"github.com/roasbeef/btcd/wire"
	"github.com/roasbeef/btcutil"
)

var (
	privPass = []byte("private-test")

	// For simplicity a single priv key controls all of our test outputs.
	testWalletPrivKey = []byte{
		0x2b, 0xd8, 0x06, 0xc9, 0x7f, 0x0e, 0x00, 0xaf,
		0x1a, 0x1f, 0xc3, 0x32, 0x8f, 0xa7, 0x63, 0xa9,
		0x26, 0x97, 0x23, 0xc8, 0xdb, 0x8f, 0xac, 0x4f,
		0x93, 0xaf, 0x71, 0xdb, 0x18, 0x6d, 0x6e, 0x90,
	}

	// We're alice :)
	bobsPrivKey = []byte{
		0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
		0x63, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
		0xd, 0xe7, 0x95, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
		0x1e, 0xb, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
	}

	// Use a hard-coded HD seed.
	testHdSeed = [32]byte{
		0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
		0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
		0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
		0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
	}

	_, testPub = btcec.PrivKeyFromBytes(btcec.S256(), testHdSeed[:])

	// The number of confirmations required to consider any created channel
	// open.
	numReqConfs = uint16(1)

	bobAddr, _ = net.ResolveTCPAddr("tcp", "10.0.0.2:9000")
)

// assertProperBalance asserts than the total value of the unspent outputs
// within the wallet are *exactly* amount. If unable to retrieve the current
// balance, or the assertion fails, the test will halt with a fatal error.
func assertProperBalance(t *testing.T, lw *lnwallet.LightningWallet, numConfirms int32, amount int64) {
	balance, err := lw.ConfirmedBalance(numConfirms, false)
	if err != nil {
		t.Fatalf("unable to query for balance: %v", err)
	}
	if balance != btcutil.Amount(amount*1e8) {
		t.Fatalf("wallet credits not properly loaded, should have 40BTC, "+
			"instead have %v", balance)
	}
}

func assertChannelOpen(t *testing.T, miner *rpctest.Harness, numConfs uint32,
	c <-chan *lnwallet.LightningChannel) *lnwallet.LightningChannel {
	// Mine a single block. After this block is mined, the channel should
	// be considered fully open.
	if _, err := miner.Node.Generate(1); err != nil {
		t.Fatalf("unable to generate block: %v", err)
	}
	select {
	case lnc := <-c:
		return lnc
	case <-time.After(time.Second * 5):
		t.Fatalf("channel never opened")
		return nil
	}

	return nil
}

// bobNode represents the other party involved as a node within LN. Bob is our
// only "default-route", we have a direct connection with him.
type bobNode struct {
	privKey *btcec.PrivateKey

	// For simplicity, used for both the commit tx and the multi-sig output.
	channelKey      *btcec.PublicKey
	deliveryAddress btcutil.Address
	revocation      [32]byte
	delay           uint32
	id              *btcec.PublicKey

	obsfucator [lnwallet.StateHintSize]byte

	availableOutputs []*wire.TxIn
	changeOutputs    []*wire.TxOut
	fundingAmt       btcutil.Amount
}

// Contribution returns bobNode's contribution necessary to open a payment
// channel with Alice.
func (b *bobNode) Contribution(aliceCommitKey *btcec.PublicKey) *lnwallet.ChannelContribution {
	revokeKey := lnwallet.DeriveRevocationPubkey(aliceCommitKey, b.revocation[:])
	return &lnwallet.ChannelContribution{
		FundingAmount:   b.fundingAmt,
		Inputs:          b.availableOutputs,
		ChangeOutputs:   b.changeOutputs,
		MultiSigKey:     b.channelKey,
		CommitKey:       b.channelKey,
		DeliveryAddress: b.deliveryAddress,
		RevocationKey:   revokeKey,
		CsvDelay:        b.delay,
	}
}

// SingleContribution returns bobNode's contribution to a single funded
// channel. This contribution contains no inputs nor change outputs.
func (b *bobNode) SingleContribution(aliceCommitKey *btcec.PublicKey) *lnwallet.ChannelContribution {
	revokeKey := lnwallet.DeriveRevocationPubkey(aliceCommitKey, b.revocation[:])
	return &lnwallet.ChannelContribution{
		FundingAmount:   b.fundingAmt,
		MultiSigKey:     b.channelKey,
		CommitKey:       b.channelKey,
		DeliveryAddress: b.deliveryAddress,
		RevocationKey:   revokeKey,
		CsvDelay:        b.delay,
	}
}

// signFundingTx generates signatures for all the inputs in the funding tx
// belonging to Bob.
// NOTE: This generates the full witness stack.
func (b *bobNode) signFundingTx(fundingTx *wire.MsgTx) ([]*lnwallet.InputScript, error) {
	bobInputScripts := make([]*lnwallet.InputScript, 0, len(b.availableOutputs))
	bobPkScript := b.changeOutputs[0].PkScript

	inputValue := int64(7e8)
	hashCache := txscript.NewTxSigHashes(fundingTx)
	for i, _ := range fundingTx.TxIn {
		// Alice has already signed this input.
		if fundingTx.TxIn[i].Witness != nil {
			continue
		}

		witness, err := txscript.WitnessScript(fundingTx, hashCache, i,
			inputValue, bobPkScript, txscript.SigHashAll, b.privKey,
			true)
		if err != nil {
			return nil, err
		}

		inputScript := &lnwallet.InputScript{Witness: witness}
		bobInputScripts = append(bobInputScripts, inputScript)
	}

	return bobInputScripts, nil
}

// signCommitTx generates a raw signature required for generating a spend from
// the funding transaction.
func (b *bobNode) signCommitTx(commitTx *wire.MsgTx, fundingScript []byte,
	channelValue int64) ([]byte, error) {

	hashCache := txscript.NewTxSigHashes(commitTx)

	return txscript.RawTxInWitnessSignature(commitTx, hashCache, 0,
		channelValue, fundingScript, txscript.SigHashAll, b.privKey)
}

// newBobNode generates a test "ln node" to interact with Alice (us). For the
// funding transaction, bob has a single output totaling 7BTC. For our basic
// test, he'll fund the channel with 5BTC, leaving 2BTC to the change output.
// TODO(roasbeef): proper handling of change etc.
func newBobNode(miner *rpctest.Harness, amt btcutil.Amount) (*bobNode, error) {
	// First, parse Bob's priv key in order to obtain a key he'll use for the
	// multi-sig funding transaction.
	privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), bobsPrivKey)

	// Next, generate an output redeemable by bob.
	pkHash := btcutil.Hash160(pubKey.SerializeCompressed())
	bobAddr, err := btcutil.NewAddressWitnessPubKeyHash(
		pkHash,
		miner.ActiveNet)
	if err != nil {
		return nil, err
	}
	bobAddrScript, err := txscript.PayToAddrScript(bobAddr)
	if err != nil {
		return nil, err
	}

	// Give bobNode one 7 BTC output for use in creating channels.
	output := &wire.TxOut{7e8, bobAddrScript}
	mainTxid, err := miner.SendOutputs([]*wire.TxOut{output}, 10)
	if err != nil {
		return nil, err
	}

	// Mine a block in order to include the above output in a block. During
	// the reservation workflow, we currently test to ensure that the funding
	// output we're given actually exists.
	if _, err := miner.Node.Generate(1); err != nil {
		return nil, err
	}

	// Grab the transaction in order to locate the output index to Bob.
	tx, err := miner.Node.GetRawTransaction(mainTxid)
	if err != nil {
		return nil, err
	}
	found, index := lnwallet.FindScriptOutputIndex(tx.MsgTx(), bobAddrScript)
	if !found {
		return nil, fmt.Errorf("output to bob never created")
	}

	prevOut := wire.NewOutPoint(mainTxid, index)
	bobTxIn := wire.NewTxIn(prevOut, nil, nil)

	// Using bobs priv key above, create a change output he can spend.
	bobChangeOutput := wire.NewTxOut(2*1e8, bobAddrScript)

	// Bob's initial revocation hash is just his private key with the first
	// byte changed...
	var revocation [32]byte
	copy(revocation[:], bobsPrivKey)
	revocation[0] = 0xff

	var obsfucator [lnwallet.StateHintSize]byte
	copy(obsfucator[:], revocation[:])

	// His ID is just as creative...
	var id [chainhash.HashSize]byte
	id[0] = 0xff

	return &bobNode{
		id:               pubKey,
		privKey:          privKey,
		channelKey:       pubKey,
		deliveryAddress:  bobAddr,
		revocation:       revocation,
		fundingAmt:       amt,
		delay:            5,
		availableOutputs: []*wire.TxIn{bobTxIn},
		changeOutputs:    []*wire.TxOut{bobChangeOutput},
	}, nil
}

func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet, numOutputs, btcPerOutput int) error {
	// Using the mining node, spend from a coinbase output numOutputs to
	// give us btcPerOutput with each output.
	satoshiPerOutput := int64(btcPerOutput * 1e8)
	addrs := make([]btcutil.Address, 0, numOutputs)
	for i := 0; i < numOutputs; i++ {
		// Grab a fresh address from the wallet to house this output.
		walletAddr, err := w.NewAddress(lnwallet.WitnessPubKey, false)
		if err != nil {
			return err
		}

		script, err := txscript.PayToAddrScript(walletAddr)
		if err != nil {
			return err
		}

		addrs = append(addrs, walletAddr)

		output := &wire.TxOut{satoshiPerOutput, script}
		if _, err := miner.SendOutputs([]*wire.TxOut{output}, 10); err != nil {
			return err
		}
	}

	// TODO(roasbeef): shouldn't hardcode 10, use config param that dictates
	// how many confs we wait before opening a channel.
	// Generate 10 blocks with the mining node, this should mine all
	// numOutputs transactions created above. We generate 10 blocks here
	// in order to give all the outputs a "sufficient" number of confirmations.
	if _, err := miner.Node.Generate(10); err != nil {
		return err
	}

	// Wait until the wallet has finished syncing up to the main chain.
	ticker := time.NewTicker(100 * time.Millisecond)
	expectedBalance := btcutil.Amount(satoshiPerOutput * int64(numOutputs))
out:
	for {
		select {
		case <-ticker.C:
			balance, err := w.ConfirmedBalance(1, false)
			if err != nil {
				return err
			}
			if balance == expectedBalance {
				break out
			}
		}
	}
	ticker.Stop()

	return nil
}

// createTestWallet creates a test LightningWallet will a total of 20BTC
// available for funding channels.
func createTestWallet(tempTestDir string, miningNode *rpctest.Harness,
	netParams *chaincfg.Params, notifier chainntnfs.ChainNotifier,
	wc lnwallet.WalletController, signer lnwallet.Signer,
	bio lnwallet.BlockChainIO) (*lnwallet.LightningWallet, error) {

	dbDir := filepath.Join(tempTestDir, "cdb")
	cdb, err := channeldb.Open(dbDir)
	if err != nil {
		return nil, err
	}

	wallet, err := lnwallet.NewLightningWallet(cdb, notifier, wc, signer,
		bio, netParams)
	if err != nil {
		return nil, err
	}

	if err := wallet.Startup(); err != nil {
		return nil, err
	}

	// Load our test wallet with 20 outputs each holding 4BTC.
	if err := loadTestCredits(miningNode, wallet, 20, 4); err != nil {
		return nil, err
	}

	return wallet, nil
}

func testDualFundingReservationWorkflow(miner *rpctest.Harness, wallet *lnwallet.LightningWallet, t *testing.T) {
	t.Log("Running dual reservation workflow test")

	// Create the bob-test wallet which will be the other side of our funding
	// channel.
	fundingAmount := btcutil.Amount(5 * 1e8)
	bobNode, err := newBobNode(miner, fundingAmount)
	if err != nil {
		t.Fatalf("unable to create bob node: %v", err)
	}

	// Bob initiates a channel funded with 5 BTC for each side, so 10
	// BTC total. He also generates 2 BTC in change.
	chanReservation, err := wallet.InitChannelReservation(fundingAmount*2,
		fundingAmount, bobNode.id, bobAddr, numReqConfs, 4, 540, 0)
	if err != nil {
		t.Fatalf("unable to initialize funding reservation: %v", err)
	}

	// The channel reservation should now be populated with a multi-sig key
	// from our HD chain, a change output with 3 BTC, and 2 outputs
	// selected of 4 BTC each. Additionally, the rest of the items needed
	// to fulfill a funding contribution should also have been filled in.
	ourContribution := chanReservation.OurContribution()
	if len(ourContribution.Inputs) != 2 {
		t.Fatalf("outputs for funding tx not properly selected, have %v "+
			"outputs should have 2", len(ourContribution.Inputs))
	}
	if ourContribution.MultiSigKey == nil {
		t.Fatalf("alice's key for multi-sig not found")
	}
	if ourContribution.CommitKey == nil {
		t.Fatalf("alice's key for commit not found")
	}
	if ourContribution.DeliveryAddress == nil {
		t.Fatalf("alice's final delivery address not found")
	}
	if ourContribution.CsvDelay == 0 {
		t.Fatalf("csv delay not set")
	}

	// Bob sends over his output, change addr, pub keys, initial revocation,
	// final delivery address, and his accepted csv delay for the
	// commitment transactions.
	bobContribution := bobNode.Contribution(ourContribution.CommitKey)
	if err := chanReservation.ProcessContribution(bobContribution); err != nil {
		t.Fatalf("unable to add bob's funds to the funding tx: %v", err)
	}

	// At this point, the reservation should have our signatures, and a
	// partial funding transaction (missing bob's sigs).
	theirContribution := chanReservation.TheirContribution()
	ourFundingSigs, ourCommitSig := chanReservation.OurSignatures()
	if len(ourFundingSigs) != 2 {
		t.Fatalf("only %v of our sigs present, should have 2",
			len(ourFundingSigs))
	}
	if ourCommitSig == nil {
		t.Fatalf("commitment sig not found")
	}
	if ourContribution.RevocationKey == nil {
		t.Fatalf("alice's revocation key not found")
	}

	// Additionally, the funding tx should have been populated.
	fundingTx := chanReservation.FinalFundingTx()
	if fundingTx == nil {
		t.Fatalf("funding transaction never created!")
	}

	// Their funds should also be filled in.
	if len(theirContribution.Inputs) != 1 {
		t.Fatalf("bob's outputs for funding tx not properly selected, have %v "+
			"outputs should have 2", len(theirContribution.Inputs))
	}
	if theirContribution.ChangeOutputs[0].Value != 2e8 {
		t.Fatalf("bob should have one change output with value 2e8"+
			"satoshis, is instead %v",
			theirContribution.ChangeOutputs[0].Value)
	}
	if theirContribution.MultiSigKey == nil {
		t.Fatalf("bob's key for multi-sig not found")
	}
	if theirContribution.CommitKey == nil {
		t.Fatalf("bob's key for commit tx not found")
	}
	if theirContribution.DeliveryAddress == nil {
		t.Fatalf("bob's final delivery address not found")
	}
	if theirContribution.RevocationKey == nil {
		t.Fatalf("bob's revocaiton key not found")
	}

	// TODO(roasbeef): account for current hard-coded commit fee,
	// need to remove bob all together
	chanCapacity := int64(10e8 + 5000)
	// Alice responds with her output, change addr, multi-sig key and signatures.
	// Bob then responds with his signatures.
	bobsSigs, err := bobNode.signFundingTx(fundingTx)
	if err != nil {
		t.Fatalf("unable to sign inputs for bob: %v", err)
	}
	commitSig, err := bobNode.signCommitTx(
		chanReservation.LocalCommitTx(),
		chanReservation.FundingRedeemScript(),
		chanCapacity)
	if err != nil {
		t.Fatalf("bob is unable to sign alice's commit tx: %v", err)
	}
	if err := chanReservation.CompleteReservation(bobsSigs, commitSig); err != nil {
		t.Fatalf("unable to complete funding tx: %v", err)
	}

	// At this point, the channel can be considered "open" when the funding
	// txn hits a "comfortable" depth.

	// The resulting active channel state should have been persisted to the DB.
	fundingSha := fundingTx.TxHash()
	channels, err := wallet.ChannelDB.FetchOpenChannels(bobNode.id)
	if err != nil {
		t.Fatalf("unable to retrieve channel from DB: %v", err)
	}
	if !bytes.Equal(channels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
		t.Fatalf("channel state not properly saved")
	}

	// Assert that the channel opens after a single block.
	lnChan := make(chan *lnwallet.LightningChannel, 1)
	go func() {
		channel, _, _ := chanReservation.DispatchChan()
		lnChan <- channel
	}()
	lnc := assertChannelOpen(t, miner, uint32(numReqConfs), lnChan)

	// Now that the channel is open, execute a cooperative closure of the
	// now open channel.
	aliceCloseSig, _, err := lnc.InitCooperativeClose()
	if err != nil {
		t.Fatalf("unable to init cooperative closure: %v", err)
	}
	aliceCloseSig = append(aliceCloseSig, byte(txscript.SigHashAll))

	chanInfo := lnc.StateSnapshot()

	// Obtain bob's signature for the closure transaction.
	witnessScript := lnc.FundingWitnessScript
	fundingOut := lnc.ChannelPoint()
	fundingTxIn := wire.NewTxIn(fundingOut, nil, nil)
	bobCloseTx := lnwallet.CreateCooperativeCloseTx(fundingTxIn,
		chanInfo.RemoteBalance, chanInfo.LocalBalance,
		lnc.RemoteDeliveryScript, lnc.LocalDeliveryScript,
		true)
	bobSig, err := bobNode.signCommitTx(bobCloseTx, witnessScript, int64(lnc.Capacity))
	if err != nil {
		t.Fatalf("unable to generate bob's signature for closing tx: %v", err)
	}

	// Broadcast the transaction to the network. This transaction should
	// be accepted, and found in the next mined block.
	ourKey := chanReservation.OurContribution().MultiSigKey.SerializeCompressed()
	theirKey := chanReservation.TheirContribution().MultiSigKey.SerializeCompressed()
	witness := lnwallet.SpendMultiSig(witnessScript, ourKey, aliceCloseSig,
		theirKey, bobSig)
	bobCloseTx.TxIn[0].Witness = witness
	if err := wallet.PublishTransaction(bobCloseTx); err != nil {
		t.Fatalf("broadcast of close tx rejected: %v", err)
	}
}

func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
	wallet *lnwallet.LightningWallet, t *testing.T) {

	t.Log("Running funding txn locked outputs test")

	// Create a single channel asking for 16 BTC total.
	fundingAmount := btcutil.Amount(8 * 1e8)
	_, err := wallet.InitChannelReservation(fundingAmount, fundingAmount,
		testPub, bobAddr, numReqConfs, 4, 540, 0)
	if err != nil {
		t.Fatalf("unable to initialize funding reservation 1: %v", err)
	}

	// Now attempt to reserve funds for another channel, this time
	// requesting 900 BTC. We only have around 64BTC worth of outpoints
	// that aren't locked, so this should fail.
	amt := btcutil.Amount(900 * 1e8)
	failedReservation, err := wallet.InitChannelReservation(amt, amt,
		testPub, bobAddr, numReqConfs, 4, 540, 0)
	if err == nil {
		t.Fatalf("not error returned, should fail on coin selection")
	}
	if _, ok := err.(*lnwallet.ErrInsufficientFunds); !ok {
		t.Fatalf("error not coinselect error: %v", err)
	}
	if failedReservation != nil {
		t.Fatalf("reservation should be nil")
	}
}

func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
	wallet *lnwallet.LightningWallet, t *testing.T) {

	t.Log("Running funding insufficient funds tests")

	// Create a reservation for 44 BTC.
	fundingAmount := btcutil.Amount(44 * 1e8)
	chanReservation, err := wallet.InitChannelReservation(fundingAmount,
		fundingAmount, testPub, bobAddr, numReqConfs, 4, 540, 0)
	if err != nil {
		t.Fatalf("unable to initialize funding reservation: %v", err)
	}

	// Attempt to create another channel with 44 BTC, this should fail.
	_, err = wallet.InitChannelReservation(fundingAmount,
		fundingAmount, testPub, bobAddr, numReqConfs, 4, 540, 0)
	if _, ok := err.(*lnwallet.ErrInsufficientFunds); !ok {
		t.Fatalf("coin selection succeded should have insufficient funds: %v",
			err)
	}

	// Now cancel that old reservation.
	if err := chanReservation.Cancel(); err != nil {
		t.Fatalf("unable to cancel reservation: %v", err)
	}

	// Those outpoints should no longer be locked.
	lockedOutPoints := wallet.LockedOutpoints()
	if len(lockedOutPoints) != 0 {
		t.Fatalf("outpoints still locked")
	}

	// Reservation ID should no longer be tracked.
	numReservations := wallet.ActiveReservations()
	if len(wallet.ActiveReservations()) != 0 {
		t.Fatalf("should have 0 reservations, instead have %v",
			numReservations)
	}

	// TODO(roasbeef): create method like Balance that ignores locked
	// outpoints, will let us fail early/fast instead of querying and
	// attempting coin selection.

	// Request to fund a new channel should now succeed.
	_, err = wallet.InitChannelReservation(fundingAmount, fundingAmount,
		testPub, bobAddr, numReqConfs, 4, 540, 0)
	if err != nil {
		t.Fatalf("unable to initialize funding reservation: %v", err)
	}
}

func testCancelNonExistantReservation(miner *rpctest.Harness,
	wallet *lnwallet.LightningWallet, t *testing.T) {

	t.Log("Running cancel reservation tests")

	// Create our own reservation, give it some ID.
	res := lnwallet.NewChannelReservation(1000, 1000, 5000, wallet, 22,
		numReqConfs, 10)

	// Attempt to cancel this reservation. This should fail, we know
	// nothing of it.
	if err := res.Cancel(); err == nil {
		t.Fatalf("cancelled non-existant reservation")
	}
}

func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness,
	wallet *lnwallet.LightningWallet, t *testing.T) {

	t.Log("Running single funder workflow initiator test")

	// For this scenario, we (lnwallet) will be the channel initiator while bob
	// will be the recipient.

	// Create the bob-test wallet which will be the other side of our funding
	// channel.
	bobNode, err := newBobNode(miner, 0)
	if err != nil {
		t.Fatalf("unable to create bob node: %v", err)
	}

	// Initialize a reservation for a channel with 4 BTC funded solely by
	// us. We'll also initially push 1 BTC of the channel towards Bob's
	// side.
	fundingAmt := btcutil.Amount(4 * 1e8)
	pushAmt := btcutil.Amount(btcutil.SatoshiPerBitcoin)
	chanReservation, err := wallet.InitChannelReservation(fundingAmt,
		fundingAmt, bobNode.id, bobAddr, numReqConfs, 4, 540, pushAmt)
	if err != nil {
		t.Fatalf("unable to init channel reservation: %v", err)
	}

	// Verify all contribution fields have been set properly.
	ourContribution := chanReservation.OurContribution()
	if len(ourContribution.Inputs) < 1 {
		t.Fatalf("outputs for funding tx not properly selected, have %v "+
			"outputs should at least 1", len(ourContribution.Inputs))
	}
	if len(ourContribution.ChangeOutputs) != 1 {
		t.Fatalf("coin selection failed, should have one change outputs, "+
			"instead have: %v", len(ourContribution.ChangeOutputs))
	}
	if ourContribution.MultiSigKey == nil {
		t.Fatalf("alice's key for multi-sig not found")
	}
	if ourContribution.CommitKey == nil {
		t.Fatalf("alice's key for commit not found")
	}
	if ourContribution.DeliveryAddress == nil {
		t.Fatalf("alice's final delivery address not found")
	}
	if ourContribution.CsvDelay == 0 {
		t.Fatalf("csv delay not set")
	}

	// At this point bob now responds to our request with a response
	// containing his channel contribution. The contribution will have no
	// inputs, only a multi-sig key, csv delay, etc.
	bobContribution := bobNode.SingleContribution(ourContribution.CommitKey)
	if err := chanReservation.ProcessContribution(bobContribution); err != nil {
		t.Fatalf("unable to add bob's contribution: %v", err)
	}

	// At this point, the reservation should have our signatures, and a
	// partial funding transaction (missing bob's sigs).
	theirContribution := chanReservation.TheirContribution()
	ourFundingSigs, ourCommitSig := chanReservation.OurSignatures()
	if ourFundingSigs == nil {
		t.Fatalf("funding sigs not found")
	}
	if ourCommitSig == nil {
		t.Fatalf("commitment sig not found")
	}
	// Additionally, the funding tx should have been populated.
	if chanReservation.FinalFundingTx() == nil {
		t.Fatalf("funding transaction never created!")
	}
	// Their funds should also be filled in.
	if len(theirContribution.Inputs) != 0 {
		t.Fatalf("bob shouldn't have any inputs, instead has %v",
			len(theirContribution.Inputs))
	}
	if len(theirContribution.ChangeOutputs) != 0 {
		t.Fatalf("bob shouldn't have any change outputs, instead "+
			"has %v", theirContribution.ChangeOutputs[0].Value)
	}
	if ourContribution.RevocationKey == nil {
		t.Fatalf("alice's revocation hash not found")
	}
	if theirContribution.MultiSigKey == nil {
		t.Fatalf("bob's key for multi-sig not found")
	}
	if theirContribution.CommitKey == nil {
		t.Fatalf("bob's key for commit tx not found")
	}
	if theirContribution.DeliveryAddress == nil {
		t.Fatalf("bob's final delivery address not found")
	}
	if theirContribution.RevocationKey == nil {
		t.Fatalf("bob's revocation hash not found")
	}

	// With this contribution processed, we're able to create the
	// funding+commitment transactions, as well as generate a signature
	// for bob's version of the commitment transaction.
	//
	// Now Bob can generate a signature for our version of the commitment
	// transaction, allowing us to complete the reservation.
	bobCommitSig, err := bobNode.signCommitTx(
		chanReservation.LocalCommitTx(),
		chanReservation.FundingRedeemScript(),
		// TODO(roasbeef): account for current hard-coded fee, need to
		// remove bobNode entirely
		int64(fundingAmt)+5000)
	if err != nil {
		t.Fatalf("bob is unable to sign alice's commit tx: %v", err)
	}
	if err := chanReservation.CompleteReservation(nil, bobCommitSig); err != nil {
		t.Fatalf("unable to complete funding tx: %v", err)
	}

	// TODO(roasbeef): verify our sig for bob's once sighash change is
	// merged.

	// The resulting active channel state should have been persisted to the DB.
	// TODO(roasbeef): de-duplicate
	fundingTx := chanReservation.FinalFundingTx()
	fundingSha := fundingTx.TxHash()
	channels, err := wallet.ChannelDB.FetchOpenChannels(bobNode.id)
	if err != nil {
		t.Fatalf("unable to retrieve channel from DB: %v", err)
	}
	if !bytes.Equal(channels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
		t.Fatalf("channel state not properly saved: %v vs %v",
			hex.EncodeToString(channels[0].FundingOutpoint.Hash[:]),
			hex.EncodeToString(fundingSha[:]))
	}
	if !channels[0].IsInitiator {
		t.Fatalf("alice not detected as channel initiator")
	}
	if channels[0].ChanType != channeldb.SingleFunder {
		t.Fatalf("channel type is incorrect, expected %v instead got %v",
			channeldb.SingleFunder, channels[0].ChanType)
	}

	lnChan := make(chan *lnwallet.LightningChannel, 1)
	go func() {
		channel, _, _ := chanReservation.DispatchChan()
		lnChan <- channel
	}()
	assertChannelOpen(t, miner, uint32(numReqConfs), lnChan)
}

func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,
	wallet *lnwallet.LightningWallet, t *testing.T) {

	t.Log("Running single funder workflow responder test")

	// For this scenario, bob will initiate the channel, while we simply act as
	// the responder.
	capacity := btcutil.Amount(4 * 1e8)

	// Create the bob-test wallet which will be initiator of a single
	// funder channel shortly.
	bobNode, err := newBobNode(miner, capacity)
	if err != nil {
		t.Fatalf("unable to create bob node: %v", err)
	}

	// Bob sends over a single funding request, so we allocate our
	// contribution and the necessary resources.
	fundingAmt := btcutil.Amount(0)
	chanReservation, err := wallet.InitChannelReservation(capacity,
		fundingAmt, bobNode.id, bobAddr, numReqConfs, 4, 540, 0)
	if err != nil {
		t.Fatalf("unable to init channel reservation: %v", err)
	}

	// Verify all contribution fields have been set properly. Since we are
	// the recipient of a single-funder channel, we shouldn't have selected
	// any coins or generated any change outputs.
	ourContribution := chanReservation.OurContribution()
	if len(ourContribution.Inputs) != 0 {
		t.Fatalf("outputs for funding tx not properly selected, have %v "+
			"outputs should have 0", len(ourContribution.Inputs))
	}
	if len(ourContribution.ChangeOutputs) != 0 {
		t.Fatalf("coin selection failed, should have no change outputs, "+
			"instead have: %v", ourContribution.ChangeOutputs[0].Value)
	}
	if ourContribution.MultiSigKey == nil {
		t.Fatalf("alice's key for multi-sig not found")
	}
	if ourContribution.CommitKey == nil {
		t.Fatalf("alice's key for commit not found")
	}
	if ourContribution.DeliveryAddress == nil {
		t.Fatalf("alice's final delivery address not found")
	}
	if ourContribution.CsvDelay == 0 {
		t.Fatalf("csv delay not set")
	}

	// Next we process Bob's single funder contribution which doesn't
	// include any inputs or change addresses, as only Bob will construct
	// the funding transaction.
	bobContribution := bobNode.Contribution(ourContribution.CommitKey)
	if err := chanReservation.ProcessSingleContribution(bobContribution); err != nil {
		t.Fatalf("unable to process bob's contribution: %v", err)
	}
	if chanReservation.FinalFundingTx() != nil {
		t.Fatalf("funding transaction populated!")
	}
	if len(bobContribution.Inputs) != 1 {
		t.Fatalf("bob shouldn't have one inputs, instead has %v",
			len(bobContribution.Inputs))
	}
	if ourContribution.RevocationKey == nil {
		t.Fatalf("alice's revocation key not found")
	}
	if len(bobContribution.ChangeOutputs) != 1 {
		t.Fatalf("bob shouldn't have one change output, instead "+
			"has %v", len(bobContribution.ChangeOutputs))
	}
	if bobContribution.MultiSigKey == nil {
		t.Fatalf("bob's key for multi-sig not found")
	}
	if bobContribution.CommitKey == nil {
		t.Fatalf("bob's key for commit tx not found")
	}
	if bobContribution.DeliveryAddress == nil {
		t.Fatalf("bob's final delivery address not found")
	}
	if bobContribution.RevocationKey == nil {
		t.Fatalf("bob's revocaiton key not found")
	}

	fundingRedeemScript, multiOut, err := lnwallet.GenFundingPkScript(
		ourContribution.MultiSigKey.SerializeCompressed(),
		bobContribution.MultiSigKey.SerializeCompressed(),
		// TODO(roasbeef): account for hard-coded fee, remove bob node
		int64(capacity)+5000)
	if err != nil {
		t.Fatalf("unable to generate multi-sig output: %v", err)
	}

	// At this point, we send Bob our contribution, allowing him to
	// construct the funding transaction, and sign our version of the
	// commitment transaction.
	fundingTx := wire.NewMsgTx(1)
	fundingTx.AddTxIn(bobNode.availableOutputs[0])
	fundingTx.AddTxOut(bobNode.changeOutputs[0])
	fundingTx.AddTxOut(multiOut)
	txsort.InPlaceSort(fundingTx)
	if _, err := bobNode.signFundingTx(fundingTx); err != nil {
		t.Fatalf("unable to generate bob's funding sigs: %v", err)
	}

	// Locate the output index of the 2-of-2 in order to send back to the
	// wallet so it can finalize the transaction by signing bob's commitment
	// transaction.
	fundingTxID := fundingTx.TxHash()
	_, multiSigIndex := lnwallet.FindScriptOutputIndex(fundingTx, multiOut.PkScript)
	fundingOutpoint := wire.NewOutPoint(&fundingTxID, multiSigIndex)
	bobObsfucator := bobNode.obsfucator

	// Next, manually create Alice's commitment transaction, signing the
	// fully sorted and state hinted transaction.
	fundingTxIn := wire.NewTxIn(fundingOutpoint, nil, nil)
	aliceCommitTx, err := lnwallet.CreateCommitTx(fundingTxIn,
		ourContribution.CommitKey, bobContribution.CommitKey,
		ourContribution.RevocationKey, ourContribution.CsvDelay, 0,
		capacity)
	if err != nil {
		t.Fatalf("unable to create alice's commit tx: %v", err)
	}
	txsort.InPlaceSort(aliceCommitTx)
	err = lnwallet.SetStateNumHint(aliceCommitTx, 0, bobObsfucator)
	if err != nil {
		t.Fatalf("unable to set state hint: %v", err)
	}
	bobCommitSig, err := bobNode.signCommitTx(aliceCommitTx,
		// TODO(roasbeef): account for hard-coded fee, remove bob node
		fundingRedeemScript, int64(capacity)+5000)
	if err != nil {
		t.Fatalf("unable to sign alice's commit tx: %v", err)
	}

	// With this stage complete, Alice can now complete the reservation.
	bobRevokeKey := bobContribution.RevocationKey
	err = chanReservation.CompleteReservationSingle(bobRevokeKey,
		fundingOutpoint, bobCommitSig, bobObsfucator)
	if err != nil {
		t.Fatalf("unable to complete reservation: %v", err)
	}

	// Alice should have saved the funding output.
	if chanReservation.FundingOutpoint() != fundingOutpoint {
		t.Fatalf("funding outputs don't match: %#v vs %#v",
			chanReservation.FundingOutpoint(), fundingOutpoint)
	}

	// Some period of time later, Bob presents us with an SPV proof
	// attesting to an open channel. At this point Alice recognizes the
	// channel, saves the state to disk, and creates the channel itself.
	if _, err := chanReservation.FinalizeReservation(); err != nil {
		t.Fatalf("unable to finalize reservation: %v", err)
	}

	// TODO(roasbeef): bob verify alice's sig
}

func testListTransactionDetails(miner *rpctest.Harness, wallet *lnwallet.LightningWallet, t *testing.T) {
	t.Log("Running list transaction details test")

	// Create 5 new outputs spendable by the wallet.
	const numTxns = 5
	const outputAmt = btcutil.SatoshiPerBitcoin
	txids := make(map[chainhash.Hash]struct{})
	for i := 0; i < numTxns; i++ {
		addr, err := wallet.NewAddress(lnwallet.WitnessPubKey, false)
		if err != nil {
			t.Fatalf("unable to create new address: %v", err)
		}
		script, err := txscript.PayToAddrScript(addr)
		if err != nil {
			t.Fatalf("unable to create output script: %v", err)
		}

		output := &wire.TxOut{outputAmt, script}
		txid, err := miner.SendOutputs([]*wire.TxOut{output}, 10)
		if err != nil {
			t.Fatalf("unable to send coinbase: %v", err)
		}
		txids[*txid] = struct{}{}
	}

	// Generate 10 blocks to mine all the transactions created above.
	const numBlocksMined = 10
	blocks, err := miner.Node.Generate(numBlocksMined)
	if err != nil {
		t.Fatalf("unable to mine blocks: %v", err)
	}

	// Next, fetch all the current transaction details.
	// TODO(roasbeef): use ntfn client here instead?
	time.Sleep(time.Second * 2)
	txDetails, err := wallet.ListTransactionDetails()
	if err != nil {
		t.Fatalf("unable to fetch tx details: %v", err)
	}

	// Each of the transactions created above should be found with the
	// proper details populated.
	for _, txDetail := range txDetails {
		if _, ok := txids[txDetail.Hash]; !ok {
			continue
		}

		if txDetail.NumConfirmations != numBlocksMined {
			t.Fatalf("num confs incorrect, got %v expected %v",
				txDetail.NumConfirmations, numBlocksMined)
		}
		if txDetail.Value != outputAmt {
			t.Fatalf("tx value incorrect, got %v expected %v",
				txDetail.Value, outputAmt)
		}
		if !bytes.Equal(txDetail.BlockHash[:], blocks[0][:]) {
			t.Fatalf("block hash mismatch, got %v expected %v",
				txDetail.BlockHash, blocks[0])
		}

		delete(txids, txDetail.Hash)
	}
	if len(txids) != 0 {
		t.Fatalf("all transactions not found in details!")
	}

	// Next create a transaction paying to an output which isn't under the
	// wallet's control.
	b := txscript.NewScriptBuilder()
	b.AddOp(txscript.OP_0)
	outputScript, err := b.Script()
	if err != nil {
		t.Fatalf("unable to make output script: %v", err)
	}
	burnOutput := wire.NewTxOut(outputAmt, outputScript)
	burnTXID, err := wallet.SendOutputs([]*wire.TxOut{burnOutput})
	if err != nil {
		t.Fatalf("unable to create burn tx: %v", err)
	}
	burnBlock, err := miner.Node.Generate(1)
	if err != nil {
		t.Fatalf("unable to mine block: %v", err)
	}

	// Fetch the transaction details again, the new transaction should be
	// shown as debiting from the wallet's balance.
	time.Sleep(time.Second * 2)
	txDetails, err = wallet.ListTransactionDetails()
	if err != nil {
		t.Fatalf("unable to fetch tx details: %v", err)
	}
	var burnTxFound bool
	for _, txDetail := range txDetails {
		if !bytes.Equal(txDetail.Hash[:], burnTXID[:]) {
			continue
		}

		burnTxFound = true
		if txDetail.NumConfirmations != 1 {
			t.Fatalf("num confs incorrect, got %v expected %v",
				txDetail.NumConfirmations, 1)
		}
		if txDetail.Value >= -outputAmt {
			t.Fatalf("tx value incorrect, got %v expected %v",
				txDetail.Value, -outputAmt)
		}
		if !bytes.Equal(txDetail.BlockHash[:], burnBlock[0][:]) {
			t.Fatalf("block hash mismatch, got %v expected %v",
				txDetail.BlockHash, burnBlock[0])
		}
	}
	if !burnTxFound {
		t.Fatalf("tx burning btc not found")
	}
}

func testTransactionSubscriptions(miner *rpctest.Harness, w *lnwallet.LightningWallet, t *testing.T) {
	t.Log("Running transaction subscriptions test")

	// First, check to see if this wallet meets the TransactionNotifier
	// interface, if not then we'll skip this test for this particular
	// implementation of the WalletController.
	txClient, err := w.SubscribeTransactions()
	if err != nil {
		t.Fatalf("unable to generate tx subscription: %v")
	}
	defer txClient.Cancel()

	const (
		outputAmt = btcutil.SatoshiPerBitcoin
		numTxns   = 3
	)
	unconfirmedNtfns := make(chan struct{})
	go func() {
		for i := 0; i < numTxns; i++ {
			txDetail := <-txClient.UnconfirmedTransactions()
			if txDetail.NumConfirmations != 0 {
				t.Fatalf("incorrect number of confs, expected %v got %v",
					0, txDetail.NumConfirmations)
			}
			if txDetail.Value != outputAmt {
				t.Fatalf("incorrect output amt, expected %v got %v",
					outputAmt, txDetail.Value)
			}
			if txDetail.BlockHash != nil {
				t.Fatalf("block hash should be nil, is instead %v",
					txDetail.BlockHash)
			}
		}

		close(unconfirmedNtfns)
	}()

	// Next, fetch a fresh address from the wallet, create 3 new outputs
	// with the pkScript.
	for i := 0; i < numTxns; i++ {
		addr, err := w.NewAddress(lnwallet.WitnessPubKey, false)
		if err != nil {
			t.Fatalf("unable to create new address: %v", err)
		}
		script, err := txscript.PayToAddrScript(addr)
		if err != nil {
			t.Fatalf("unable to create output script: %v", err)
		}

		output := &wire.TxOut{outputAmt, script}
		if _, err := miner.SendOutputs([]*wire.TxOut{output}, 10); err != nil {
			t.Fatalf("unable to send coinbase: %v", err)
		}
	}

	// We should receive a notification for all three transactions
	// generated above.
	select {
	case <-time.After(time.Second * 5):
		t.Fatalf("transactions not received after 3 seconds")
	case <-unconfirmedNtfns: // Fall through on successs
	}

	confirmedNtfns := make(chan struct{})
	go func() {
		for i := 0; i < numTxns; i++ {
			txDetail := <-txClient.ConfirmedTransactions()
			if txDetail.NumConfirmations != 1 {
				t.Fatalf("incorrect number of confs, expected %v got %v",
					1, txDetail.NumConfirmations)
			}
			if txDetail.Value != outputAmt {
				t.Fatalf("incorrect output amt, expected %v got %v",
					outputAmt, txDetail.Value)
			}
		}
		close(confirmedNtfns)
	}()

	// Next mine a single block, all the transactions generated above
	// should be included.
	if _, err := miner.Node.Generate(1); err != nil {
		t.Fatalf("unable to generate block: %v", err)
	}

	// We should receive a notification for all three transactions
	// since they should be mined in the next block.
	select {
	case <-time.After(time.Second * 5):
		t.Fatalf("transactions not received after 3 seconds")
	case <-confirmedNtfns: // Fall through on success
	}
}

func testSignOutputPrivateTweak(r *rpctest.Harness, w *lnwallet.LightningWallet, t *testing.T) {
	t.Logf("Running private tweak test")

	// We'd like to test the ability of the wallet's Signer implementation
	// to be able to sign with a private key derived from tweaking the
	// specific public key. This scenario exercises the case when the
	// wallet needs to sign for a sweep of a revoked output.

	// First, generate a new public key under th control of the wallet,
	// then generate a revocation key using it.
	pubkey, err := w.NewRawKey()
	if err != nil {
		t.Fatalf("unable to obtain public key: %v", err)
	}
	revocation := bytes.Repeat([]byte{2}, 32)
	revocationKey := lnwallet.DeriveRevocationPubkey(pubkey, revocation)

	// With the revocation key generated, create a pkScript that pays to
	// the revocation key using a simple p2wkh script.
	pubkeyHash := btcutil.Hash160(revocationKey.SerializeCompressed())
	revokeAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubkeyHash,
		&chaincfg.SimNetParams)
	if err != nil {
		t.Fatalf("unable to create addr: %v", err)
	}
	revokeScript, err := txscript.PayToAddrScript(revokeAddr)
	if err != nil {
		t.Fatalf("unable to generate script: %v", err)
	}

	// With the script fully assemebld, instruct the wallet to fund the
	// output with a newly creaed transaction.
	revokeOutput := &wire.TxOut{
		Value:    btcutil.SatoshiPerBitcoin,
		PkScript: revokeScript,
	}
	txid, err := w.SendOutputs([]*wire.TxOut{revokeOutput})
	if err != nil {
		t.Fatalf("unable to create output: %v", err)
	}

	// Query for the transaction generated above so we can located the
	// index of our output.
	tx, err := w.ChainIO.GetTransaction(txid)
	if err != nil {
		t.Fatalf("unable to query for tx: %v", err)
	}
	var outputIndex uint32
	if bytes.Equal(tx.TxOut[0].PkScript, revokeScript) {
		outputIndex = 0
	} else {
		outputIndex = 1
	}

	/// WIth the index located, we can create a transaction spending the
	//referenced output.
	sweepTx := wire.NewMsgTx(2)
	sweepTx.AddTxIn(&wire.TxIn{
		PreviousOutPoint: wire.OutPoint{
			Hash:  tx.TxHash(),
			Index: outputIndex,
		},
	})

	// Now we can populate the sign descriptor which we'll use to generate
	// the signature. Within the descriptor we set the private tweak value
	// as the key in the script is derived based on this tweak value and
	// the key we originally generated above.
	signDesc := &lnwallet.SignDescriptor{
		PubKey:        pubkey,
		PrivateTweak:  revocation,
		WitnessScript: revokeScript,
		Output:        revokeOutput,
		HashType:      txscript.SigHashAll,
		SigHashes:     txscript.NewTxSigHashes(sweepTx),
		InputIndex:    0,
	}

	// With the descriptor created, we use it to generate a signature, then
	// manually create a valid witness stack we'll use for signing.
	spendSig, err := w.Signer.SignOutputRaw(sweepTx, signDesc)
	if err != nil {
		t.Fatalf("unable to generate signature: %v", err)
	}
	witness := make([][]byte, 2)
	witness[0] = append(spendSig, byte(txscript.SigHashAll))
	witness[1] = revocationKey.SerializeCompressed()
	sweepTx.TxIn[0].Witness = witness

	// Finally, attempt to validate the completed transaction. This should
	// succeed if the wallet was able to properly generate the proper
	// private key.
	vm, err := txscript.NewEngine(revokeScript,
		sweepTx, 0, txscript.StandardVerifyFlags, nil,
		nil, int64(btcutil.SatoshiPerBitcoin))
	if err != nil {
		t.Fatalf("unable to create engine: %v", err)
	}
	if err := vm.Execute(); err != nil {
		t.Fatalf("revocation spend invalid: %v", err)
	}
}

var walletTests = []func(miner *rpctest.Harness, w *lnwallet.LightningWallet, test *testing.T){
	// TODO(roasbeef): reservation tests should prob be split out
	testDualFundingReservationWorkflow,
	testSingleFunderReservationWorkflowInitiator,
	testSingleFunderReservationWorkflowResponder,
	testFundingTransactionLockedOutputs,
	testFundingCancellationNotEnoughFunds,
	testTransactionSubscriptions,
	testListTransactionDetails,
	testSignOutputPrivateTweak,
	testCancelNonExistantReservation,
}

type testLnWallet struct {
	lnwallet    *lnwallet.LightningWallet
	cleanUpFunc func()
}

func clearWalletState(w *lnwallet.LightningWallet) error {
	w.ResetReservations()

	return w.ChannelDB.Wipe()
}

// TestInterfaces tests all registered interfaces with a unified set of tests
// which excersie each of the required methods found within the WalletController
// interface.
//
// NOTE: In the future, when additional implementations of the WalletController
// interface have been implemented, in order to ensure the new concrete
// implementation is automatically tested, two steps must be undertaken. First,
// one needs add a "non-captured" (_) import from the new sub-package. This
// import should trigger an init() method within the package which registeres
// the interface. Second, an additional case in the switch within the main loop
// below needs to be added which properly initializes the interface.
//
// TODO(roasbeef): purge bobNode in favor of dual lnwallet's
func TestLightningWallet(t *testing.T) {
	netParams := &chaincfg.SimNetParams

	// Initialize the harness around a btcd node which will serve as our
	// dedicated miner to generate blocks, cause re-orgs, etc. We'll set
	// up this node with a chain length of 125, so we have plentyyy of BTC
	// to play around with.
	miningNode, err := rpctest.New(netParams, nil, nil)
	if err != nil {
		t.Fatalf("unable to create mining node: %v", err)
	}
	defer miningNode.TearDown()
	if err := miningNode.SetUp(true, 25); err != nil {
		t.Fatalf("unable to set up mining node: %v", err)
	}

	// Next mine enough blocks in order for segwit and the CSV package
	// soft-fork to activate on SimNet.
	numBlocks := netParams.MinerConfirmationWindow * 2
	if _, err := miningNode.Node.Generate(numBlocks); err != nil {
		t.Fatalf("unable to generate blocks: %v", err)
	}

	rpcConfig := miningNode.RPCConfig()

	chainNotifier, err := btcdnotify.New(&rpcConfig)
	if err != nil {
		t.Fatalf("unable to create notifier: %v", err)
	}
	if err := chainNotifier.Start(); err != nil {
		t.Fatalf("unable to start notifier: %v", err)
	}

	var bio lnwallet.BlockChainIO
	var signer lnwallet.Signer
	var wc lnwallet.WalletController
	for _, walletDriver := range lnwallet.RegisteredWallets() {
		tempTestDir, err := ioutil.TempDir("", "lnwallet")
		if err != nil {
			t.Fatalf("unable to create temp directory: %v", err)
		}
		defer os.RemoveAll(tempTestDir)

		walletType := walletDriver.WalletType
		switch walletType {
		case "btcwallet":
			btcwalletConfig := &btcwallet.Config{
				PrivatePass: privPass,
				HdSeed:      testHdSeed[:],
				DataDir:     tempTestDir,
				NetParams:   netParams,
				RpcHost:     rpcConfig.Host,
				RpcUser:     rpcConfig.User,
				RpcPass:     rpcConfig.Pass,
				CACert:      rpcConfig.Certificates,
			}
			wc, err = walletDriver.New(btcwalletConfig)
			if err != nil {
				t.Fatalf("unable to create btcwallet: %v", err)
			}
			signer = wc.(*btcwallet.BtcWallet)
			bio = wc.(*btcwallet.BtcWallet)
		default:
			t.Fatalf("unknown wallet driver: %v", walletType)
		}

		// Funding via 20 outputs with 4BTC each.
		lnw, err := createTestWallet(tempTestDir, miningNode, netParams,
			chainNotifier, wc, signer, bio)
		if err != nil {
			t.Fatalf("unable to create test ln wallet: %v", err)
		}

		// The wallet should now have 80BTC available for spending.
		assertProperBalance(t, lnw, 1, 80)

		// Execute every test, clearing possibly mutated wallet state after
		// each step.
		for _, walletTest := range walletTests {
			walletTest(miningNode, lnw, t)

			// TODO(roasbeef): possible reset mining node's chainstate to
			// initial level, cleanly wipe buckets
			if err := clearWalletState(lnw); err != nil &&
				err != bolt.ErrBucketNotFound {
				t.Fatalf("unable to wipe wallet state: %v", err)
			}
		}

		lnw.Shutdown()
	}
}


text:
class openh264:
    name = "libopenh264"
    proto = "git"
    url = "https://github.com/cisco/openh264.git"
    dirname = "" # leave empty to auto guess
    ffmpeg_opts = [ "--enable-libopenh264 " ]

    def has_builtin(self):
        return pkg_config_builtin("openh264");

    def skip(self, prefix, force):
        if force: return False;
        return pkg_config_exists("openh264");

    def configure(self, prefix):
        print(info("*** No need to run ./configure"));

    def make(self, prefix, opts):
        runcmd("make PREFIX={} {}".format(prefix, opts));

    def install(self, prefix):
        runcmd("make PREFIX={} install".format(prefix));

deps.append(openh264());

# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

redpajama_set_name: RedPajamaGithub


text:
Hello Rest World!

 We are here to understand how to implement a RestFul web-app
	with Jersey.

Say "hello world"

Generate WADL


text:
package org.apache.jena.tdb.store.tupletable;

import java.util.Iterator ;

import org.apache.jena.atlas.lib.ColumnMap ;
import org.apache.jena.atlas.lib.Tuple ;
import org.apache.jena.tdb.TDBException ;
import org.apache.jena.tdb.store.NodeId ;

public abstract class TupleIndexBase implements TupleIndex
{
    private static final boolean Check = false ;

    protected final ColumnMap colMap ;
    protected final int tupleLength ;

    private final String name ;

    protected TupleIndexBase(int N, ColumnMap colMapping, String name)
    {
        this.tupleLength = N ;
        this.colMap = colMapping ;
        this.name = name ;
    }

    /** Add tuple worker: Tuple passed in unmapped (untouched) order */
    protected abstract boolean performAdd(Tuple<NodeId> tuple) ;

    /** Delete tuple worker: Tuple passed in unmaped (untouched) order */
    protected abstract boolean performDelete(Tuple<NodeId> tuple) ;

    /** Find tuples worker: Tuple passed in unmaped (untouched) order */
    protected abstract Iterator<Tuple<NodeId>> performFind(Tuple<NodeId> tuple) ;

    /** Insert a tuple - return true if it was really added, false if it was a duplicate */
    @Override
    public final boolean add(Tuple<NodeId> tuple)
    {
        if ( Check )
        {
            if ( tupleLength != tuple.size() )
            throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", tuple.size(), tupleLength)) ;
        }
        return performAdd(tuple) ;
    }
    /** Delete a tuple - return true if it was deleted, false if it didn't exist */
    @Override
    public final boolean delete(Tuple<NodeId> tuple)
    {
        if ( Check )
        {
            if ( tupleLength != tuple.size() )
            throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", tuple.size(), tupleLength)) ;
        }

        return performDelete(tuple) ;
    }

    /** Find all matching tuples - a slot of NodeId.NodeIdAny (or null) means match any.
     *  Input pattern in natural order, not index order.
     */
    @Override
    public final Iterator<Tuple<NodeId>> find(Tuple<NodeId> pattern)
    {
        if ( Check )
        {
            if ( tupleLength != pattern.size() )
            throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", pattern.size(), tupleLength)) ;
        }
        // null to NodeId.NodIdAny ??
        return performFind(pattern) ;
    }

    @Override
    public final int weight(Tuple<NodeId> pattern)
    {
        for ( int i = 0 ; i < tupleLength ; i++ )
        {
            NodeId X = colMap.fetchSlot(i, pattern) ;
            if ( undef(X) )
                // End of fixed terms
                return i ;
        }
        return tupleLength ;
    }

    @Override
    public final String getMapping()          { return colMap.getLabel() ; }

    @Override
    public final String getName()           { return name ; }

    @Override
    public final int getTupleLength()       { return tupleLength ; }

    @Override
    public final ColumnMap getColumnMap()   { return colMap ;  }

    protected final boolean undef(NodeId x)
    { return NodeId.isAny(x) ; }

    @Override
    public String toString() { return "index:"+getName() ; }
}


text:
class AddDefOfActiveUsersToShipCardOwnerships < ActiveRecord::Migration[5.1]
  def change
    # アクティブユーザの定義を表す数値
    add_column :ship_card_ownerships, :def_of_active_users, :integer, after: :no_of_active_users, default: 0, null: false
  end
end


text:
/**
 * Created by Liuxz on 2017/7/11.
 */

public class Leet148SortList {
    public static void main(String[] args){
        ListNode head = new ListNode(4);
        head.next = new ListNode(19);
        head.next.next = new ListNode(14);
        head.next.next.next = new ListNode(5);
        head.next.next.next.next = new ListNode(-3);
        head.next.next.next.next.next = new ListNode(1);
        head.next.next.next.next.next.next = new ListNode(1);
        head.next.next.next.next.next.next.next = new ListNode(8);
        head.next.next.next.next.next.next.next.next = new ListNode(5);
        head.next.next.next.next.next.next.next.next.next = new ListNode(11);
        head.next.next.next.next.next.next.next.next.next.next = new ListNode(15);
        Leet148SortList xx = new Leet148SortList();
        head = xx.sortList(head);
        for (ListNode temp = head; temp != null; temp=temp.next){
            System.out.print(temp.val);
            System.out.print("->");
        }
    }

    public ListNode sortList(ListNode head) {
        int l = return_len(head);
        if (l <= 1){return head;}
        int step = l/2;
        ListNode cur = head;
        for (int i = 1 ; i < step ; i ++){
            cur = cur.next;
        }
        ListNode head_b = cur.next;
        cur.next = null;
        return merge(sortList(head), sortList(head_b));
    }

    private int return_len(ListNode node){
        ListNode cur = node;
        int len = 0;
        while(cur != null){
            len ++;
            cur = cur.next;
        }
        return len;
    }

    private ListNode merge(ListNode a, ListNode b){
        ListNode a_head = new ListNode(Integer.MIN_VALUE);
        a_head.next = a;
        for(ListNode a_cur = a_head, b_cur = b; b_cur!= null; ){
            if (((a_cur.next != null)&&(a_cur.val<=b_cur.val)&&(b_cur.val<=a_cur.next.val))||
                    ((a_cur.next == null)&&(a_cur.val<=b_cur.val))){
                ListNode temp_b = b_cur;
                b_cur = b_cur.next;
                temp_b.next = a_cur.next;
                a_cur.next = temp_b;
            }else{
                a_cur = a_cur.next;
            }
        }
        return a_head.next;
    }
}


text:
#region License

// Copyright (C) 2011-2015 Kazunori Sakamoto
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using System.Diagnostics.Contracts;
using System.Xml.Linq;
using Code2Xml.Core.Location;
using Code2Xml.Core.Serialization;

namespace Code2Xml.Core.SyntaxTree {
    public class AstToken : SyntaxTreeToken<AstToken> {
        public CodeRange? Range { get; set; }

        public int? StartPosition => Range?.StartPosition;
        public int? EndPosition => Range?.EndPosition;
        public int? StartLine => Range?.StartLine;
        public int? EndLine => Range?.EndLine;

        public AstToken(string name) : this(name, "") {}

        public AstToken(string name, string text) {
            Contract.Requires(name != null);
            Contract.Requires(text != null);
            Name = name;
            Text = text;
        }

        public AstToken(string name, string text, CodeRange range) {
            Contract.Requires(name != null);
            Contract.Requires(text != null);
            Name = name;
            Text = text;
            Range = range;
        }

        #region Inter-conversion between AstToken and XElement

        public XElement ToXml() {
            var element = new XElement(Name) { Value = Text };
            if (Range != null) {
                element.SetAttributeValue(
                        Code2XmlConstants.StartLineName, StartLine);
                element.SetAttributeValue(
                        Code2XmlConstants.StartPositionName, StartPosition);
                element.SetAttributeValue(
                        Code2XmlConstants.EndLineName, EndLine);
                element.SetAttributeValue(
                        Code2XmlConstants.EndPositionName, EndPosition);
            }
            return element;
        }

        public static AstToken FromXml(XElement element) {
            CodeRange range;
            if (CodeRange.TryParse(element, element, out range)) {
                return new AstToken(element.Name.LocalName, element.Value, range);
            }
            return new AstToken(element.Name.LocalName, element.Value);
        }

        #endregion

        #region Serialization / Deserialization

        public void Serialize(TextSerializer serializer) {
            serializer.Serialize(Name);
            serializer.Serialize(Text);
        }

        public static AstToken Deserialize(TextDeserializer deserializer) {
            var name = deserializer.DeserializeString();
            var text = deserializer.DeserializeString();
            return new AstToken(name, text);
        }

        #endregion

        public override string ToString() {
            return ToXml().ToString();
        }
    }
}


text:
package com.google.gerrit.server.patch;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.client.Project;
import java.util.List;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.lib.ObjectId;

@AutoValue
public abstract class IntraLineDiffArgs {
  public static IntraLineDiffArgs create(
      Text aText,
      Text bText,
      List<Edit> edits,
      Project.NameKey project,
      ObjectId commit,
      String path) {
    return new AutoValue_IntraLineDiffArgs(
        aText, bText, deepCopyEdits(edits), project, commit, path);
  }

  private static ImmutableList<Edit> deepCopyEdits(List<Edit> edits) {
    return edits.stream().map(IntraLineDiffArgs::copy).collect(ImmutableList.toImmutableList());
  }

  private static Edit copy(Edit edit) {
    return new Edit(edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB());
  }

  public abstract Text aText();

  public abstract Text bText();

  public abstract ImmutableList<Edit> edits();

  public abstract Project.NameKey project();

  public abstract ObjectId commit();

  public abstract String path();
}


text:
package com.graphhopper.http;

import com.graphhopper.util.Helper;
import com.graphhopper.util.TranslationMap;
import com.graphhopper.util.Translation;

import java.io.IOException;
import java.util.Locale;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static javax.servlet.http.HttpServletResponse.*;

import org.json.JSONObject;

/**
 * @author Peter Karich
 */
public class I18NServlet extends GHBaseServlet
{
    @Inject
    private TranslationMap map;

    @Override
    public void doGet( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException
    {
        String locale = "";
        String path = req.getPathInfo();
        if (!Helper.isEmpty(path) && path.startsWith("/"))
            locale = path.substring(1);

        if (Helper.isEmpty(locale))
        {
            // fall back to language specified in header e.g. via browser settings
            String acceptLang = req.getHeader("Accept-Language");
            if (!Helper.isEmpty(acceptLang))
                locale = acceptLang.split(",")[0];
        }

        Translation tr = map.get(locale);
        JSONObject json = new JSONObject();
        if (tr != null && !Locale.US.equals(tr.getLocale()))
            json.put("default", tr.asMap());

        json.put("locale", locale.toString());
        json.put("en", map.get("en").asMap());
        writeJson(req, res, json);
    }
}


text:
Here is the prototype of this project.
Create a very simple server on nodejs(express).

To start the server, open the cmd or terminal, direct to the project root

do npm install to get the node modules of the project

type in node server.js

Use link http://localhost:8081/#/ in the browser to Open the Application

This first login page is just a cover, doesn't make any sense

the User name and password is Sai and tmx;

After this, the true project landing page will be shown

With same username and password you can login


text:
package net.datenstrudel.bulbs.shared.domain.model.client.identity;

import javax.validation.constraints.Size;

/**
 *
 * @author Thomas Wendzinski
 */
public class DtoBulbsContextUser{

    //~ Member(s) //////////////////////////////////////////////////////////////
    @Size(min = 5, max = 128)
    private String email;
    @Size(min = 2, max = 16)
    private String nickname;
    @Size(min = 6, max = 64)
    private String password;
    private String apiKey;

    //~ Method(s) //////////////////////////////////////////////////////////////
    //~ Private Artifact(s) ////////////////////////////////////////////////////

    //~ Construction ///////////////////////////////////////////////////////////
    public DtoBulbsContextUser() {
    }

    public void clearDto(){
        setEmail(null);
        setNickname(null);
        setApiKey(null);
    }

    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }

    public String getNickname() {
        return nickname;
    }
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    public String getApiKey() {
        return apiKey;
    }
    public void setApiKey(String apiKey) {
        this.apiKey = apiKey;
    }

}


text:
<?php

class GetLevelTest extends TestCase
{
    public function setUp() {
        parent::setUp();
    }

    public function testLevelZero()
    {
        $this->userMock->points = -5;
        $this->assertEquals(0, $this->userMock->level[0]);
    }

    public function testLevelOne()
    {
        $this->userMock->points = 0;
        $this->assertEquals(1, $this->userMock->level[0]);
    }

    public function testLevelTwo()
    {
        $this->userMock = factory(App\User::class)->make();
        $this->userMock->points = 1;
        $this->assertEquals(1, $this->userMock->level[0]);
    }

    public function testLevelThree()
    {
        $this->userMock->points = 50;
        $this->assertEquals(2, $this->userMock->level[0]);
    }

    public function testLevelFour()
    {
        $this->userMock->points = 100;
        $this->assertEquals(3, $this->userMock->level[0]);
    }

    public function testLevelFive()
    {
        $this->userMock->points = 500;
        $this->assertEquals(4, $this->userMock->level[0]);
    }

}


text:
import vtk
from vtk.test import Testing
from vtk.util.misc import vtkGetDataRoot
VTK_DATA_ROOT = vtkGetDataRoot()

# Shift and scale an image (in that order)
# This filter is useful for converting to a lower precision data type.
reader = vtk.vtkImageReader()
reader.GetExecutive().SetReleaseDataFlag(0,0)
reader.SetDataByteOrderToLittleEndian()
reader.SetDataExtent(0,63,0,63,1,93)
reader.SetFilePrefix("" + str(VTK_DATA_ROOT) + "/Data/headsq/quarter")
reader.SetDataMask(0x7fff)
shiftScale = vtk.vtkImageShiftScale()
shiftScale.SetInputConnection(reader.GetOutputPort())
shiftScale.SetShift(0)
shiftScale.SetScale(0.5)
shiftScale.SetOutputScalarTypeToDouble()
shiftScale2 = vtk.vtkImageShiftScale()
shiftScale2.SetInputConnection(shiftScale.GetOutputPort())
shiftScale2.SetShift(0)
shiftScale2.SetScale(2.0)
mag = vtk.vtkImageMagnify()
mag.SetInputConnection(shiftScale2.GetOutputPort())
mag.SetMagnificationFactors(4,4,1)
mag.InterpolateOff()
viewer = vtk.vtkImageViewer()
viewer.SetInputConnection(mag.GetOutputPort())
viewer.SetColorWindow(1024)
viewer.SetColorLevel(1024)
#make interface
#skipping source
#vtkPNMWriter w
#w SetFileName "D:/vtknew/vtk/graphics/examplesTcl/mace2.ppm"
#w SetInputConnection [shiftScale GetOutputPort]
#w Write
# --- end of script --


text:
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdlib.h>
#include <string.h>

#if DYNLOAD_LIBEXPAT
# include <dlfcn.h>
#else
# if HAVE_LIBEXPAT
#  include <expat.h>
# endif
#endif

/* Keep the references to XML_GetCurrent{Line,Column}Number symbols
   before loading libexpat-compat.h, since they are redefined to
   rpl_XML_GetCurrent{Line,Column}Number .  */
#if !DYNLOAD_LIBEXPAT && XML_MAJOR_VERSION >= 2
static void *p_XML_GetCurrentLineNumber = (void *) &XML_GetCurrentLineNumber;
static void *p_XML_GetCurrentColumnNumber = (void *) &XML_GetCurrentColumnNumber;
#endif

#include "libexpat-compat.h"

/* ======================= Different libexpat ABIs.  ======================= */

/* There are three different ABIs of libexpat, regarding the functions
   XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber.
   In expat < 2.0, they return an 'int'.
   In expat >= 2.0, they return
     - a 'long' if expat was compiled with the default flags, or
     - a 'long long' if expat was compiled with -DXML_LARGE_SIZE.
   But the <expat.h> include file does not contain the information whether
   expat was compiled with -DXML_LARGE_SIZE; so the include file is lying!
   For this information, we need to call XML_GetFeatureList(), for
   expat >= 2.0.1; for expat = 2.0.0, we have to assume the default flags.  */

#if !DYNLOAD_LIBEXPAT && XML_MAJOR_VERSION >= 2

/* expat >= 2.0 -> Return type is 'int64_t' worst-case.  */

/* Return true if libexpat was compiled with -DXML_LARGE_SIZE.  */
static bool
is_XML_LARGE_SIZE_ABI (void)
{
  static bool tested;
  static bool is_large;

  if (!tested)
    {
      const XML_Feature *features;

      is_large = false;
      for (features = XML_GetFeatureList (); features->name != NULL; features++)
        if (strcmp (features->name, "XML_LARGE_SIZE") == 0)
          {
            is_large = true;
            break;
          }

      tested = true;
    }
  return is_large;
}

int64_t
rpl_XML_GetCurrentLineNumber (XML_Parser parser)
{
  if (is_XML_LARGE_SIZE_ABI ())
    return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
  else
    return ((long (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
}

int64_t
rpl_XML_GetCurrentColumnNumber (XML_Parser parser)
{
  if (is_XML_LARGE_SIZE_ABI ())
    return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
  else
    return ((long (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
}
#endif

/* ===================== Dynamic loading of libexpat.  ===================== */

#if DYNLOAD_LIBEXPAT

static XML_Expat_Version (*p_XML_ExpatVersionInfo) (void);

XML_Expat_Version
XML_ExpatVersionInfo (void)
{
  return (*p_XML_ExpatVersionInfo) ();
}

static const XML_Feature * (*p_XML_GetFeatureList) (void);

const XML_Feature *
XML_GetFeatureList (void)
{
  return (*p_XML_GetFeatureList) ();
}

enum XML_Size_ABI
get_XML_Size_ABI (void)
{
  static bool tested;
  static enum XML_Size_ABI abi;

  if (!tested)
    {
      if (XML_ExpatVersionInfo () .major >= 2)
        /* expat >= 2.0 -> XML_Size is 'int64_t' or 'long'.  */
        {
          const XML_Feature *features;

          abi = is_long;
          for (features = XML_GetFeatureList ();
               features->name != NULL;
               features++)
            if (strcmp (features->name, "XML_LARGE_SIZE") == 0)
              {
                abi = is_int64_t;
                break;
              }
        }
      else
        /* expat < 2.0 -> XML_Size is 'int'.  */
        abi = is_int;
      tested = true;
    }
  return abi;
}

static XML_Parser (*p_XML_ParserCreate) (const XML_Char *encoding);

XML_Parser
XML_ParserCreate (const XML_Char *encoding)
{
  return (*p_XML_ParserCreate) (encoding);
}

static void (*p_XML_SetElementHandler) (XML_Parser parser,
                                        XML_StartElementHandler start,
                                        XML_EndElementHandler end);

void
XML_SetElementHandler (XML_Parser parser,
                       XML_StartElementHandler start,
                       XML_EndElementHandler end)
{
  (*p_XML_SetElementHandler) (parser, start, end);
}

static void (*p_XML_SetCharacterDataHandler) (XML_Parser parser,
                                              XML_CharacterDataHandler handler);

void
XML_SetCharacterDataHandler (XML_Parser parser,
                             XML_CharacterDataHandler handler)
{
  (*p_XML_SetCharacterDataHandler) (parser, handler);
}

static void (*p_XML_SetCommentHandler) (XML_Parser parser,
                                        XML_CommentHandler handler);

void
XML_SetCommentHandler (XML_Parser parser, XML_CommentHandler handler)
{
  (*p_XML_SetCommentHandler) (parser, handler);
}

static int (*p_XML_Parse) (XML_Parser parser, const char *s,
                           int len, int isFinal);

int
XML_Parse (XML_Parser parser, const char *s, int len, int isFinal)
{
  return (*p_XML_Parse) (parser, s, len, isFinal);
}

static enum XML_Error (*p_XML_GetErrorCode) (XML_Parser parser);

enum XML_Error
XML_GetErrorCode (XML_Parser parser)
{
  return (*p_XML_GetErrorCode) (parser);
}

static void *p_XML_GetCurrentLineNumber;

int64_t
XML_GetCurrentLineNumber (XML_Parser parser)
{
  switch (get_XML_Size_ABI ())
    {
    case is_int:
      return ((int (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
    case is_long:
      return ((long (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
    case is_int64_t:
      return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
    default:
      abort ();
    }
}

static void *p_XML_GetCurrentColumnNumber;

int64_t
XML_GetCurrentColumnNumber (XML_Parser parser)
{
  switch (get_XML_Size_ABI ())
    {
    case is_int:
      return ((int (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
    case is_long:
      return ((long (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
    case is_int64_t:
      return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
    default:
      abort ();
    }
}

static const XML_LChar * (*p_XML_ErrorString) (int code);

const XML_LChar *
XML_ErrorString (int code)
{
  return (*p_XML_ErrorString) (code);
}

static void (*p_XML_ParserFree) (XML_Parser parser);

void
XML_ParserFree (XML_Parser parser)
{
  return (*p_XML_ParserFree) (parser);
}

static int libexpat_loaded = 0;

bool
load_libexpat ()
{
  if (libexpat_loaded == 0)
    {
      void *handle;

      /* Try to load libexpat-2.x.  */
      handle = dlopen ("libexpat.so.1", RTLD_LAZY);
      if (handle == NULL)
        /* Try to load libexpat-1.x.  */
        handle = dlopen ("libexpat.so.0", RTLD_LAZY);
      if (handle != NULL
          && (p_XML_ExpatVersionInfo =
                (XML_Expat_Version (*) (void))
                dlsym (handle, "XML_ExpatVersionInfo")) != NULL
          && (p_XML_GetFeatureList =
                (const XML_Feature * (*) (void))
                dlsym (handle, "XML_GetFeatureList")) != NULL
          && (p_XML_ParserCreate =
                (XML_Parser (*) (const XML_Char *))
                dlsym (handle, "XML_ParserCreate")) != NULL
          && (p_XML_SetElementHandler =
                (void (*) (XML_Parser, XML_StartElementHandler, XML_EndElementHandler))
                dlsym (handle, "XML_SetElementHandler")) != NULL
          && (p_XML_SetCharacterDataHandler =
                (void (*) (XML_Parser, XML_CharacterDataHandler))
                dlsym (handle, "XML_SetCharacterDataHandler")) != NULL
          && (p_XML_SetCommentHandler =
                (void (*) (XML_Parser, XML_CommentHandler))
                dlsym (handle, "XML_SetCommentHandler")) != NULL
          && (p_XML_Parse =
                (int (*) (XML_Parser, const char *, int, int))
                dlsym (handle, "XML_Parse")) != NULL
          && (p_XML_GetErrorCode =
                (enum XML_Error (*) (XML_Parser))
                dlsym (handle, "XML_GetErrorCode")) != NULL
          && (p_XML_GetCurrentLineNumber =
                dlsym (handle, "XML_GetCurrentLineNumber")) != NULL
          && (p_XML_GetCurrentColumnNumber =
                dlsym (handle, "XML_GetCurrentColumnNumber")) != NULL
          && (p_XML_ParserFree =
                (void (*) (XML_Parser))
                dlsym (handle, "XML_ParserFree")) != NULL
          && (p_XML_ErrorString =
                (const XML_LChar * (*) (int))
                dlsym (handle, "XML_ErrorString")) != NULL)
        libexpat_loaded = 1;
      else
        libexpat_loaded = -1;
    }
  return libexpat_loaded >= 0;
}

#endif


text:
class CProcessMonitor : public CLock
{
private:
    int            eyecatcher_;      // Debuggging aid -- leave as first
                                     // member variable of the class
public:
    typedef enum {
        PM_DISABLED=0,    // initial state
        PM_START,         // start timer
        PM_CHECK,         // check processes
        PM_STOP,          // stop timer
        PM_EXIT           // thread exit
    } PmState_t;

    CProcessMonitor();
    ~CProcessMonitor( void );

    void    MonitorProcesses( void );
    void    SetCheckMonitor( bool checkMonitor ) { CAutoLock lock(getLocker()); checkMonitor_ = checkMonitor; }
    void    SetState( PmState_t state ) { CAutoLock lock(getLocker()); state_ = state; }
    void    StartLunMgrMonitoring( int pid );
    void    StopLunMgrMonitoring( void );
    int     StartWorker( void );
    int     ShutdownWork( void );

protected:

private:
    void    CheckLunMgr( void );
    void    CheckMonitor( void );
    PmState_t GetState( void ) { CAutoLock lock(getLocker()); return( state_ ); }
    bool    IsEnabled( void ) { CAutoLock lock(getLocker()); return( enabled_ ); }
    bool    IsCheckLunMgr( void ) { CAutoLock lock(getLocker()); return( checkLunMgr_ ); }
    bool    IsCheckMonitor( void ) { CAutoLock lock(getLocker()); return( checkMonitor_ ); }
    bool    IsLunMgrTimerExpired( void );
    void    SetEnabled( bool enabled ) { CAutoLock lock(getLocker()); enabled_ = enabled; }
    void    SetCheckLunMgr( bool checkLunMgr ) { CAutoLock lock(getLocker()); checkLunMgr_ = checkLunMgr; }
    void    SetTimeToWakeUp( struct timespec &ts);
    void    StartProcessMonitoring( void );
    void    StopProcessMonitoring( void );

    PmState_t       state_;        // Physical node's current operating state
    bool            enabled_;      // true when process monitoring enabled
    bool            checkMonitor_; // true when monitor process monitoring enabled
    bool            checkLunMgr_;  // true when lunmgr process monitoring enabled
    int             lunMgrPid_;    // lunmgr process' pid
    int             monitorPid_;   // monitor process' pid
    long            pmMonitorRate_; // in nano seconds
    long            pmLunMgrHangDelay_; // in seconds
    struct timespec lunmgrIsHungTime_;  // lunmgr process started + hang delay
    struct timespec monitorCheckStart_; // time lunmgr process started
    pthread_t       threadId_;     // Softdog thread id

};

#endif // PROCMON_H


text:
namespace remoting {
namespace policy_hack {

namespace {

const FilePath::CharType kPolicyDir[] =
    FILE_PATH_LITERAL("/etc/opt/chrome/policies/managed");

// Amount of time we wait for the files on disk to settle before trying to load
// them. This alleviates the problem of reading partially written files and
// makes it possible to batch quasi-simultaneous changes.
const int kSettleIntervalSeconds = 5;

}  // namespace

class NatPolicyLinux : public NatPolicy {
 public:
  NatPolicyLinux(base::MessageLoopProxy* message_loop_proxy,
                 const FilePath& config_dir)
      : NatPolicy(message_loop_proxy),
        config_dir_(config_dir),
        ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
    // Detach the factory because we ensure that only the policy thread ever
    // calls methods on this. Also, the API contract of having to call
    // StopWatching() (which signals completion) after StartWatching()
    // before this object can be destructed ensures there are no users of
    // this object before it is destructed.
    weak_factory_.DetachFromThread();
  }

  virtual ~NatPolicyLinux() {}

 protected:
  virtual void StartWatchingInternal() OVERRIDE {
    DCHECK(OnPolicyThread());
    watcher_.reset(new base::files::FilePathWatcher());

    if (!config_dir_.empty() &&
        !watcher_->Watch(
            config_dir_,
            new FilePathWatcherDelegate(weak_factory_.GetWeakPtr()))) {
      OnFilePathError(config_dir_);
    }

    // There might have been changes to the directory in the time between
    // construction of the loader and initialization of the watcher. Call reload
    // to detect if that is the case.
    Reload();

    ScheduleFallbackReloadTask();
  }

  virtual void StopWatchingInternal() OVERRIDE {
    DCHECK(OnPolicyThread());
    // Cancel any inflight requests.
    watcher_.reset();
  }

  // Called by FilePathWatcherDelegate.
  virtual void OnFilePathError(const FilePath& path) {
    LOG(ERROR) << "NatPolicyLinux on " << path.value()
               << " failed.";
  }

  // Called by FilePathWatcherDelegate.
  virtual void OnFilePathChanged(const FilePath& path) {
    DCHECK(OnPolicyThread());

    Reload();
  }

 private:
  // Needed to avoid refcounting NatPolicyLinux.
  class FilePathWatcherDelegate :
    public base::files::FilePathWatcher::Delegate {
   public:
    FilePathWatcherDelegate(base::WeakPtr<NatPolicyLinux> policy_watcher)
        : policy_watcher_(policy_watcher) {
    }

    virtual void OnFilePathError(const FilePath& path) {
      if (policy_watcher_) {
        policy_watcher_->OnFilePathError(path);
      }
    }

    virtual void OnFilePathChanged(const FilePath& path) {
      if (policy_watcher_) {
        policy_watcher_->OnFilePathChanged(path);
      }
    }

   private:
    base::WeakPtr<NatPolicyLinux> policy_watcher_;
  };

  base::Time GetLastModification() {
    DCHECK(OnPolicyThread());
    base::Time last_modification = base::Time();
    base::PlatformFileInfo file_info;

    // If the path does not exist or points to a directory, it's safe to load.
    if (!file_util::GetFileInfo(config_dir_, &file_info) ||
        !file_info.is_directory) {
      return last_modification;
    }

    // Enumerate the files and find the most recent modification timestamp.
    file_util::FileEnumerator file_enumerator(config_dir_,
                                              false,
                                              file_util::FileEnumerator::FILES);
    for (FilePath config_file = file_enumerator.Next();
         !config_file.empty();
         config_file = file_enumerator.Next()) {
      if (file_util::GetFileInfo(config_file, &file_info) &&
          !file_info.is_directory) {
        last_modification = std::max(last_modification,
                                     file_info.last_modified);
      }
    }

    return last_modification;
  }

  // Caller owns the value.
  DictionaryValue* Load() {
    DCHECK(OnPolicyThread());
    // Enumerate the files and sort them lexicographically.
    std::set<FilePath> files;
    file_util::FileEnumerator file_enumerator(config_dir_, false,
                                              file_util::FileEnumerator::FILES);
    for (FilePath config_file_path = file_enumerator.Next();
         !config_file_path.empty(); config_file_path = file_enumerator.Next())
      files.insert(config_file_path);

    // Start with an empty dictionary and merge the files' contents.
    DictionaryValue* policy = new DictionaryValue();
    for (std::set<FilePath>::iterator config_file_iter = files.begin();
         config_file_iter != files.end(); ++config_file_iter) {
      JSONFileValueSerializer deserializer(*config_file_iter);
      int error_code = 0;
      std::string error_msg;
      scoped_ptr<Value> value(
          deserializer.Deserialize(&error_code, &error_msg));
      if (!value.get()) {
        LOG(WARNING) << "Failed to read configuration file "
                     << config_file_iter->value() << ": " << error_msg;
        continue;
      }
      if (!value->IsType(Value::TYPE_DICTIONARY)) {
        LOG(WARNING) << "Expected JSON dictionary in configuration file "
                     << config_file_iter->value();
        continue;
      }
      policy->MergeDictionary(static_cast<DictionaryValue*>(value.get()));
    }

    return policy;
  }

  void Reload() {
    DCHECK(OnPolicyThread());
    // Check the directory time in order to see whether a reload is required.
    base::TimeDelta delay;
    base::Time now = base::Time::Now();
    if (!IsSafeToReloadPolicy(now, &delay)) {
      ScheduleReloadTask(delay);
      return;
    }

    // Check again in case the directory has changed while reading it.
    if (!IsSafeToReloadPolicy(now, &delay)) {
      ScheduleReloadTask(delay);
      return;
    }

    // Load the policy definitions.
    scoped_ptr<DictionaryValue> new_policy(Load());
    UpdateNatPolicy(new_policy.get());

    ScheduleFallbackReloadTask();
  }

  bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay) {
    DCHECK(OnPolicyThread());
    DCHECK(delay);
    const base::TimeDelta kSettleInterval =
        base::TimeDelta::FromSeconds(kSettleIntervalSeconds);

    base::Time last_modification = GetLastModification();
    if (last_modification.is_null())
      return true;

    if (last_modification_file_.is_null())
      last_modification_file_ = last_modification;

    // If there was a change since the last recorded modification, wait some
    // more.
    if (last_modification != last_modification_file_) {
      last_modification_file_ = last_modification;
      last_modification_clock_ = now;
      *delay = kSettleInterval;
      return false;
    }

    // Check whether the settle interval has elapsed.
    base::TimeDelta age = now - last_modification_clock_;
    if (age < kSettleInterval) {
      *delay = kSettleInterval - age;
      return false;
    }

    return true;
  }

  // Managed with a scoped_ptr rather than being declared as an inline member to
  // decouple the watcher's life cycle from the NatPolicyLinux. This decoupling
  // makes it possible to destroy the watcher before the loader's destructor is
  // called (e.g. during Stop), since |watcher_| internally holds a reference to
  // the loader and keeps it alive.
  scoped_ptr<base::files::FilePathWatcher> watcher_;

  // Records last known modification timestamp of |config_dir_|.
  base::Time last_modification_file_;

  // The wall clock time at which the last modification timestamp was
  // recorded.  It's better to not assume the file notification time and the
  // wall clock times come from the same source, just in case there is some
  // non-local filesystem involved.
  base::Time last_modification_clock_;

  const FilePath config_dir_;

  // Allows us to cancel any inflight FileWatcher events or scheduled reloads.
  base::WeakPtrFactory<NatPolicyLinux> weak_factory_;
};

NatPolicy* NatPolicy::Create(base::MessageLoopProxy* message_loop_proxy) {
  FilePath policy_dir(kPolicyDir);
  return new NatPolicyLinux(message_loop_proxy, policy_dir);
}

}  // namespace policy_hack
}  // namespace remoting


text:
Run the Sails app in the current dir (if `node_modules/sails` exists, it will be used instead of the globally installed Sails)

##### Options:

  * `--dev` - in development environment (the default). In the development environment Sails use *grunt-watch* to keep a eye on your files in `/assets`. If you change something (for example in one of our css-files) and reload your browser Sails will automatically show your changes. Also you views won't be cached so you can change your view-files without restarting Sails like the assets.
  * `--prod` - in production environment
  * `--port <portNum>` - on the port specified by `portNum` instead of the default (1337)
  * `--verbose` - with verbose logging enabled
  * `--silly` - with insane logging enabled

### Example

```sh
$ sails lift

info: Starting app...

info:
info:
info:    Sails              <|
info:    v0.10.3             |\
info:                       /|.\
info:                      / || \
info:                    ,'  |'  \
info:                 .-'.-==|/_--'
info:                 `--'-------'
info:    __---___--___---___--___---___--___
info:  ____---___--___---___--___---___--___-__
info:
info: Server lifted in `/Users/mikermcneil/code/sandbox/second`
info: To see your app, visit http://localhost:1337
info: To shut down Sails, press <CTRL> + C at any time.

debug: --------------------------------------------------------
debug: :: Sat Apr 05 2014 17:03:39 GMT-0500 (CDT)

debug: Environment : development
debug: Port        : 1337
debug: --------------------------------------------------------
```

<docmeta name="uniqueID" value="sailslift482554">
<docmeta name="displayName" value="sails lift">


text:
<?xml version='1.0' encoding='UTF-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.google.cloud</groupId>
  <artifactId>containeranalysis-snippets</artifactId>
  <packaging>jar</packaging>
  <name>Google Cloud Container Analysis Snippets</name>
  <url>https://github.com/googleapis/java-containeranalysis</url>

  <!--
    The parent pom defines common style checks and testing strategies for our samples.
    Removing or replacing it should not affect the execution of the samples in anyway.
  -->
  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>

  <properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <!-- [START containeranalysis_install_with_bom] -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>libraries-bom</artifactId>
        <version>26.1.4</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-containeranalysis</artifactId>
    </dependency>
    <!-- [END containeranalysis_install_with_bom] -->

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.google.truth</groupId>
      <artifactId>truth</artifactId>
      <version>1.1.3</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>