From 1e5659e5f41680d2efafe24df422b924094d60d8 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 27 Mar 2018 00:00:24 -0400 Subject: [PATCH 01/14] routing: introduce routing hints to lightning payments In this commit, we add a new field of routing hints to payments over the Lightning Network. These routing hints can later be used within the path finding algorithm in order to craft a path that will reach the destination succesfully. --- routing/pathfind.go | 22 ++++++++++++++++++++++ routing/router.go | 10 ++++++++++ 2 files changed, 32 insertions(+) diff --git a/routing/pathfind.go b/routing/pathfind.go index 98874083..7867a41b 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -28,6 +28,28 @@ const ( infinity = math.MaxInt64 ) +// HopHint is a routing hint that contains the minimum information of a channel +// required for an intermediate hop in a route to forward the payment to the +// next. This should be ideally used for private channels, since they are not +// publicly advertised to the network for routing. +type HopHint struct { + // NodeID is the public key of the node at the start of the channel. + NodeID *btcec.PublicKey + + // ChannelID is the unique identifier of the channel. + ChannelID uint64 + + // FeeBaseMSat is the base fee of the channel in millisatoshis. + FeeBaseMSat uint32 + + // FeeProportionalMillionths is the fee rate, in millionths of a + // satoshi, for every satoshi sent through the channel. + FeeProportionalMillionths uint32 + + // CLTVExpiryDelta is the time-lock delta of the channel. + CLTVExpiryDelta uint16 +} + // ChannelHop is an intermediate hop within the network with a greater // multi-hop payment route. This struct contains the relevant routing policy of // the particular edge, as well as the total capacity, and origin chain of the diff --git a/routing/router.go b/routing/router.go index a6fa6085..4515555c 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1482,6 +1482,16 @@ type LightningPayment struct { // indefinitely. PayAttemptTimeout time.Duration + // RouteHints represents the different routing hints that can be used to + // assist a payment in reaching its destination successfully. These + // hints will act as intermediate hops along the route. + // + // NOTE: This is optional unless required by the payment. When providing + // multiple routes, ensure the hop hints within each route are chained + // together and sorted in forward order in order to reach the + // destination successfully. + RouteHints [][]HopHint + // TODO(roasbeef): add e2e message? } From 5ddee854795378e739470132250e2b3633242ca1 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 27 Mar 2018 00:03:15 -0400 Subject: [PATCH 02/14] routing: prevent logging the public key params within the routing hints --- routing/router.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/routing/router.go b/routing/router.go index 4515555c..13cb965a 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1505,7 +1505,14 @@ type LightningPayment struct { func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route, error) { log.Tracef("Dispatching route for lightning payment: %v", newLogClosure(func() string { + // Remove the public key curve parameters when logging + // the route to prevent spamming the logs. payment.Target.Curve = nil + for _, routeHint := range payment.RouteHints { + for _, hopHint := range routeHint { + hopHint.NodeID.Curve = nil + } + } return spew.Sdump(payment) }), ) From 7965247db1a04f780713ba72cebe212dd8baf2e9 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 26 Mar 2018 23:53:46 -0400 Subject: [PATCH 03/14] routing: add additionalEdges field to a missionControl's paymentSession In this commit, we introduce the ability for payment sessions to store an additional set of edges that can be used to assist a payment in successfully reaching its destination. --- routing/missioncontrol.go | 57 ++++++++++++++++++++++++++++++++++++--- routing/router.go | 4 ++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go index 8d8e595c..1c14dd4d 100644 --- a/routing/missioncontrol.go +++ b/routing/missioncontrol.go @@ -5,6 +5,8 @@ import ( "time" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/roasbeef/btcd/btcec" ) const ( @@ -148,20 +150,69 @@ func (m *missionControl) GraphPruneView() graphPruneView { // and will now be pruned after a decay like the main view within mission // control. We do this as we want to avoid the case where we continually try a // bad edge or route multiple times in a session. This can lead to an infinite -// loop if payment attempts take long enough. +// loop if payment attempts take long enough. An additional set of edges can +// also be provided to assist in reaching the payment's destination. type paymentSession struct { pruneViewSnapshot graphPruneView + additionalEdges map[Vertex][]*channeldb.ChannelEdgePolicy + mc *missionControl } // NewPaymentSession creates a new payment session backed by the latest prune -// view from Mission Control. -func (m *missionControl) NewPaymentSession() *paymentSession { +// view from Mission Control. An optional set of routing hints can be provided +// in order to populate additional edges to explore when finding a path to the +// payment's destination. +func (m *missionControl) NewPaymentSession(routeHints [][]HopHint, + target *btcec.PublicKey) *paymentSession { + viewSnapshot := m.GraphPruneView() + edges := make(map[Vertex][]*channeldb.ChannelEdgePolicy) + + // Traverse through all of the available hop hints and include them in + // our edges map, indexed by the public key of the channel's starting + // node. + for _, routeHint := range routeHints { + // If multiple hop hints are provided within a single route + // hint, we'll assume they must be chained together and sorted + // in forward order in order to reach the target successfully. + for i, hopHint := range routeHint { + // In order to determine the end node of this hint, + // we'll need to look at the next hint's start node. If + // we've reached the end of the hints list, we can + // assume we've reached the destination. + endNode := &channeldb.LightningNode{} + if i != len(routeHint)-1 { + endNode.AddPubKey(routeHint[i+1].NodeID) + } else { + endNode.AddPubKey(target) + } + + // Finally, create the channel edge from the hop hint + // and add it to list of edges corresponding to the node + // at the start of the channel. + edge := &channeldb.ChannelEdgePolicy{ + Node: endNode, + ChannelID: hopHint.ChannelID, + FeeBaseMSat: lnwire.MilliSatoshi( + hopHint.FeeBaseMSat, + ), + FeeProportionalMillionths: lnwire.MilliSatoshi( + hopHint.FeeProportionalMillionths, + ), + TimeLockDelta: hopHint.CLTVExpiryDelta, + } + + v := NewVertex(hopHint.NodeID) + edges[v] = append(edges[v], edge) + } + } + return &paymentSession{ pruneViewSnapshot: viewSnapshot, + additionalEdges: edges, mc: m, } } diff --git a/routing/router.go b/routing/router.go index 13cb965a..bb1e4b62 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1554,7 +1554,9 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte, *Route // Before starting the HTLC routing attempt, we'll create a fresh // payment session which will report our errors back to mission // control. - paySession := r.missionControl.NewPaymentSession() + paySession := r.missionControl.NewPaymentSession( + payment.RouteHints, payment.Target, + ) // We'll continue until either our payment succeeds, or we encounter a // critical error during path finding. From 4598df054ede0a8f236a043ead4c04b7a5f62535 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 27 Mar 2018 00:14:10 -0400 Subject: [PATCH 04/14] routing: modify findPath to take into account additional edges In this commit, we modify our path finding algorithm to take an additional set of edges that are currently not known to us that are used to temporarily extend our graph with during a payment session. These edges should assist the sender of a payment in successfully constructing a path to the destination. These edges should usually represent private channels, as they are not publicly advertised to the network for routing. --- routing/missioncontrol.go | 7 +- routing/pathfind.go | 169 ++++++++++++++++++++++---------------- routing/pathfind_test.go | 54 ++++++++---- routing/router_test.go | 4 +- 4 files changed, 142 insertions(+), 92 deletions(-) diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go index 1c14dd4d..02caf26c 100644 --- a/routing/missioncontrol.go +++ b/routing/missioncontrol.go @@ -282,8 +282,11 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment, // Taking into account this prune view, we'll attempt to locate a path // to our destination, respecting the recommendations from // missionControl. - path, err := findPath(nil, p.mc.graph, p.mc.selfNode, payment.Target, - pruneView.vertexes, pruneView.edges, payment.Amount) + path, err := findPath( + nil, p.mc.graph, p.additionalEdges, p.mc.selfNode, + payment.Target, pruneView.vertexes, pruneView.edges, + payment.Amount, + ) if err != nil { return nil, err } diff --git a/routing/pathfind.go b/routing/pathfind.go index 7867a41b..74743d65 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -455,6 +455,7 @@ func edgeWeight(amt lnwire.MilliSatoshi, e *channeldb.ChannelEdgePolicy) int64 { // function returns a slice of ChannelHop structs which encoded the chosen path // from the target to the source. func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph, + additionalEdges map[Vertex][]*channeldb.ChannelEdgePolicy, sourceNode *channeldb.LightningNode, target *btcec.PublicKey, ignoredNodes map[Vertex]struct{}, ignoredEdges map[uint64]struct{}, amt lnwire.MilliSatoshi) ([]*ChannelHop, error) { @@ -473,9 +474,8 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph, // traversal. var nodeHeap distanceHeap - // For each node/Vertex the graph we create an entry in the distance - // map for the node set with a distance of "infinity". We also mark - // add the node to our set of unvisited nodes. + // For each node in the graph, we create an entry in the distance + // map for the node set with a distance of "infinity". distance := make(map[Vertex]nodeWithDist) if err := graph.ForEachNode(tx, func(_ *bolt.Tx, node *channeldb.LightningNode) error { // TODO(roasbeef): with larger graph can just use disk seeks @@ -489,6 +489,86 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph, return nil, err } + // We'll also include all the nodes found within the additional edges + // that are not known to us yet in the distance map. + for vertex := range additionalEdges { + node := &channeldb.LightningNode{PubKeyBytes: vertex} + distance[vertex] = nodeWithDist{ + dist: infinity, + node: node, + } + } + + // We can't always assume that the end destination is publicly + // advertised to the network and included in the graph.ForEachNode call + // above, so we'll manually include the target node. + targetVertex := NewVertex(target) + targetNode := &channeldb.LightningNode{PubKeyBytes: targetVertex} + distance[targetVertex] = nodeWithDist{ + dist: infinity, + node: targetNode, + } + + // We'll use this map as a series of "previous" hop pointers. So to get + // to `Vertex` we'll take the edge that it's mapped to within `prev`. + prev := make(map[Vertex]edgeWithPrev) + + // processEdge is a helper closure that will be used to make sure edges + // satisfy our specific requirements. + processEdge := func(edge *channeldb.ChannelEdgePolicy, + capacity btcutil.Amount, pivot Vertex) { + + v := Vertex(edge.Node.PubKeyBytes) + + // If the edge is currently disabled, then we'll stop here, as + // we shouldn't attempt to route through it. + edgeFlags := lnwire.ChanUpdateFlag(edge.Flags) + if edgeFlags&lnwire.ChanUpdateDisabled != 0 { + return + } + + // If this vertex or edge has been black listed, then we'll skip + // exploring this edge. + if _, ok := ignoredNodes[v]; ok { + return + } + if _, ok := ignoredEdges[edge.ChannelID]; ok { + return + } + + // Compute the tentative distance to this new channel/edge which + // is the distance to our pivot node plus the weight of this + // edge. + tempDist := distance[pivot].dist + edgeWeight(amt, edge) + + // If this new tentative distance is better than the current + // best known distance to this node, then we record the new + // better distance, and also populate our "next hop" map with + // this edge. We'll also shave off irrelevant edges by adding + // the sufficient capacity of an edge and clearing their + // min-htlc amount to our relaxation condition. + if tempDist < distance[v].dist && capacity >= amt.ToSatoshis() && + amt >= edge.MinHTLC && edge.TimeLockDelta != 0 { + + distance[v] = nodeWithDist{ + dist: tempDist, + node: edge.Node, + } + + prev[v] = edgeWithPrev{ + edge: &ChannelHop{ + ChannelEdgePolicy: edge, + Capacity: capacity, + }, + prevNode: pivot, + } + + // Add this new node to our heap as we'd like to further + // explore down this edge. + heap.Push(&nodeHeap, distance[v]) + } + } + // TODO(roasbeef): also add path caching // * similar to route caching, but doesn't factor in the amount @@ -505,11 +585,6 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph, // heap. heap.Push(&nodeHeap, distance[sourceVertex]) - targetBytes := target.SerializeCompressed() - - // We'll use this map as a series of "previous" hop pointers. So to get - // to `Vertex` we'll take the edge that it's mapped to within `prev`. - prev := make(map[Vertex]edgeWithPrev) for nodeHeap.Len() != 0 { // Fetch the node within the smallest distance from our source // from the heap. @@ -519,7 +594,7 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph, // If we've reached our target (or we don't have any outgoing // edges), then we're done here and can exit the graph // traversal early. - if bytes.Equal(bestNode.PubKeyBytes[:], targetBytes) { + if bytes.Equal(bestNode.PubKeyBytes[:], targetVertex[:]) { break } @@ -529,65 +604,9 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph, pivot := Vertex(bestNode.PubKeyBytes) err := bestNode.ForEachChannel(tx, func(tx *bolt.Tx, edgeInfo *channeldb.ChannelEdgeInfo, - outEdge, inEdge *channeldb.ChannelEdgePolicy) error { + outEdge, _ *channeldb.ChannelEdgePolicy) error { - v := Vertex(outEdge.Node.PubKeyBytes) - - // If the outgoing edge is currently disabled, then - // we'll stop here, as we shouldn't attempt to route - // through it. - edgeFlags := lnwire.ChanUpdateFlag(outEdge.Flags) - if edgeFlags&lnwire.ChanUpdateDisabled == lnwire.ChanUpdateDisabled { - return nil - } - - // If this Vertex or edge has been black listed, then - // we'll skip exploring this edge during this - // iteration. - if _, ok := ignoredNodes[v]; ok { - return nil - } - if _, ok := ignoredEdges[outEdge.ChannelID]; ok { - return nil - } - - // Compute the tentative distance to this new - // channel/edge which is the distance to our current - // pivot node plus the weight of this edge. - tempDist := distance[pivot].dist + edgeWeight(amt, outEdge) - - // If this new tentative distance is better than the - // current best known distance to this node, then we - // record the new better distance, and also populate - // our "next hop" map with this edge. We'll also shave - // off irrelevant edges by adding the sufficient - // capacity of an edge and clearing their min-htlc - // amount to our relaxation condition. - if tempDist < distance[v].dist && - edgeInfo.Capacity >= amt.ToSatoshis() && - amt >= outEdge.MinHTLC && - outEdge.TimeLockDelta != 0 { - - distance[v] = nodeWithDist{ - dist: tempDist, - node: outEdge.Node, - } - prev[v] = edgeWithPrev{ - // We'll use the *incoming* edge here - // as we need to use the routing policy - // specified by the node this channel - // connects to. - edge: &ChannelHop{ - ChannelEdgePolicy: outEdge, - Capacity: edgeInfo.Capacity, - }, - prevNode: bestNode.PubKeyBytes, - } - - // Add this new node to our heap as we'd like - // to further explore down this edge. - heap.Push(&nodeHeap, distance[v]) - } + processEdge(outEdge, edgeInfo.Capacity, pivot) // TODO(roasbeef): return min HTLC as error in end? @@ -596,6 +615,15 @@ func findPath(tx *bolt.Tx, graph *channeldb.ChannelGraph, if err != nil { return nil, err } + + // Then, we'll examine all the additional edges from the node + // we're currently visiting. Since we don't know the capacity + // of the private channel, we'll assume it was selected as a + // routing hint due to having enough capacity for the payment + // and use the payment amount as its capacity. + for _, edge := range additionalEdges[bestNode.PubKeyBytes] { + processEdge(edge, amt.ToSatoshis(), pivot) + } } // If the target node isn't found in the prev hop map, then a path @@ -669,7 +697,8 @@ func findPaths(tx *bolt.Tx, graph *channeldb.ChannelGraph, // selfNode) to the target destination that's capable of carrying amt // satoshis along the path before fees are calculated. startingPath, err := findPath( - tx, graph, source, target, ignoredVertexes, ignoredEdges, amt, + tx, graph, nil, source, target, ignoredVertexes, ignoredEdges, + amt, ) if err != nil { log.Errorf("Unable to find path: %v", err) @@ -742,8 +771,8 @@ func findPaths(tx *bolt.Tx, graph *channeldb.ChannelGraph, // root path removed, we'll attempt to find another // shortest path from the spur node to the destination. spurPath, err := findPath( - tx, graph, spurNode, target, ignoredVertexes, - ignoredEdges, amt, + tx, graph, nil, spurNode, target, + ignoredVertexes, ignoredEdges, amt, ) // If we weren't able to find a path, we'll continue to diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 0a4d4eeb..b65e50e7 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -311,8 +311,10 @@ func TestBasicGraphPathFinding(t *testing.T) { paymentAmt := lnwire.NewMSatFromSatoshis(100) target := aliases["sophon"] - path, err := findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, paymentAmt) + path, err := findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, paymentAmt, + ) if err != nil { t.Fatalf("unable to find path: %v", err) } @@ -451,8 +453,10 @@ func TestBasicGraphPathFinding(t *testing.T) { // exist two possible paths in the graph, but the shorter (1 hop) path // should be selected. target = aliases["luoji"] - path, err = findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, paymentAmt) + path, err = findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, paymentAmt, + ) if err != nil { t.Fatalf("unable to find route: %v", err) } @@ -572,8 +576,10 @@ func TestNewRoutePathTooLong(t *testing.T) { // We start by confirming that routing a payment 20 hops away is possible. // Alice should be able to find a valid route to ursula. target := aliases["ursula"] - _, err = findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, paymentAmt) + _, err = findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, paymentAmt, + ) if err != nil { t.Fatalf("path should have been found") } @@ -581,8 +587,10 @@ func TestNewRoutePathTooLong(t *testing.T) { // Vincent is 21 hops away from Alice, and thus no valid route should be // presented to Alice. target = aliases["vincent"] - path, err := findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, paymentAmt) + path, err := findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, paymentAmt, + ) if err == nil { t.Fatalf("should not have been able to find path, supposed to be "+ "greater than 20 hops, found route with %v hops", @@ -621,8 +629,10 @@ func TestPathNotAvailable(t *testing.T) { t.Fatalf("unable to parse pubkey: %v", err) } - _, err = findPath(nil, graph, sourceNode, unknownNode, ignoredVertexes, - ignoredEdges, 100) + _, err = findPath( + nil, graph, nil, sourceNode, unknownNode, ignoredVertexes, + ignoredEdges, 100, + ) if !IsError(err, ErrNoPathFound) { t.Fatalf("path shouldn't have been found: %v", err) } @@ -655,8 +665,10 @@ func TestPathInsufficientCapacity(t *testing.T) { target := aliases["sophon"] payAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) - _, err = findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, payAmt) + _, err = findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, payAmt, + ) if !IsError(err, ErrNoPathFound) { t.Fatalf("graph shouldn't be able to support payment: %v", err) } @@ -683,8 +695,10 @@ func TestRouteFailMinHTLC(t *testing.T) { // attempt should fail. target := aliases["songoku"] payAmt := lnwire.MilliSatoshi(10) - _, err = findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, payAmt) + _, err = findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, payAmt, + ) if !IsError(err, ErrNoPathFound) { t.Fatalf("graph shouldn't be able to support payment: %v", err) } @@ -711,8 +725,10 @@ func TestRouteFailDisabledEdge(t *testing.T) { // succeed without issue, and return a single path. target := aliases["songoku"] payAmt := lnwire.NewMSatFromSatoshis(10000) - _, err = findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, payAmt) + _, err = findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, payAmt, + ) if err != nil { t.Fatalf("unable to find path: %v", err) } @@ -730,8 +746,10 @@ func TestRouteFailDisabledEdge(t *testing.T) { // Now, if we attempt to route through that edge, we should get a // failure as it is no longer eligible. - _, err = findPath(nil, graph, sourceNode, target, ignoredVertexes, - ignoredEdges, payAmt) + _, err = findPath( + nil, graph, nil, sourceNode, target, ignoredVertexes, + ignoredEdges, payAmt, + ) if !IsError(err, ErrNoPathFound) { t.Fatalf("graph shouldn't be able to support payment: %v", err) } diff --git a/routing/router_test.go b/routing/router_test.go index 8c73826e..b7029e67 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -1602,8 +1602,8 @@ func TestFindPathFeeWeighting(t *testing.T) { // the edge weighting, we should select the direct path over the 2 hop // path even though the direct path has a higher potential time lock. path, err := findPath( - nil, ctx.graph, sourceNode, target, ignoreVertex, ignoreEdge, - amt, + nil, ctx.graph, nil, sourceNode, target, ignoreVertex, + ignoreEdge, amt, ) if err != nil { t.Fatalf("unable to find path: %v", err) From beb08b3887fd8f63caf257d9531e3479cd767e86 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 27 Mar 2018 00:32:37 -0400 Subject: [PATCH 05/14] routing: add test for finding paths with additional edges --- routing/pathfind_test.go | 92 ++++++++++++++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 14 deletions(-) diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index b65e50e7..b2a31332 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -489,6 +489,69 @@ func TestBasicGraphPathFinding(t *testing.T) { } } +func TestPathFindingWithAdditionalEdges(t *testing.T) { + t.Parallel() + + graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) + defer cleanUp() + if err != nil { + t.Fatalf("unable to create graph: %v", err) + } + + sourceNode, err := graph.SourceNode() + if err != nil { + t.Fatalf("unable to fetch source node: %v", err) + } + + paymentAmt := lnwire.NewMSatFromSatoshis(100) + + // In this test, we'll test that we're able to find paths through + // private channels when providing them as additional edges in our path + // finding algorithm. To do so, we'll create a new node, doge, and + // create a private channel between it and songoku. We'll then attempt + // to find a path from our source node, roasbeef, to doge. + dogePubKeyHex := "03dd46ff29a6941b4a2607525b043ec9b020b3f318a1bf281536fd7011ec59c882" + dogePubKeyBytes, err := hex.DecodeString(dogePubKeyHex) + if err != nil { + t.Fatalf("unable to decode public key: %v", err) + } + dogePubKey, err := btcec.ParsePubKey(dogePubKeyBytes, btcec.S256()) + if err != nil { + t.Fatalf("unable to parse public key from bytes: %v", err) + } + + doge := &channeldb.LightningNode{} + doge.AddPubKey(dogePubKey) + doge.Alias = "doge" + + // Create the channel edge going from songoku to doge and include it in + // our map of additional edges. + songokuToDoge := &channeldb.ChannelEdgePolicy{ + Node: doge, + ChannelID: 1337, + FeeBaseMSat: 1, + FeeProportionalMillionths: 1000, + TimeLockDelta: 9, + } + + additionalEdges := map[Vertex][]*channeldb.ChannelEdgePolicy{ + NewVertex(aliases["songoku"]): {songokuToDoge}, + } + + // We should now be able to find a path from roasbeef to doge. + path, err := findPath( + nil, graph, additionalEdges, sourceNode, dogePubKey, nil, nil, + paymentAmt, + ) + if err != nil { + t.Fatalf("unable to find private path to doge: %v", err) + } + + // The path should represent the following hops: + // roasbeef -> songoku -> doge + assertExpectedPath(t, path, "songoku", "doge") +} + func TestKShortestPathFinding(t *testing.T) { t.Parallel() @@ -533,23 +596,11 @@ func TestKShortestPathFinding(t *testing.T) { t.Fatalf("paths found not ordered properly") } - // Finally, we'll assert the exact expected ordering of both paths - // found. - assertExpectedPath := func(path []*ChannelHop, nodeAliases ...string) { - for i, hop := range path { - if hop.Node.Alias != nodeAliases[i] { - t.Fatalf("expected %v to be pos #%v in hop, "+ - "instead %v was", nodeAliases[i], i, - hop.Node.Alias) - } - } - } - // The first route should be a direct route to luo ji. - assertExpectedPath(paths[0], "roasbeef", "luoji") + assertExpectedPath(t, paths[0], "roasbeef", "luoji") // The second route should be a route to luo ji via satoshi. - assertExpectedPath(paths[1], "roasbeef", "satoshi", "luoji") + assertExpectedPath(t, paths[1], "roasbeef", "satoshi", "luoji") } func TestNewRoutePathTooLong(t *testing.T) { @@ -985,3 +1036,16 @@ func TestPathFindSpecExample(t *testing.T) { startingHeight+DefaultFinalCLTVDelta) } } + +func assertExpectedPath(t *testing.T, path []*ChannelHop, nodeAliases ...string) { + if len(path) != len(nodeAliases) { + t.Fatal("number of hops and number of aliases do not match") + } + + for i, hop := range path { + if hop.Node.Alias != nodeAliases[i] { + t.Fatalf("expected %v to be pos #%v in hop, instead "+ + "%v was", nodeAliases[i], i, hop.Node.Alias) + } + } +} From ea9e609ef0c203d5cc3b2c1c20c9efdf7fd650cc Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 27 Mar 2018 00:42:35 -0400 Subject: [PATCH 06/14] zpay32: modify an invoice's `r` field to allow multiple routes Before this commit, if an invoice encoded multiple `r` fields, we would decode them as one single route. We fix this by allowing an invoice to store multiple routes. --- zpay32/invoice.go | 148 +++++++++++++++++--------------- zpay32/invoice_internal_test.go | 29 ++++--- zpay32/invoice_test.go | 85 ++++++++++-------- 3 files changed, 141 insertions(+), 121 deletions(-) diff --git a/zpay32/invoice.go b/zpay32/invoice.go index fc9f7d81..ffed10fd 100644 --- a/zpay32/invoice.go +++ b/zpay32/invoice.go @@ -37,9 +37,9 @@ const ( // with zeroes. pubKeyBase32Len = 53 - // routingInfoLen is the number of bytes needed to encode the extra - // routing info of a single private route. - routingInfoLen = 51 + // hopHintLen is the number of bytes needed to encode the hop hint of a + // single private route. + hopHintLen = 51 // The following byte values correspond to the supported field types. // The field name is the character representing that 5-bit value in the @@ -141,31 +141,12 @@ type Invoice struct { // Optional. FallbackAddr btcutil.Address - // RoutingInfo is one or more entries containing extra routing - // information for a private route to the target node. - // Optional. - RoutingInfo []ExtraRoutingInfo -} - -// ExtraRoutingInfo holds the information needed to route a payment along one -// private channel. -type ExtraRoutingInfo struct { - // PubKey is the public key of the node at the start of this channel. - PubKey *btcec.PublicKey - - // ShortChanID is the channel ID of the channel. - ShortChanID uint64 - - // FeeBaseMsat is the base fee in millisatoshis required for routing - // along this channel. - FeeBaseMsat uint32 - - // FeeProportionalMillionths is the proportional fee in millionths of a - // satoshi required for routing along this channel. - FeeProportionalMillionths uint32 - - // CltvExpDelta is this channel's cltv expiry delta. - CltvExpDelta uint16 + // RouteHints represents one or more different route hints. Each route + // hint can be individually used to reach the destination. These usually + // represent private routes. + // + // NOTE: This is optional. + RouteHints [][]routing.HopHint } // Amount is a functional option that allows callers of NewInvoice to set the @@ -231,12 +212,11 @@ func FallbackAddr(fallbackAddr btcutil.Address) func(*Invoice) { } } -// RoutingInfo is a functional option that allows callers of NewInvoice to set -// one or more entries containing extra routing information for a private route -// to the target node. -func RoutingInfo(routingInfo []ExtraRoutingInfo) func(*Invoice) { +// RouteHint is a functional option that allows callers of NewInvoice to add +// one or more hop hints that represent a private route to the destination. +func RouteHint(routeHint []routing.HopHint) func(*Invoice) { return func(i *Invoice) { - i.RoutingInfo = routingInfo + i.RouteHints = append(i.RouteHints, routeHint) } } @@ -525,10 +505,19 @@ func validateInvoice(invoice *Invoice) error { return fmt.Errorf("neither description nor description hash set") } - // Can have at most 20 extra hops for routing. - if len(invoice.RoutingInfo) > 20 { - return fmt.Errorf("too many extra hops: %d", - len(invoice.RoutingInfo)) + // We'll restrict invoices to include up to 20 different private route + // hints. We do this to avoid overly large invoices. + if len(invoice.RouteHints) > 20 { + return fmt.Errorf("too many private routes: %d", + len(invoice.RouteHints)) + } + + // Each route hint can have at most 20 hops. + for i, routeHint := range invoice.RouteHints { + if len(routeHint) > 20 { + return fmt.Errorf("route hint %d has too many extra "+ + "hops: %d", i, len(routeHint)) + } } // Check that we support the field lengths. @@ -666,13 +655,15 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er invoice.FallbackAddr, err = parseFallbackAddr(base32Data, net) case fieldTypeR: - if invoice.RoutingInfo != nil { - // We skip the field if we have already seen a - // supported one. - continue + // An `r` field can be included in an invoice multiple + // times, so we won't skip it if we have already seen + // one. + routeHint, err := parseRouteHint(base32Data) + if err != nil { + return err } - invoice.RoutingInfo, err = parseRoutingInfo(base32Data) + invoice.RouteHints = append(invoice.RouteHints, routeHint) default: // Ignore unknown type. } @@ -850,35 +841,38 @@ func parseFallbackAddr(data []byte, net *chaincfg.Params) (btcutil.Address, erro return addr, nil } -// parseRoutingInfo converts the data (encoded in base32) into an array -// containing one or more entries of extra routing info. -func parseRoutingInfo(data []byte) ([]ExtraRoutingInfo, error) { +// parseRouteHint converts the data (encoded in base32) into an array containing +// one or more routing hop hints that represent a single route hint. +func parseRouteHint(data []byte) ([]routing.HopHint, error) { base256Data, err := bech32.ConvertBits(data, 5, 8, false) if err != nil { return nil, err } - if len(base256Data)%routingInfoLen != 0 { - return nil, fmt.Errorf("expected length multiple of %d bytes, got %d", - routingInfoLen, len(base256Data)) + if len(base256Data)%hopHintLen != 0 { + return nil, fmt.Errorf("expected length multiple of %d bytes, "+ + "got %d", hopHintLen, len(base256Data)) } - var routingInfo []ExtraRoutingInfo - info := ExtraRoutingInfo{} + var routeHint []routing.HopHint + for len(base256Data) > 0 { - info.PubKey, err = btcec.ParsePubKey(base256Data[:33], btcec.S256()) + hopHint := routing.HopHint{} + hopHint.NodeID, err = btcec.ParsePubKey(base256Data[:33], btcec.S256()) if err != nil { return nil, err } - info.ShortChanID = binary.BigEndian.Uint64(base256Data[33:41]) - info.FeeBaseMsat = binary.BigEndian.Uint32(base256Data[41:45]) - info.FeeProportionalMillionths = binary.BigEndian.Uint32(base256Data[45:49]) - info.CltvExpDelta = binary.BigEndian.Uint16(base256Data[49:51]) - routingInfo = append(routingInfo, info) + hopHint.ChannelID = binary.BigEndian.Uint64(base256Data[33:41]) + hopHint.FeeBaseMSat = binary.BigEndian.Uint32(base256Data[41:45]) + hopHint.FeeProportionalMillionths = binary.BigEndian.Uint32(base256Data[45:49]) + hopHint.CLTVExpiryDelta = binary.BigEndian.Uint16(base256Data[49:51]) + + routeHint = append(routeHint, hopHint) + base256Data = base256Data[51:] } - return routingInfo, nil + return routeHint, nil } // writeTaggedFields writes the non-nil tagged fields of the Invoice to the @@ -977,25 +971,37 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error { } } - if len(invoice.RoutingInfo) > 0 { - // Each extra routing info is encoded using 51 bytes. - routingDataBase256 := make([]byte, 0, 51*len(invoice.RoutingInfo)) - for _, r := range invoice.RoutingInfo { - base256 := make([]byte, 51) - copy(base256[:33], r.PubKey.SerializeCompressed()) - binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID) - binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat) - binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths) - binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta) - routingDataBase256 = append(routingDataBase256, base256...) + for _, routeHint := range invoice.RouteHints { + // Each hop hint is encoded using 51 bytes, so we'll make to + // sure to allocate enough space for the whole route hint. + routeHintBase256 := make([]byte, 0, hopHintLen*len(routeHint)) + + for _, hopHint := range routeHint { + hopHintBase256 := make([]byte, hopHintLen) + copy(hopHintBase256[:33], hopHint.NodeID.SerializeCompressed()) + binary.BigEndian.PutUint64( + hopHintBase256[33:41], hopHint.ChannelID, + ) + binary.BigEndian.PutUint32( + hopHintBase256[41:45], hopHint.FeeBaseMSat, + ) + binary.BigEndian.PutUint32( + hopHintBase256[45:49], hopHint.FeeProportionalMillionths, + ) + binary.BigEndian.PutUint16( + hopHintBase256[49:51], hopHint.CLTVExpiryDelta, + ) + routeHintBase256 = append(routeHintBase256, hopHintBase256...) } - routingDataBase32, err := bech32.ConvertBits(routingDataBase256, - 8, 5, true) + + routeHintBase32, err := bech32.ConvertBits( + routeHintBase256, 8, 5, true, + ) if err != nil { return err } - err = writeTaggedField(bufferBase32, fieldTypeR, routingDataBase32) + err = writeTaggedField(bufferBase32, fieldTypeR, routeHintBase32) if err != nil { return err } diff --git a/zpay32/invoice_internal_test.go b/zpay32/invoice_internal_test.go index 613c3a13..cee1b5e0 100644 --- a/zpay32/invoice_internal_test.go +++ b/zpay32/invoice_internal_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/routing" "github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/chaincfg" "github.com/roasbeef/btcutil" @@ -706,18 +707,18 @@ func TestParseFallbackAddr(t *testing.T) { } } -// TestParseRoutingInfo checks that the routing info is properly parsed. -func TestParseRoutingInfo(t *testing.T) { +// TestParseRouteHint checks that the routing info is properly parsed. +func TestParseRouteHint(t *testing.T) { t.Parallel() var testSingleHopData []byte for _, r := range testSingleHop { base256 := make([]byte, 51) - copy(base256[:33], r.PubKey.SerializeCompressed()) - binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID) - binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat) + copy(base256[:33], r.NodeID.SerializeCompressed()) + binary.BigEndian.PutUint64(base256[33:41], r.ChannelID) + binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMSat) binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths) - binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta) + binary.BigEndian.PutUint16(base256[49:51], r.CLTVExpiryDelta) testSingleHopData = append(testSingleHopData, base256...) } testSingleHopData, _ = bech32.ConvertBits(testSingleHopData, 8, 5, true) @@ -725,11 +726,11 @@ func TestParseRoutingInfo(t *testing.T) { var testDoubleHopData []byte for _, r := range testDoubleHop { base256 := make([]byte, 51) - copy(base256[:33], r.PubKey.SerializeCompressed()) - binary.BigEndian.PutUint64(base256[33:41], r.ShortChanID) - binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMsat) + copy(base256[:33], r.NodeID.SerializeCompressed()) + binary.BigEndian.PutUint64(base256[33:41], r.ChannelID) + binary.BigEndian.PutUint32(base256[41:45], r.FeeBaseMSat) binary.BigEndian.PutUint32(base256[45:49], r.FeeProportionalMillionths) - binary.BigEndian.PutUint16(base256[49:51], r.CltvExpDelta) + binary.BigEndian.PutUint16(base256[49:51], r.CLTVExpiryDelta) testDoubleHopData = append(testDoubleHopData, base256...) } testDoubleHopData, _ = bech32.ConvertBits(testDoubleHopData, 8, 5, true) @@ -737,7 +738,7 @@ func TestParseRoutingInfo(t *testing.T) { tests := []struct { data []byte valid bool - result []ExtraRoutingInfo + result []routing.HopHint }{ { data: []byte{0x0, 0x0, 0x0, 0x0}, @@ -746,7 +747,7 @@ func TestParseRoutingInfo(t *testing.T) { { data: []byte{}, valid: true, - result: []ExtraRoutingInfo{}, + result: []routing.HopHint{}, }, { data: testSingleHopData, @@ -765,13 +766,13 @@ func TestParseRoutingInfo(t *testing.T) { } for i, test := range tests { - routingInfo, err := parseRoutingInfo(test.data) + routeHint, err := parseRouteHint(test.data) if (err == nil) != test.valid { t.Errorf("routing info decoding test %d failed: %v", i, err) return } if test.valid { - if err := compareRoutingInfos(test.result, routingInfo); err != nil { + if err := compareRouteHints(test.result, routeHint); err != nil { t.Fatalf("test %d failed decoding routing info: %v", i, err) } } diff --git a/zpay32/invoice_test.go b/zpay32/invoice_test.go index 78ede39f..e52d6098 100644 --- a/zpay32/invoice_test.go +++ b/zpay32/invoice_test.go @@ -12,6 +12,7 @@ import ( "time" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/routing" "github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/chaincfg" "github.com/roasbeef/btcd/chaincfg/chainhash" @@ -47,34 +48,34 @@ var ( testAddrMainnetP2WPKH, _ = btcutil.DecodeAddress("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", &chaincfg.MainNetParams) testAddrMainnetP2WSH, _ = btcutil.DecodeAddress("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", &chaincfg.MainNetParams) - testRoutingInfoPubkeyBytes, _ = hex.DecodeString("029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255") - testRoutingInfoPubkey, _ = btcec.ParsePubKey(testRoutingInfoPubkeyBytes, btcec.S256()) - testRoutingInfoPubkeyBytes2, _ = hex.DecodeString("039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255") - testRoutingInfoPubkey2, _ = btcec.ParsePubKey(testRoutingInfoPubkeyBytes2, btcec.S256()) + testHopHintPubkeyBytes1, _ = hex.DecodeString("029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255") + testHopHintPubkey1, _ = btcec.ParsePubKey(testHopHintPubkeyBytes1, btcec.S256()) + testHopHintPubkeyBytes2, _ = hex.DecodeString("039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255") + testHopHintPubkey2, _ = btcec.ParsePubKey(testHopHintPubkeyBytes2, btcec.S256()) - testSingleHop = []ExtraRoutingInfo{ + testSingleHop = []routing.HopHint{ { - PubKey: testRoutingInfoPubkey, - ShortChanID: 0x0102030405060708, - FeeBaseMsat: 0, + NodeID: testHopHintPubkey1, + ChannelID: 0x0102030405060708, + FeeBaseMSat: 0, FeeProportionalMillionths: 20, - CltvExpDelta: 3, + CLTVExpiryDelta: 3, }, } - testDoubleHop = []ExtraRoutingInfo{ + testDoubleHop = []routing.HopHint{ { - PubKey: testRoutingInfoPubkey, - ShortChanID: 0x0102030405060708, - FeeBaseMsat: 1, + NodeID: testHopHintPubkey1, + ChannelID: 0x0102030405060708, + FeeBaseMSat: 1, FeeProportionalMillionths: 20, - CltvExpDelta: 3, + CLTVExpiryDelta: 3, }, { - PubKey: testRoutingInfoPubkey2, - ShortChanID: 0x030405060708090a, - FeeBaseMsat: 2, + NodeID: testHopHintPubkey2, + ChannelID: 0x030405060708090a, + FeeBaseMSat: 2, FeeProportionalMillionths: 30, - CltvExpDelta: 4, + CLTVExpiryDelta: 4, }, } @@ -413,7 +414,7 @@ func TestDecodeEncode(t *testing.T) { DescriptionHash: &testDescriptionHash, Destination: testPubKey, FallbackAddr: testRustyAddr, - RoutingInfo: testSingleHop, + RouteHints: [][]routing.HopHint{testSingleHop}, } }, beforeEncoding: func(i *Invoice) { @@ -436,7 +437,7 @@ func TestDecodeEncode(t *testing.T) { DescriptionHash: &testDescriptionHash, Destination: testPubKey, FallbackAddr: testRustyAddr, - RoutingInfo: testDoubleHop, + RouteHints: [][]routing.HopHint{testDoubleHop}, } }, beforeEncoding: func(i *Invoice) { @@ -680,7 +681,7 @@ func TestNewInvoice(t *testing.T) { Amount(testMillisat20mBTC), DescriptionHash(testDescriptionHash), FallbackAddr(testRustyAddr), - RoutingInfo(testDoubleHop), + RouteHint(testDoubleHop), ) }, valid: true, @@ -802,7 +803,19 @@ func compareInvoices(expected, actual *Invoice) error { expected.FallbackAddr, actual.FallbackAddr) } - return compareRoutingInfos(expected.RoutingInfo, actual.RoutingInfo) + if len(expected.RouteHints) != len(actual.RouteHints) { + return fmt.Errorf("expected %d RouteHints, got %d", + len(expected.RouteHints), len(actual.RouteHints)) + } + + for i, routeHint := range expected.RouteHints { + err := compareRouteHints(routeHint, actual.RouteHints[i]) + if err != nil { + return err + } + } + + return nil } func comparePubkeys(a, b *btcec.PublicKey) bool { @@ -831,36 +844,36 @@ func compareHashes(a, b *[32]byte) bool { return bytes.Equal(a[:], b[:]) } -func compareRoutingInfos(a, b []ExtraRoutingInfo) error { +func compareRouteHints(a, b []routing.HopHint) error { if len(a) != len(b) { return fmt.Errorf("expected len routingInfo %d, got %d", len(a), len(b)) } for i := 0; i < len(a); i++ { - if !comparePubkeys(a[i].PubKey, b[i].PubKey) { - return fmt.Errorf("expected routingInfo pubkey %x, "+ - "got %x", a[i].PubKey, b[i].PubKey) + if !comparePubkeys(a[i].NodeID, b[i].NodeID) { + return fmt.Errorf("expected routeHint nodeID %x, "+ + "got %x", a[i].NodeID, b[i].NodeID) } - if a[i].ShortChanID != b[i].ShortChanID { - return fmt.Errorf("expected routingInfo shortChanID "+ - "%d, got %d", a[i].ShortChanID, b[i].ShortChanID) + if a[i].ChannelID != b[i].ChannelID { + return fmt.Errorf("expected routeHint channelID "+ + "%d, got %d", a[i].ChannelID, b[i].ChannelID) } - if a[i].FeeBaseMsat != b[i].FeeBaseMsat { - return fmt.Errorf("expected routingInfo feeBaseMsat %d, got %d", - a[i].FeeBaseMsat, b[i].FeeBaseMsat) + if a[i].FeeBaseMSat != b[i].FeeBaseMSat { + return fmt.Errorf("expected routeHint feeBaseMsat %d, got %d", + a[i].FeeBaseMSat, b[i].FeeBaseMSat) } if a[i].FeeProportionalMillionths != b[i].FeeProportionalMillionths { - return fmt.Errorf("expected routingInfo feeProportionalMillionths %d, got %d", + return fmt.Errorf("expected routeHint feeProportionalMillionths %d, got %d", a[i].FeeProportionalMillionths, b[i].FeeProportionalMillionths) } - if a[i].CltvExpDelta != b[i].CltvExpDelta { - return fmt.Errorf("expected routingInfo cltvExpDelta "+ - "%d, got %d", a[i].CltvExpDelta, b[i].CltvExpDelta) + if a[i].CLTVExpiryDelta != b[i].CLTVExpiryDelta { + return fmt.Errorf("expected routeHint cltvExpiryDelta "+ + "%d, got %d", a[i].CLTVExpiryDelta, b[i].CLTVExpiryDelta) } } From 6394c2fbb53630347b0e3dd22c132f21bf870675 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 27 Mar 2018 23:45:22 -0400 Subject: [PATCH 07/14] lnrpc: add route hints proto field to invoices --- lnrpc/rpc.pb.go | 870 +++++++++++++++++++++++------------------ lnrpc/rpc.pb.gw.go | 84 ++-- lnrpc/rpc.proto | 35 ++ lnrpc/rpc.swagger.json | 62 ++- 4 files changed, 606 insertions(+), 445 deletions(-) diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 41a9185e..5f8377a4 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -82,6 +82,8 @@ It has these top-level messages: NodeUpdate ChannelEdgeUpdate ClosedChannelUpdate + HopHint + RouteHint Invoice AddInvoiceResponse PaymentHash @@ -519,9 +521,7 @@ func (m *ChannelPoint) String() string { return proto.CompactTextStri func (*ChannelPoint) ProtoMessage() {} func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } -type isChannelPoint_FundingTxid interface { - isChannelPoint_FundingTxid() -} +type isChannelPoint_FundingTxid interface{ isChannelPoint_FundingTxid() } type ChannelPoint_FundingTxidBytes struct { FundingTxidBytes []byte `protobuf:"bytes,1,opt,name=funding_txid_bytes,proto3,oneof"` @@ -1608,9 +1608,7 @@ func (m *CloseStatusUpdate) String() string { return proto.CompactTex func (*CloseStatusUpdate) ProtoMessage() {} func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} } -type isCloseStatusUpdate_Update interface { - isCloseStatusUpdate_Update() -} +type isCloseStatusUpdate_Update interface{ isCloseStatusUpdate_Update() } type CloseStatusUpdate_ClosePending struct { ClosePending *PendingUpdate `protobuf:"bytes,1,opt,name=close_pending,oneof"` @@ -1873,9 +1871,7 @@ func (m *OpenStatusUpdate) String() string { return proto.CompactText func (*OpenStatusUpdate) ProtoMessage() {} func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} } -type isOpenStatusUpdate_Update interface { - isOpenStatusUpdate_Update() -} +type isOpenStatusUpdate_Update interface{ isOpenStatusUpdate_Update() } type OpenStatusUpdate_ChanPending struct { ChanPending *PendingUpdate `protobuf:"bytes,1,opt,name=chan_pending,oneof"` @@ -2808,7 +2804,7 @@ func (m *RoutingPolicy) GetFeeRateMilliMsat() int64 { // * // A fully authenticated channel along with all its unique attributes. // Once an authenticated channel announcement has been processed on the network, -// then a instance of ChannelEdgeInfo encapsulating the channels attributes is +// then an instance of ChannelEdgeInfo encapsulating the channels attributes is // stored. The other portions relevant to routing policy of a channel are stored // within a ChannelEdgePolicy for each direction of the channel. type ChannelEdge struct { @@ -3230,6 +3226,80 @@ func (m *ClosedChannelUpdate) GetChanPoint() *ChannelPoint { return nil } +type HopHint struct { + // / The public key of the node at the start of the channel. + NodeId string `protobuf:"bytes,1,opt,name=node_id" json:"node_id,omitempty"` + // / The unique identifier of the channel. + ChanId uint64 `protobuf:"varint,2,opt,name=chan_id" json:"chan_id,omitempty"` + // / The base fee of the channel denominated in millisatoshis. + FeeBaseMsat uint32 `protobuf:"varint,3,opt,name=fee_base_msat" json:"fee_base_msat,omitempty"` + // * + // The fee rate of the channel for sending one satoshi across it denominated in + // millionths of a satoshi. + FeeProportionalMillionths uint32 `protobuf:"varint,4,opt,name=fee_proportional_millionths" json:"fee_proportional_millionths,omitempty"` + // / The time-lock delta of the channel. + CltvExpiryDelta uint32 `protobuf:"varint,5,opt,name=cltv_expiry_delta" json:"cltv_expiry_delta,omitempty"` +} + +func (m *HopHint) Reset() { *m = HopHint{} } +func (m *HopHint) String() string { return proto.CompactTextString(m) } +func (*HopHint) ProtoMessage() {} +func (*HopHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{74} } + +func (m *HopHint) GetNodeId() string { + if m != nil { + return m.NodeId + } + return "" +} + +func (m *HopHint) GetChanId() uint64 { + if m != nil { + return m.ChanId + } + return 0 +} + +func (m *HopHint) GetFeeBaseMsat() uint32 { + if m != nil { + return m.FeeBaseMsat + } + return 0 +} + +func (m *HopHint) GetFeeProportionalMillionths() uint32 { + if m != nil { + return m.FeeProportionalMillionths + } + return 0 +} + +func (m *HopHint) GetCltvExpiryDelta() uint32 { + if m != nil { + return m.CltvExpiryDelta + } + return 0 +} + +type RouteHint struct { + // * + // A list of hop hints that when chained together can assist in reaching a + // specific destination. + HopHints []*HopHint `protobuf:"bytes,1,rep,name=hop_hints" json:"hop_hints,omitempty"` +} + +func (m *RouteHint) Reset() { *m = RouteHint{} } +func (m *RouteHint) String() string { return proto.CompactTextString(m) } +func (*RouteHint) ProtoMessage() {} +func (*RouteHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{75} } + +func (m *RouteHint) GetHopHints() []*HopHint { + if m != nil { + return m.HopHints + } + return nil +} + type Invoice struct { // * // An optional memo to attach along with the invoice. Used for record keeping @@ -3269,12 +3339,16 @@ type Invoice struct { FallbackAddr string `protobuf:"bytes,12,opt,name=fallback_addr" json:"fallback_addr,omitempty"` // / Delta to use for the time-lock of the CLTV extended to the final hop. CltvExpiry uint64 `protobuf:"varint,13,opt,name=cltv_expiry" json:"cltv_expiry,omitempty"` + // * + // Route hints that can each be individually used to assist in reaching the + // invoice's destination. + RouteHints []*RouteHint `protobuf:"bytes,14,rep,name=route_hints" json:"route_hints,omitempty"` } func (m *Invoice) Reset() { *m = Invoice{} } func (m *Invoice) String() string { return proto.CompactTextString(m) } func (*Invoice) ProtoMessage() {} -func (*Invoice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{74} } +func (*Invoice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{76} } func (m *Invoice) GetMemo() string { if m != nil { @@ -3367,6 +3441,13 @@ func (m *Invoice) GetCltvExpiry() uint64 { return 0 } +func (m *Invoice) GetRouteHints() []*RouteHint { + if m != nil { + return m.RouteHints + } + return nil +} + type AddInvoiceResponse struct { RHash []byte `protobuf:"bytes,1,opt,name=r_hash,proto3" json:"r_hash,omitempty"` // * @@ -3379,7 +3460,7 @@ type AddInvoiceResponse struct { func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} } func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*AddInvoiceResponse) ProtoMessage() {} -func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{75} } +func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{77} } func (m *AddInvoiceResponse) GetRHash() []byte { if m != nil { @@ -3407,7 +3488,7 @@ type PaymentHash struct { func (m *PaymentHash) Reset() { *m = PaymentHash{} } func (m *PaymentHash) String() string { return proto.CompactTextString(m) } func (*PaymentHash) ProtoMessage() {} -func (*PaymentHash) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{76} } +func (*PaymentHash) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{78} } func (m *PaymentHash) GetRHashStr() string { if m != nil { @@ -3431,7 +3512,7 @@ type ListInvoiceRequest struct { func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} } func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) } func (*ListInvoiceRequest) ProtoMessage() {} -func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{77} } +func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{79} } func (m *ListInvoiceRequest) GetPendingOnly() bool { if m != nil { @@ -3447,7 +3528,7 @@ type ListInvoiceResponse struct { func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} } func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*ListInvoiceResponse) ProtoMessage() {} -func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{78} } +func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{80} } func (m *ListInvoiceResponse) GetInvoices() []*Invoice { if m != nil { @@ -3462,7 +3543,7 @@ type InvoiceSubscription struct { func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} } func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) } func (*InvoiceSubscription) ProtoMessage() {} -func (*InvoiceSubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{79} } +func (*InvoiceSubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{81} } type Payment struct { // / The payment hash @@ -3482,7 +3563,7 @@ type Payment struct { func (m *Payment) Reset() { *m = Payment{} } func (m *Payment) String() string { return proto.CompactTextString(m) } func (*Payment) ProtoMessage() {} -func (*Payment) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{80} } +func (*Payment) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{82} } func (m *Payment) GetPaymentHash() string { if m != nil { @@ -3532,7 +3613,7 @@ type ListPaymentsRequest struct { func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} } func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*ListPaymentsRequest) ProtoMessage() {} -func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{81} } +func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{83} } type ListPaymentsResponse struct { // / The list of payments @@ -3542,7 +3623,7 @@ type ListPaymentsResponse struct { func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} } func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*ListPaymentsResponse) ProtoMessage() {} -func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{82} } +func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{84} } func (m *ListPaymentsResponse) GetPayments() []*Payment { if m != nil { @@ -3557,7 +3638,7 @@ type DeleteAllPaymentsRequest struct { func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsRequest{} } func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsRequest) ProtoMessage() {} -func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{83} } +func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{85} } type DeleteAllPaymentsResponse struct { } @@ -3565,7 +3646,7 @@ type DeleteAllPaymentsResponse struct { func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResponse{} } func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsResponse) ProtoMessage() {} -func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{84} } +func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{86} } type DebugLevelRequest struct { Show bool `protobuf:"varint,1,opt,name=show" json:"show,omitempty"` @@ -3575,7 +3656,7 @@ type DebugLevelRequest struct { func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} } func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) } func (*DebugLevelRequest) ProtoMessage() {} -func (*DebugLevelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{85} } +func (*DebugLevelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{87} } func (m *DebugLevelRequest) GetShow() bool { if m != nil { @@ -3598,7 +3679,7 @@ type DebugLevelResponse struct { func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} } func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) } func (*DebugLevelResponse) ProtoMessage() {} -func (*DebugLevelResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{86} } +func (*DebugLevelResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{88} } func (m *DebugLevelResponse) GetSubSystems() string { if m != nil { @@ -3615,7 +3696,7 @@ type PayReqString struct { func (m *PayReqString) Reset() { *m = PayReqString{} } func (m *PayReqString) String() string { return proto.CompactTextString(m) } func (*PayReqString) ProtoMessage() {} -func (*PayReqString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{87} } +func (*PayReqString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{89} } func (m *PayReqString) GetPayReq() string { if m != nil { @@ -3625,21 +3706,22 @@ func (m *PayReqString) GetPayReq() string { } type PayReq struct { - Destination string `protobuf:"bytes,1,opt,name=destination" json:"destination,omitempty"` - PaymentHash string `protobuf:"bytes,2,opt,name=payment_hash" json:"payment_hash,omitempty"` - NumSatoshis int64 `protobuf:"varint,3,opt,name=num_satoshis" json:"num_satoshis,omitempty"` - Timestamp int64 `protobuf:"varint,4,opt,name=timestamp" json:"timestamp,omitempty"` - Expiry int64 `protobuf:"varint,5,opt,name=expiry" json:"expiry,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description" json:"description,omitempty"` - DescriptionHash string `protobuf:"bytes,7,opt,name=description_hash" json:"description_hash,omitempty"` - FallbackAddr string `protobuf:"bytes,8,opt,name=fallback_addr" json:"fallback_addr,omitempty"` - CltvExpiry int64 `protobuf:"varint,9,opt,name=cltv_expiry" json:"cltv_expiry,omitempty"` + Destination string `protobuf:"bytes,1,opt,name=destination" json:"destination,omitempty"` + PaymentHash string `protobuf:"bytes,2,opt,name=payment_hash" json:"payment_hash,omitempty"` + NumSatoshis int64 `protobuf:"varint,3,opt,name=num_satoshis" json:"num_satoshis,omitempty"` + Timestamp int64 `protobuf:"varint,4,opt,name=timestamp" json:"timestamp,omitempty"` + Expiry int64 `protobuf:"varint,5,opt,name=expiry" json:"expiry,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description" json:"description,omitempty"` + DescriptionHash string `protobuf:"bytes,7,opt,name=description_hash" json:"description_hash,omitempty"` + FallbackAddr string `protobuf:"bytes,8,opt,name=fallback_addr" json:"fallback_addr,omitempty"` + CltvExpiry int64 `protobuf:"varint,9,opt,name=cltv_expiry" json:"cltv_expiry,omitempty"` + RouteHints []*RouteHint `protobuf:"bytes,10,rep,name=route_hints" json:"route_hints,omitempty"` } func (m *PayReq) Reset() { *m = PayReq{} } func (m *PayReq) String() string { return proto.CompactTextString(m) } func (*PayReq) ProtoMessage() {} -func (*PayReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{88} } +func (*PayReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{90} } func (m *PayReq) GetDestination() string { if m != nil { @@ -3704,13 +3786,20 @@ func (m *PayReq) GetCltvExpiry() int64 { return 0 } +func (m *PayReq) GetRouteHints() []*RouteHint { + if m != nil { + return m.RouteHints + } + return nil +} + type FeeReportRequest struct { } func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} } func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) } func (*FeeReportRequest) ProtoMessage() {} -func (*FeeReportRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{89} } +func (*FeeReportRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{91} } type ChannelFeeReport struct { // / The channel that this fee report belongs to. @@ -3726,7 +3815,7 @@ type ChannelFeeReport struct { func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} } func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) } func (*ChannelFeeReport) ProtoMessage() {} -func (*ChannelFeeReport) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{90} } +func (*ChannelFeeReport) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{92} } func (m *ChannelFeeReport) GetChanPoint() string { if m != nil { @@ -3770,7 +3859,7 @@ type FeeReportResponse struct { func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} } func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) } func (*FeeReportResponse) ProtoMessage() {} -func (*FeeReportResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{91} } +func (*FeeReportResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{93} } func (m *FeeReportResponse) GetChannelFees() []*ChannelFeeReport { if m != nil { @@ -3816,11 +3905,9 @@ type PolicyUpdateRequest struct { func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} } func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateRequest) ProtoMessage() {} -func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{92} } +func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{94} } -type isPolicyUpdateRequest_Scope interface { - isPolicyUpdateRequest_Scope() -} +type isPolicyUpdateRequest_Scope interface{ isPolicyUpdateRequest_Scope() } type PolicyUpdateRequest_Global struct { Global bool `protobuf:"varint,1,opt,name=global,oneof"` @@ -3953,7 +4040,7 @@ type PolicyUpdateResponse struct { func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} } func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateResponse) ProtoMessage() {} -func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{93} } +func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{95} } type ForwardingHistoryRequest struct { // / Start time is the starting point of the forwarding history request. All records beyond this point will be included, respecting the end time, and the index offset. @@ -3969,7 +4056,7 @@ type ForwardingHistoryRequest struct { func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryRequest{} } func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryRequest) ProtoMessage() {} -func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{94} } +func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{96} } func (m *ForwardingHistoryRequest) GetStartTime() uint64 { if m != nil { @@ -4017,7 +4104,7 @@ type ForwardingEvent struct { func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} } func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) } func (*ForwardingEvent) ProtoMessage() {} -func (*ForwardingEvent) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{95} } +func (*ForwardingEvent) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{97} } func (m *ForwardingEvent) GetTimestamp() uint64 { if m != nil { @@ -4071,7 +4158,7 @@ type ForwardingHistoryResponse struct { func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResponse{} } func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryResponse) ProtoMessage() {} -func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{96} } +func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{98} } func (m *ForwardingHistoryResponse) GetForwardingEvents() []*ForwardingEvent { if m != nil { @@ -4166,6 +4253,8 @@ func init() { proto.RegisterType((*NodeUpdate)(nil), "lnrpc.NodeUpdate") proto.RegisterType((*ChannelEdgeUpdate)(nil), "lnrpc.ChannelEdgeUpdate") proto.RegisterType((*ClosedChannelUpdate)(nil), "lnrpc.ClosedChannelUpdate") + proto.RegisterType((*HopHint)(nil), "lnrpc.HopHint") + proto.RegisterType((*RouteHint)(nil), "lnrpc.RouteHint") proto.RegisterType((*Invoice)(nil), "lnrpc.Invoice") proto.RegisterType((*AddInvoiceResponse)(nil), "lnrpc.AddInvoiceResponse") proto.RegisterType((*PaymentHash)(nil), "lnrpc.PaymentHash") @@ -6203,346 +6292,353 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 5446 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0xcd, 0x93, 0x1c, 0xc9, - 0x55, 0xb8, 0xaa, 0xa7, 0xe7, 0xa3, 0x5f, 0xf7, 0x7c, 0xe5, 0x8c, 0x46, 0xad, 0x5e, 0x59, 0xab, - 0x4d, 0x6f, 0x58, 0xfa, 0xcd, 0x6f, 0xd1, 0x68, 0xc7, 0xf6, 0xb2, 0xac, 0xc0, 0x0e, 0x7d, 0xcf, - 0xda, 0x5a, 0x79, 0x5c, 0x23, 0x79, 0xc1, 0x0b, 0xb4, 0x6b, 0xba, 0x73, 0x7a, 0xca, 0xea, 0xae, - 0xaa, 0xad, 0xaa, 0x9e, 0x51, 0xef, 0xa2, 0x08, 0x3e, 0x22, 0x38, 0xe1, 0xe0, 0x00, 0x17, 0x43, - 0x38, 0x88, 0xb0, 0x2f, 0x70, 0xe0, 0xc8, 0xc9, 0x04, 0x7f, 0x80, 0x23, 0x08, 0x0e, 0x3e, 0x39, - 0xb8, 0xf1, 0x71, 0x00, 0x82, 0x23, 0x17, 0x0e, 0x04, 0xf1, 0x5e, 0x7e, 0x54, 0x66, 0x55, 0x8d, - 0x24, 0xdb, 0xc0, 0xad, 0xf3, 0xe5, 0xcb, 0x97, 0x5f, 0xef, 0xbd, 0x7c, 0x5f, 0xd5, 0xd0, 0x4a, - 0x93, 0xc1, 0xf5, 0x24, 0x8d, 0xf3, 0x98, 0xcd, 0x8f, 0xa3, 0x34, 0x19, 0xf4, 0x2e, 0x8d, 0xe2, - 0x78, 0x34, 0x16, 0x3b, 0x41, 0x12, 0xee, 0x04, 0x51, 0x14, 0xe7, 0x41, 0x1e, 0xc6, 0x51, 0x26, - 0x91, 0xf8, 0xb7, 0x60, 0xe5, 0x81, 0x88, 0x0e, 0x84, 0x18, 0xfa, 0xe2, 0xe3, 0xa9, 0xc8, 0x72, - 0xf6, 0xff, 0x61, 0x3d, 0x10, 0x9f, 0x08, 0x31, 0xec, 0x27, 0x41, 0x96, 0x25, 0xc7, 0x69, 0x90, - 0x89, 0xae, 0x77, 0xc5, 0xbb, 0xd6, 0xf1, 0xd7, 0x64, 0xc7, 0xbe, 0x81, 0xb3, 0x37, 0xa0, 0x93, - 0x21, 0xaa, 0x88, 0xf2, 0x34, 0x4e, 0x66, 0xdd, 0x06, 0xe1, 0xb5, 0x11, 0x76, 0x4f, 0x82, 0xf8, - 0x18, 0x56, 0xcd, 0x0c, 0x59, 0x12, 0x47, 0x99, 0x60, 0x37, 0x60, 0x73, 0x10, 0x26, 0xc7, 0x22, - 0xed, 0xd3, 0xe0, 0x49, 0x24, 0x26, 0x71, 0x14, 0x0e, 0xba, 0xde, 0x95, 0xb9, 0x6b, 0x2d, 0x9f, - 0xc9, 0x3e, 0x1c, 0xf1, 0x81, 0xea, 0x61, 0x57, 0x61, 0x55, 0x44, 0x12, 0x2e, 0x86, 0x34, 0x4a, - 0x4d, 0xb5, 0x52, 0x80, 0x71, 0x00, 0xff, 0x53, 0x0f, 0xd6, 0xdf, 0x8f, 0xc2, 0xfc, 0xc3, 0x60, - 0x3c, 0x16, 0xb9, 0xde, 0xd3, 0x55, 0x58, 0x3d, 0x25, 0x00, 0xed, 0xe9, 0x34, 0x4e, 0x87, 0x6a, - 0x47, 0x2b, 0x12, 0xbc, 0xaf, 0xa0, 0x67, 0xae, 0xac, 0x71, 0xe6, 0xca, 0x6a, 0x8f, 0x6b, 0xae, - 0xfe, 0xb8, 0xf8, 0x26, 0x30, 0x7b, 0x71, 0xf2, 0x38, 0xf8, 0x97, 0x60, 0xe3, 0x49, 0x34, 0x8e, - 0x07, 0x4f, 0x7f, 0xb6, 0x45, 0xf3, 0x2d, 0xd8, 0x74, 0xc7, 0x2b, 0xba, 0xdf, 0x6d, 0x40, 0xfb, - 0x71, 0x1a, 0x44, 0x59, 0x30, 0xc0, 0x2b, 0x67, 0x5d, 0x58, 0xcc, 0x9f, 0xf5, 0x8f, 0x83, 0xec, - 0x98, 0x08, 0xb5, 0x7c, 0xdd, 0x64, 0x5b, 0xb0, 0x10, 0x4c, 0xe2, 0x69, 0x94, 0xd3, 0xa9, 0xce, - 0xf9, 0xaa, 0xc5, 0xde, 0x82, 0xf5, 0x68, 0x3a, 0xe9, 0x0f, 0xe2, 0xe8, 0x28, 0x4c, 0x27, 0x92, - 0x71, 0x68, 0x73, 0xf3, 0x7e, 0xb5, 0x83, 0x5d, 0x06, 0x38, 0xc4, 0x65, 0xc8, 0x29, 0x9a, 0x34, - 0x85, 0x05, 0x61, 0x1c, 0x3a, 0xaa, 0x25, 0xc2, 0xd1, 0x71, 0xde, 0x9d, 0x27, 0x42, 0x0e, 0x0c, - 0x69, 0xe4, 0xe1, 0x44, 0xf4, 0xb3, 0x3c, 0x98, 0x24, 0xdd, 0x05, 0x5a, 0x8d, 0x05, 0xa1, 0xfe, - 0x38, 0x0f, 0xc6, 0xfd, 0x23, 0x21, 0xb2, 0xee, 0xa2, 0xea, 0x37, 0x10, 0xf6, 0x39, 0x58, 0x19, - 0x8a, 0x2c, 0xef, 0x07, 0xc3, 0x61, 0x2a, 0xb2, 0x4c, 0x64, 0xdd, 0x25, 0xba, 0xba, 0x12, 0x94, - 0x77, 0x61, 0xeb, 0x81, 0xc8, 0xad, 0xd3, 0xc9, 0xd4, 0xb1, 0xf3, 0x87, 0xc0, 0x2c, 0xf0, 0x5d, - 0x91, 0x07, 0xe1, 0x38, 0x63, 0xef, 0x40, 0x27, 0xb7, 0x90, 0x89, 0x55, 0xdb, 0xbb, 0xec, 0x3a, - 0xc9, 0xd8, 0x75, 0x6b, 0x80, 0xef, 0xe0, 0xf1, 0xff, 0xf4, 0xa0, 0x7d, 0x20, 0x22, 0x23, 0x5d, - 0x0c, 0x9a, 0xb8, 0x12, 0x75, 0x93, 0xf4, 0x9b, 0xbd, 0x0e, 0x6d, 0x5a, 0x5d, 0x96, 0xa7, 0x61, - 0x34, 0xa2, 0x2b, 0x68, 0xf9, 0x80, 0xa0, 0x03, 0x82, 0xb0, 0x35, 0x98, 0x0b, 0x26, 0x39, 0x1d, - 0xfc, 0x9c, 0x8f, 0x3f, 0x51, 0xee, 0x92, 0x60, 0x36, 0x11, 0x51, 0x5e, 0x1c, 0x76, 0xc7, 0x6f, - 0x2b, 0xd8, 0x1e, 0x9e, 0xf6, 0x75, 0xd8, 0xb0, 0x51, 0x34, 0xf5, 0x79, 0xa2, 0xbe, 0x6e, 0x61, - 0xaa, 0x49, 0xae, 0xc2, 0xaa, 0xc6, 0x4f, 0xe5, 0x62, 0xe9, 0xf8, 0x5b, 0xfe, 0x8a, 0x02, 0xeb, - 0x2d, 0x5c, 0x83, 0xb5, 0xa3, 0x30, 0x0a, 0xc6, 0xfd, 0xc1, 0x38, 0x3f, 0xe9, 0x0f, 0xc5, 0x38, - 0x0f, 0xe8, 0x22, 0xe6, 0xfd, 0x15, 0x82, 0xdf, 0x19, 0xe7, 0x27, 0x77, 0x11, 0xca, 0xff, 0xd8, - 0x83, 0x8e, 0xdc, 0xbc, 0x12, 0xfc, 0x37, 0x61, 0x59, 0xcf, 0x21, 0xd2, 0x34, 0x4e, 0x15, 0x1f, - 0xba, 0x40, 0xb6, 0x0d, 0x6b, 0x1a, 0x90, 0xa4, 0x22, 0x9c, 0x04, 0x23, 0xa1, 0xa4, 0xbd, 0x02, - 0x67, 0xbb, 0x05, 0xc5, 0x34, 0x9e, 0xe6, 0x52, 0xf4, 0xda, 0xbb, 0x1d, 0x75, 0x31, 0x3e, 0xc2, - 0x7c, 0x17, 0x85, 0x7f, 0xdf, 0x83, 0xce, 0x9d, 0xe3, 0x20, 0x8a, 0xc4, 0x78, 0x3f, 0x0e, 0xa3, - 0x9c, 0xdd, 0x00, 0x76, 0x34, 0x8d, 0x86, 0x61, 0x34, 0xea, 0xe7, 0xcf, 0xc2, 0x61, 0xff, 0x70, - 0x96, 0x8b, 0x4c, 0x5e, 0xd1, 0xde, 0x39, 0xbf, 0xa6, 0x8f, 0xbd, 0x05, 0x6b, 0x0e, 0x34, 0xcb, - 0x53, 0x79, 0x6f, 0x7b, 0xe7, 0xfc, 0x4a, 0x0f, 0x32, 0x7e, 0x3c, 0xcd, 0x93, 0x69, 0xde, 0x0f, - 0xa3, 0xa1, 0x78, 0x46, 0x6b, 0x5c, 0xf6, 0x1d, 0xd8, 0xed, 0x15, 0xe8, 0xd8, 0xe3, 0xf8, 0x97, - 0x60, 0xed, 0x21, 0x4a, 0x44, 0x14, 0x46, 0xa3, 0x5b, 0x92, 0x6d, 0x51, 0x4c, 0x93, 0xe9, 0xe1, - 0x53, 0x31, 0x53, 0xe7, 0xa6, 0x5a, 0xc8, 0x54, 0xc7, 0x71, 0x96, 0x2b, 0xce, 0xa1, 0xdf, 0xfc, - 0x1f, 0x3d, 0x58, 0xc5, 0xb3, 0xff, 0x20, 0x88, 0x66, 0xfa, 0xe6, 0x1e, 0x42, 0x07, 0x49, 0x3d, - 0x8e, 0x6f, 0x49, 0x61, 0x97, 0x4c, 0x7c, 0x4d, 0x9d, 0x55, 0x09, 0xfb, 0xba, 0x8d, 0x8a, 0xca, - 0x7c, 0xe6, 0x3b, 0xa3, 0x91, 0x6d, 0xf3, 0x20, 0x1d, 0x89, 0x9c, 0xd4, 0x80, 0x52, 0x0b, 0x20, - 0x41, 0x77, 0xe2, 0xe8, 0x88, 0x5d, 0x81, 0x4e, 0x16, 0xe4, 0xfd, 0x44, 0xa4, 0x74, 0x6a, 0xc4, - 0x7a, 0x73, 0x3e, 0x64, 0x41, 0xbe, 0x2f, 0xd2, 0xdb, 0xb3, 0x5c, 0xf4, 0xbe, 0x0c, 0xeb, 0x95, - 0x59, 0x90, 0xdb, 0x8b, 0x2d, 0xe2, 0x4f, 0xb6, 0x09, 0xf3, 0x27, 0xc1, 0x78, 0x2a, 0x94, 0x76, - 0x92, 0x8d, 0xf7, 0x1a, 0xef, 0x7a, 0xfc, 0x73, 0xb0, 0x56, 0x2c, 0x5b, 0x31, 0x19, 0x83, 0x26, - 0x9e, 0xa0, 0x22, 0x40, 0xbf, 0xf9, 0xef, 0x78, 0x12, 0xf1, 0x4e, 0x1c, 0x1a, 0x49, 0x47, 0x44, - 0x54, 0x08, 0x1a, 0x11, 0x7f, 0x9f, 0xa9, 0x09, 0x7f, 0xfe, 0xcd, 0xf2, 0xab, 0xb0, 0x6e, 0x2d, - 0xe1, 0x05, 0x8b, 0xfd, 0x8e, 0x07, 0xeb, 0x8f, 0xc4, 0xa9, 0xba, 0x75, 0xbd, 0xda, 0x77, 0xa1, - 0x99, 0xcf, 0x12, 0xf9, 0x14, 0xaf, 0xec, 0xbe, 0xa9, 0x2e, 0xad, 0x82, 0x77, 0x5d, 0x35, 0x1f, - 0xcf, 0x12, 0xe1, 0xd3, 0x08, 0xfe, 0x25, 0x68, 0x5b, 0x40, 0x76, 0x01, 0x36, 0x3e, 0x7c, 0xff, - 0xf1, 0xa3, 0x7b, 0x07, 0x07, 0xfd, 0xfd, 0x27, 0xb7, 0xbf, 0x7a, 0xef, 0xd7, 0xfa, 0x7b, 0xb7, - 0x0e, 0xf6, 0xd6, 0xce, 0xb1, 0x2d, 0x60, 0x8f, 0xee, 0x1d, 0x3c, 0xbe, 0x77, 0xd7, 0x81, 0x7b, - 0xbc, 0x07, 0xdd, 0x47, 0xe2, 0xf4, 0xc3, 0x30, 0x8f, 0x44, 0x96, 0xb9, 0xb3, 0xf1, 0xeb, 0xc0, - 0xec, 0x25, 0xa8, 0x5d, 0x75, 0x61, 0x51, 0xa9, 0x5a, 0xfd, 0xd2, 0xa8, 0x26, 0xff, 0x1c, 0xb0, - 0x83, 0x70, 0x14, 0x7d, 0x20, 0xb2, 0x2c, 0x18, 0x09, 0xbd, 0xb7, 0x35, 0x98, 0x9b, 0x64, 0x23, - 0xa5, 0x14, 0xf1, 0x27, 0xff, 0x3c, 0x6c, 0x38, 0x78, 0x8a, 0xf0, 0x25, 0x68, 0x65, 0xe1, 0x28, - 0x0a, 0xf2, 0x69, 0x2a, 0x14, 0xe9, 0x02, 0xc0, 0xef, 0xc3, 0xe6, 0x37, 0x44, 0x1a, 0x1e, 0xcd, - 0x5e, 0x46, 0xde, 0xa5, 0xd3, 0x28, 0xd3, 0xb9, 0x07, 0xe7, 0x4b, 0x74, 0xd4, 0xf4, 0x92, 0x11, - 0xd5, 0x75, 0x2d, 0xf9, 0xb2, 0x61, 0x89, 0x65, 0xc3, 0x16, 0x4b, 0xfe, 0x04, 0xd8, 0x9d, 0x38, - 0x8a, 0xc4, 0x20, 0xdf, 0x17, 0x22, 0x2d, 0xec, 0xab, 0x82, 0xeb, 0xda, 0xbb, 0x17, 0xd4, 0x3d, - 0x96, 0x65, 0x5d, 0xb1, 0x23, 0x83, 0x66, 0x22, 0xd2, 0x09, 0x11, 0x5e, 0xf2, 0xe9, 0x37, 0x3f, - 0x0f, 0x1b, 0x0e, 0x59, 0xf5, 0xda, 0xbf, 0x0d, 0xe7, 0xef, 0x86, 0xd9, 0xa0, 0x3a, 0x61, 0x17, - 0x16, 0x93, 0xe9, 0x61, 0xbf, 0x90, 0x29, 0xdd, 0xc4, 0x47, 0xb0, 0x3c, 0x44, 0x11, 0xfb, 0x7d, - 0x0f, 0x9a, 0x7b, 0x8f, 0x1f, 0xde, 0x61, 0x3d, 0x58, 0x0a, 0xa3, 0x41, 0x3c, 0xc1, 0xa7, 0x43, - 0x6e, 0xda, 0xb4, 0xcf, 0x94, 0x95, 0x4b, 0xd0, 0xa2, 0x17, 0x07, 0xdf, 0x75, 0x65, 0x0a, 0x15, - 0x00, 0xb4, 0x29, 0xc4, 0xb3, 0x24, 0x4c, 0xc9, 0x68, 0xd0, 0xa6, 0x40, 0x93, 0x34, 0x62, 0xb5, - 0x83, 0xff, 0x57, 0x13, 0x16, 0x95, 0xae, 0xa6, 0xf9, 0x06, 0x79, 0x78, 0x22, 0xd4, 0x4a, 0x54, - 0x0b, 0x5f, 0x95, 0x54, 0x4c, 0xe2, 0x5c, 0xf4, 0x9d, 0x6b, 0x70, 0x81, 0x88, 0x35, 0x90, 0x84, - 0xfa, 0x09, 0x6a, 0x7d, 0x5a, 0x59, 0xcb, 0x77, 0x81, 0x78, 0x58, 0x08, 0xe8, 0x87, 0x43, 0x5a, - 0x53, 0xd3, 0xd7, 0x4d, 0x3c, 0x89, 0x41, 0x90, 0x04, 0x83, 0x30, 0x9f, 0x29, 0xe1, 0x36, 0x6d, - 0xa4, 0x3d, 0x8e, 0x07, 0xc1, 0xb8, 0x7f, 0x18, 0x8c, 0x83, 0x68, 0x20, 0x94, 0xe1, 0xe2, 0x02, - 0xd1, 0x36, 0x51, 0x4b, 0xd2, 0x68, 0xd2, 0x7e, 0x29, 0x41, 0xd1, 0xc6, 0x19, 0xc4, 0x93, 0x49, - 0x98, 0xa3, 0x49, 0xd3, 0x5d, 0x92, 0x8a, 0xa4, 0x80, 0xd0, 0x4e, 0x64, 0xeb, 0x54, 0x9e, 0x5e, - 0x4b, 0xce, 0xe6, 0x00, 0x91, 0xca, 0x91, 0x10, 0xa4, 0x90, 0x9e, 0x9e, 0x76, 0x41, 0x52, 0x29, - 0x20, 0x78, 0x0f, 0xd3, 0x28, 0x13, 0x79, 0x3e, 0x16, 0x43, 0xb3, 0xa0, 0x36, 0xa1, 0x55, 0x3b, - 0xd8, 0x0d, 0xd8, 0x90, 0x56, 0x56, 0x16, 0xe4, 0x71, 0x76, 0x1c, 0x66, 0xfd, 0x4c, 0x44, 0x79, - 0xb7, 0x43, 0xf8, 0x75, 0x5d, 0xec, 0x5d, 0xb8, 0x50, 0x02, 0xa7, 0x62, 0x20, 0xc2, 0x13, 0x31, - 0xec, 0x2e, 0xd3, 0xa8, 0xb3, 0xba, 0xd9, 0x15, 0x68, 0xa3, 0x71, 0x39, 0x4d, 0x86, 0x01, 0xbe, - 0xc3, 0x2b, 0x74, 0x0f, 0x36, 0x88, 0xbd, 0x0d, 0xcb, 0x89, 0x90, 0x8f, 0xe5, 0x71, 0x3e, 0x1e, - 0x64, 0xdd, 0x55, 0x7a, 0xc9, 0xda, 0x4a, 0x98, 0x90, 0x73, 0x7d, 0x17, 0x03, 0x99, 0x72, 0x90, - 0x91, 0xb9, 0x12, 0xcc, 0xba, 0x6b, 0xc4, 0x6e, 0x05, 0x80, 0x64, 0x24, 0x0d, 0x4f, 0x82, 0x5c, - 0x74, 0xd7, 0x89, 0xb7, 0x74, 0x93, 0xff, 0x99, 0x07, 0x1b, 0x0f, 0xc3, 0x2c, 0x57, 0x4c, 0x68, - 0xd4, 0xf1, 0xeb, 0xd0, 0x96, 0xec, 0xd7, 0x8f, 0xa3, 0xf1, 0x4c, 0x71, 0x24, 0x48, 0xd0, 0xd7, - 0xa2, 0xf1, 0x8c, 0x7d, 0x16, 0x96, 0xc3, 0xc8, 0x46, 0x91, 0x32, 0xdc, 0xd1, 0x40, 0x42, 0x7a, - 0x1d, 0xda, 0xc9, 0xf4, 0x70, 0x1c, 0x0e, 0x24, 0xca, 0x9c, 0xa4, 0x22, 0x41, 0x84, 0x80, 0x86, - 0x9e, 0x5c, 0x89, 0xc4, 0x68, 0x12, 0x46, 0x5b, 0xc1, 0x10, 0x85, 0xdf, 0x86, 0x4d, 0x77, 0x81, - 0x4a, 0x59, 0x6d, 0xc3, 0x92, 0xe2, 0xed, 0xac, 0xdb, 0xa6, 0xf3, 0x59, 0x51, 0xe7, 0xa3, 0x50, - 0x7d, 0xd3, 0xcf, 0xff, 0xd5, 0x83, 0x26, 0x2a, 0x80, 0xb3, 0x95, 0x85, 0xad, 0xd3, 0xe7, 0x1c, - 0x9d, 0x4e, 0x76, 0x3f, 0x5a, 0x45, 0x92, 0x25, 0xa4, 0xd8, 0x58, 0x90, 0xa2, 0x3f, 0x15, 0x83, - 0x13, 0x92, 0x1d, 0xd3, 0x8f, 0x10, 0x94, 0x2c, 0x7c, 0x3a, 0x69, 0xb4, 0x14, 0x1c, 0xd3, 0xd6, - 0x7d, 0x34, 0x72, 0xb1, 0xe8, 0xa3, 0x71, 0x5d, 0x58, 0x0c, 0xa3, 0xc3, 0x78, 0x1a, 0x0d, 0x49, - 0x48, 0x96, 0x7c, 0xdd, 0xc4, 0xcb, 0x4e, 0xc8, 0x92, 0x0a, 0x27, 0x42, 0x49, 0x47, 0x01, 0xe0, - 0x0c, 0x4d, 0xab, 0x8c, 0x14, 0x9e, 0x79, 0xc7, 0xde, 0x81, 0x75, 0x0b, 0xa6, 0x4e, 0xf0, 0x0d, - 0x98, 0x4f, 0x10, 0xa0, 0x0c, 0x25, 0xcd, 0x5e, 0xa4, 0x29, 0x65, 0x0f, 0x5f, 0x43, 0xff, 0x39, - 0x7f, 0x3f, 0x3a, 0x8a, 0x35, 0xa5, 0x9f, 0xcc, 0xa1, 0xc3, 0xab, 0x40, 0x8a, 0xd0, 0x35, 0x58, - 0x0d, 0x87, 0x22, 0xca, 0xc3, 0x7c, 0xd6, 0x77, 0x2c, 0xb8, 0x32, 0x18, 0x5f, 0x98, 0x60, 0x1c, - 0x06, 0x99, 0xd2, 0x61, 0xb2, 0xc1, 0x76, 0x61, 0x13, 0xd9, 0x5f, 0x73, 0xb4, 0xb9, 0x56, 0x69, - 0x48, 0xd6, 0xf6, 0xa1, 0xc4, 0x22, 0x5c, 0x71, 0xa0, 0x19, 0x22, 0x35, 0x6d, 0x5d, 0x17, 0x9e, - 0x9a, 0xa4, 0x84, 0x5b, 0x9e, 0x97, 0x22, 0x62, 0x00, 0x15, 0xef, 0x6d, 0x41, 0x1a, 0xb1, 0x65, - 0xef, 0xcd, 0xf2, 0x00, 0x97, 0x2a, 0x1e, 0xe0, 0x35, 0x58, 0xcd, 0x66, 0xd1, 0x40, 0x0c, 0xfb, - 0x79, 0x8c, 0xf3, 0x86, 0x11, 0xdd, 0xce, 0x92, 0x5f, 0x06, 0x93, 0xaf, 0x2a, 0xb2, 0x3c, 0x12, - 0x39, 0xa9, 0xae, 0x25, 0x5f, 0x37, 0xf1, 0x15, 0x20, 0x14, 0xc9, 0xd4, 0x2d, 0x5f, 0xb5, 0xf0, - 0xa9, 0x9c, 0xa6, 0x61, 0xd6, 0xed, 0x10, 0x94, 0x7e, 0xb3, 0x2f, 0xc0, 0xf9, 0x43, 0xf4, 0xac, - 0x8e, 0x45, 0x30, 0x14, 0x29, 0xdd, 0xbe, 0x74, 0x2c, 0xa5, 0x06, 0xaa, 0xef, 0xc4, 0xb9, 0x4f, - 0x44, 0x9a, 0x85, 0x71, 0x44, 0xba, 0xa7, 0xe5, 0xeb, 0x26, 0xff, 0x84, 0x5e, 0x74, 0xe3, 0xf2, - 0x3e, 0x21, 0x75, 0xc4, 0x5e, 0x83, 0x96, 0xdc, 0x63, 0x76, 0x1c, 0x28, 0x23, 0x63, 0x89, 0x00, - 0x07, 0xc7, 0x01, 0x0a, 0xb0, 0x73, 0x6c, 0x0d, 0xb2, 0x1c, 0xdb, 0x04, 0xdb, 0x93, 0xa7, 0xf6, - 0x26, 0xac, 0x68, 0x67, 0x3a, 0xeb, 0x8f, 0xc5, 0x51, 0xae, 0x1d, 0x84, 0x68, 0x3a, 0xc1, 0xe9, - 0xb2, 0x87, 0xe2, 0x28, 0xe7, 0x8f, 0x60, 0x5d, 0xc9, 0xed, 0xd7, 0x12, 0xa1, 0xa7, 0xfe, 0xa5, - 0xf2, 0xa3, 0x26, 0xad, 0x8a, 0x0d, 0x57, 0xd0, 0xc9, 0xcb, 0x29, 0xbd, 0x74, 0xdc, 0x07, 0xa6, - 0xba, 0xef, 0x8c, 0xe3, 0x4c, 0x28, 0x82, 0x1c, 0x3a, 0x83, 0x71, 0x9c, 0x69, 0x37, 0x44, 0x6d, - 0xc7, 0x81, 0xe1, 0xf9, 0x64, 0xd3, 0xc1, 0x00, 0x35, 0x81, 0xd4, 0x69, 0xba, 0xc9, 0xff, 0xdc, - 0x83, 0x0d, 0xa2, 0xa6, 0x35, 0x8c, 0xb1, 0x5d, 0x5f, 0x7d, 0x99, 0x9d, 0x81, 0xed, 0x9a, 0x6d, - 0xc2, 0xfc, 0x51, 0x9c, 0x0e, 0x84, 0x9a, 0x49, 0x36, 0x7e, 0x7a, 0x6b, 0xbc, 0x59, 0xb1, 0xc6, - 0x7f, 0xe2, 0xc1, 0x3a, 0x2d, 0xf5, 0x20, 0x0f, 0xf2, 0x69, 0xa6, 0xb6, 0xff, 0xcb, 0xb0, 0x8c, - 0x5b, 0x15, 0x5a, 0x9c, 0xd4, 0x42, 0x37, 0x8d, 0xe4, 0x13, 0x54, 0x22, 0xef, 0x9d, 0xf3, 0x5d, - 0x64, 0xf6, 0x65, 0xe8, 0xd8, 0x11, 0x11, 0x5a, 0x73, 0x7b, 0xf7, 0xa2, 0xde, 0x65, 0x85, 0x73, - 0xf6, 0xce, 0xf9, 0xce, 0x00, 0x76, 0x13, 0x80, 0xcc, 0x0d, 0x22, 0xab, 0x5c, 0xd9, 0x8b, 0xee, - 0x21, 0x59, 0x97, 0xb5, 0x77, 0xce, 0xb7, 0xd0, 0x6f, 0x2f, 0xc1, 0x82, 0x7c, 0x1f, 0xf9, 0x03, - 0x58, 0x76, 0x56, 0xea, 0x78, 0x19, 0x1d, 0xe9, 0x65, 0x54, 0x9c, 0xd2, 0x46, 0xd5, 0x29, 0xe5, - 0xff, 0xdc, 0x00, 0x86, 0xdc, 0x56, 0xba, 0x4e, 0x7c, 0xa0, 0xe3, 0xa1, 0x63, 0x6e, 0x75, 0x7c, - 0x1b, 0xc4, 0xae, 0x03, 0xb3, 0x9a, 0x3a, 0xf6, 0x20, 0xdf, 0x8d, 0x9a, 0x1e, 0x54, 0x70, 0xd2, - 0x56, 0xd2, 0x3e, 0xb0, 0x32, 0x2c, 0xe5, 0xbd, 0xd5, 0xf6, 0xe1, 0xd3, 0x90, 0x4c, 0xb3, 0x63, - 0x34, 0x20, 0xb4, 0x41, 0xa6, 0xdb, 0x65, 0x06, 0x59, 0x78, 0x29, 0x83, 0x2c, 0x96, 0x19, 0xc4, - 0x36, 0x09, 0x96, 0x1c, 0x93, 0x00, 0xed, 0xaf, 0x49, 0x18, 0x91, 0x5d, 0xd1, 0x9f, 0xe0, 0xec, - 0xca, 0xfe, 0x72, 0x80, 0x6c, 0x1b, 0xd6, 0x94, 0x5d, 0x57, 0xd8, 0x1d, 0x40, 0x67, 0x5c, 0x81, - 0xf3, 0x1f, 0x7b, 0xb0, 0x86, 0xe7, 0xec, 0xf0, 0xe2, 0x7b, 0x40, 0xa2, 0xf0, 0x8a, 0xac, 0xe8, - 0xe0, 0xfe, 0xfc, 0x9c, 0xf8, 0x2e, 0xb4, 0x88, 0x60, 0x9c, 0x88, 0x48, 0x31, 0x62, 0xd7, 0x65, - 0xc4, 0x42, 0x0b, 0xed, 0x9d, 0xf3, 0x0b, 0x64, 0x8b, 0x0d, 0xff, 0xce, 0x83, 0xb6, 0x5a, 0xe6, - 0xcf, 0xec, 0x4b, 0xf4, 0x60, 0x09, 0x39, 0xd2, 0x32, 0xd8, 0x4d, 0x1b, 0x5f, 0x93, 0x09, 0x3a, - 0x6c, 0xf8, 0x7c, 0x3a, 0x7e, 0x44, 0x19, 0x8c, 0x6f, 0x21, 0x29, 0xdc, 0xac, 0x9f, 0x87, 0xe3, - 0xbe, 0xee, 0x55, 0x01, 0xc8, 0xba, 0x2e, 0xd4, 0x3b, 0x59, 0x1e, 0x8c, 0x84, 0x7a, 0xe6, 0x64, - 0x03, 0x1d, 0x26, 0xb5, 0xa1, 0x92, 0x39, 0xc8, 0x7f, 0x04, 0x70, 0xa1, 0xd2, 0x65, 0xc2, 0xdd, - 0xca, 0x40, 0x1e, 0x87, 0x93, 0xc3, 0xd8, 0xd8, 0xda, 0x9e, 0x6d, 0x3b, 0x3b, 0x5d, 0x6c, 0x04, - 0xe7, 0xf5, 0x7b, 0x8e, 0x67, 0x5a, 0xbc, 0xde, 0x0d, 0x32, 0x44, 0xde, 0x76, 0x79, 0xa0, 0x3c, - 0xa1, 0x86, 0xdb, 0x92, 0x5b, 0x4f, 0x8f, 0x1d, 0x43, 0xd7, 0x18, 0x0e, 0x4a, 0xc5, 0x5b, 0xc6, - 0x05, 0xce, 0xf5, 0xd6, 0x4b, 0xe6, 0x22, 0x7d, 0x34, 0xd4, 0xd3, 0x9c, 0x49, 0x8d, 0xcd, 0xe0, - 0xb2, 0xee, 0x23, 0x1d, 0x5e, 0x9d, 0xaf, 0xf9, 0x4a, 0x7b, 0xbb, 0x8f, 0x83, 0xdd, 0x49, 0x5f, - 0x42, 0xb8, 0xf7, 0x23, 0x0f, 0x56, 0x5c, 0x72, 0xc8, 0x3a, 0x4a, 0x08, 0xb5, 0x32, 0xd2, 0x06, - 0x59, 0x09, 0x5c, 0x75, 0x1b, 0x1b, 0x75, 0x6e, 0xa3, 0xed, 0x1c, 0xce, 0xbd, 0xcc, 0x39, 0x6c, - 0xbe, 0x9a, 0x73, 0x38, 0x5f, 0xe7, 0x1c, 0xf6, 0xfe, 0xc3, 0x03, 0x56, 0xbd, 0x5f, 0xf6, 0x40, - 0xfa, 0xad, 0x91, 0x18, 0x2b, 0x3d, 0xf1, 0x0b, 0xaf, 0xc6, 0x23, 0xfa, 0x0c, 0xf5, 0x68, 0x64, - 0x56, 0x5b, 0x11, 0xd8, 0x66, 0xcb, 0xb2, 0x5f, 0xd7, 0x55, 0x72, 0x57, 0x9b, 0x2f, 0x77, 0x57, - 0xe7, 0x5f, 0xee, 0xae, 0x2e, 0x94, 0xdd, 0xd5, 0xde, 0x6f, 0xc1, 0xb2, 0x73, 0xeb, 0xff, 0x73, - 0x3b, 0x2e, 0x9b, 0x3c, 0xf2, 0x82, 0x1d, 0x58, 0xef, 0xdf, 0x1a, 0xc0, 0xaa, 0x9c, 0xf7, 0x7f, - 0xba, 0x06, 0xe2, 0x23, 0x47, 0x81, 0xcc, 0x29, 0x3e, 0x72, 0x54, 0xc7, 0xff, 0xa6, 0x52, 0x7c, - 0x0b, 0xd6, 0x53, 0x31, 0x88, 0x4f, 0x28, 0x09, 0xe7, 0x86, 0x3a, 0xaa, 0x1d, 0x68, 0xf4, 0xb9, - 0x4e, 0xfa, 0x92, 0x93, 0x33, 0xb1, 0x5e, 0x86, 0x92, 0xaf, 0xce, 0xb7, 0x60, 0x53, 0xa6, 0xb2, - 0x6e, 0x4b, 0x52, 0x5a, 0xc9, 0x7e, 0xcf, 0x83, 0xf3, 0xa5, 0x8e, 0x22, 0xb1, 0x20, 0xf5, 0xa8, - 0xab, 0x5c, 0x5d, 0x20, 0xae, 0x5f, 0x31, 0xb0, 0xb5, 0x7e, 0xf9, 0xde, 0x54, 0x3b, 0xf0, 0x7c, - 0xa6, 0x51, 0x15, 0x5f, 0x9e, 0x7a, 0x5d, 0x17, 0xbf, 0x00, 0xe7, 0xd5, 0xcd, 0x96, 0x16, 0x7e, - 0x04, 0x5b, 0xe5, 0x8e, 0x22, 0x52, 0xea, 0x2e, 0x59, 0x37, 0xd1, 0x24, 0x72, 0x74, 0xb6, 0xbb, - 0xde, 0xda, 0x3e, 0xfe, 0x9b, 0xc0, 0xbe, 0x3e, 0x15, 0xe9, 0x8c, 0xd2, 0x1e, 0x26, 0x54, 0x71, - 0xa1, 0xec, 0xd3, 0x2f, 0x24, 0xd3, 0xc3, 0xaf, 0x8a, 0x99, 0xce, 0x2b, 0x35, 0x8a, 0xbc, 0xd2, - 0x67, 0x00, 0xd0, 0x15, 0xa1, 0x3c, 0x89, 0xce, 0xf4, 0xa1, 0x0f, 0x28, 0x09, 0xf2, 0x9b, 0xb0, - 0xe1, 0xd0, 0x37, 0xa7, 0xbf, 0xa0, 0x46, 0x48, 0x47, 0xd9, 0xcd, 0xbe, 0xa8, 0x3e, 0xfe, 0xef, - 0x1e, 0xcc, 0xed, 0xc5, 0x89, 0x1d, 0x62, 0xf3, 0xdc, 0x10, 0x9b, 0xd2, 0xb5, 0x7d, 0xa3, 0x4a, - 0x1b, 0x4a, 0x53, 0xd8, 0x40, 0xb6, 0x0d, 0x2b, 0xc1, 0x24, 0x47, 0x57, 0xf1, 0x28, 0x4e, 0x4f, - 0x83, 0x74, 0x28, 0xaf, 0xe4, 0x76, 0xa3, 0xeb, 0xf9, 0xa5, 0x1e, 0xb6, 0x09, 0x73, 0x46, 0x29, - 0x11, 0x02, 0x36, 0xd1, 0xd8, 0xa0, 0x48, 0xe3, 0x4c, 0x79, 0xb9, 0xaa, 0x85, 0x37, 0xee, 0x8e, - 0x97, 0xe6, 0x9d, 0xe4, 0xf0, 0xba, 0x2e, 0xd4, 0xfb, 0xa8, 0xa3, 0x08, 0x4d, 0x85, 0x27, 0x74, - 0x9b, 0xff, 0x8b, 0x07, 0xf3, 0x74, 0x02, 0x28, 0x93, 0x92, 0x11, 0x29, 0x91, 0x49, 0x61, 0x51, - 0x4f, 0xca, 0x64, 0x09, 0xcc, 0xb8, 0x93, 0xde, 0x6c, 0x98, 0x65, 0xdb, 0x29, 0xce, 0x2b, 0xd0, - 0x92, 0x2d, 0x93, 0x13, 0x24, 0x94, 0x02, 0xc8, 0x2e, 0x43, 0xf3, 0x38, 0x4e, 0xf4, 0x8b, 0x0a, - 0x3a, 0x2a, 0x16, 0x27, 0x3e, 0xc1, 0x8b, 0xf5, 0x20, 0x3d, 0xb9, 0x78, 0xa9, 0x93, 0xcb, 0x60, - 0x7c, 0x95, 0x0c, 0x59, 0xfb, 0x30, 0x4a, 0x50, 0xbe, 0x0d, 0xab, 0x8f, 0xe2, 0xa1, 0xb0, 0xe2, - 0x20, 0x67, 0x72, 0x1d, 0xff, 0x6d, 0x0f, 0x96, 0x34, 0x32, 0xbb, 0x06, 0x4d, 0x7c, 0x6a, 0x4b, - 0xc6, 0xad, 0x89, 0x86, 0x23, 0x9e, 0x4f, 0x18, 0xa8, 0x22, 0xc9, 0x4b, 0x2e, 0x4c, 0x21, 0xed, - 0x23, 0x17, 0x46, 0x86, 0x59, 0x6e, 0xe9, 0x31, 0x2e, 0x41, 0xf9, 0x5f, 0x78, 0xb0, 0xec, 0xcc, - 0x81, 0x2e, 0xcd, 0x38, 0xc8, 0x72, 0x15, 0x61, 0x54, 0xd7, 0x63, 0x83, 0xec, 0xc8, 0x58, 0xc3, - 0x8d, 0x8c, 0x99, 0x98, 0xcd, 0x9c, 0x1d, 0xb3, 0xb9, 0x01, 0xad, 0x22, 0x09, 0xdd, 0x74, 0x54, - 0x1f, 0xce, 0xa8, 0xe3, 0xfc, 0x05, 0x12, 0xd2, 0x19, 0xc4, 0xe3, 0x38, 0x55, 0x39, 0x5a, 0xd9, - 0xe0, 0x37, 0xa1, 0x6d, 0xe1, 0xe3, 0x32, 0x22, 0x91, 0x9f, 0xc6, 0xe9, 0x53, 0x1d, 0xa0, 0x53, - 0x4d, 0x93, 0xce, 0x6a, 0x14, 0xe9, 0x2c, 0xfe, 0x97, 0x1e, 0x2c, 0x23, 0x0f, 0x86, 0xd1, 0x68, - 0x3f, 0x1e, 0x87, 0x83, 0x19, 0xdd, 0xbd, 0x66, 0x37, 0x95, 0xbc, 0xd5, 0xbc, 0xe8, 0x82, 0x91, - 0xb7, 0xb5, 0x47, 0xa3, 0x04, 0xd1, 0xb4, 0x51, 0x52, 0x91, 0xcf, 0x0f, 0x83, 0x4c, 0x31, 0xbf, - 0x7a, 0x8b, 0x1c, 0x20, 0xca, 0x13, 0x02, 0xd2, 0x20, 0x17, 0xfd, 0x49, 0x38, 0x1e, 0x87, 0x12, - 0x57, 0x9a, 0x08, 0x75, 0x5d, 0xfc, 0x87, 0x0d, 0x68, 0x2b, 0x4d, 0x79, 0x6f, 0x38, 0x92, 0xa1, - 0x70, 0x65, 0x68, 0x19, 0x75, 0x61, 0x41, 0x74, 0xbf, 0x63, 0x9a, 0x59, 0x90, 0xf2, 0xb5, 0xce, - 0x55, 0xaf, 0xf5, 0x12, 0xb4, 0x90, 0xbd, 0xde, 0x26, 0x1b, 0x50, 0xd6, 0x2c, 0x14, 0x00, 0xdd, - 0xbb, 0x4b, 0xbd, 0xf3, 0x45, 0x2f, 0x01, 0x1c, 0xab, 0x6f, 0xa1, 0x64, 0xf5, 0xbd, 0x0b, 0x1d, - 0x45, 0x86, 0xce, 0x9d, 0xb4, 0x43, 0xc1, 0xe0, 0xce, 0x9d, 0xf8, 0x0e, 0xa6, 0x1e, 0xb9, 0xab, - 0x47, 0x2e, 0xbd, 0x6c, 0xa4, 0xc6, 0xa4, 0xcc, 0x90, 0x3c, 0x9b, 0x07, 0x69, 0x90, 0x1c, 0xeb, - 0xd7, 0x67, 0x68, 0xd2, 0xdd, 0x04, 0x66, 0xdb, 0x30, 0x8f, 0xc3, 0xb4, 0xb6, 0xae, 0x17, 0x3a, - 0x89, 0xc2, 0xae, 0xc1, 0xbc, 0x18, 0x8e, 0x84, 0xf6, 0x3c, 0x98, 0xeb, 0x03, 0xe2, 0x1d, 0xf9, - 0x12, 0x01, 0x55, 0x00, 0x42, 0x4b, 0x2a, 0xc0, 0xd5, 0xf4, 0x0b, 0xd8, 0x7c, 0x7f, 0xc8, 0x37, - 0x81, 0x3d, 0x92, 0x5c, 0x6b, 0x47, 0x4e, 0x7f, 0x6f, 0x0e, 0xda, 0x16, 0x18, 0xa5, 0x79, 0x84, - 0x0b, 0xee, 0x0f, 0xc3, 0x60, 0x22, 0x72, 0x91, 0x2a, 0x4e, 0x2d, 0x41, 0x11, 0x2f, 0x38, 0x19, - 0xf5, 0xe3, 0x69, 0xde, 0x1f, 0x8a, 0x51, 0x2a, 0xe4, 0x1b, 0x89, 0x8f, 0x81, 0x03, 0x45, 0xbc, - 0x49, 0xf0, 0xcc, 0xc6, 0x93, 0xfc, 0x50, 0x82, 0xea, 0x38, 0xa8, 0x3c, 0xa3, 0x66, 0x11, 0x07, - 0x95, 0x27, 0x52, 0xd6, 0x43, 0xf3, 0x35, 0x7a, 0xe8, 0x1d, 0xd8, 0x92, 0x1a, 0x47, 0xc9, 0x66, - 0xbf, 0xc4, 0x26, 0x67, 0xf4, 0xb2, 0x6d, 0x58, 0xc3, 0x35, 0x6b, 0x06, 0xcf, 0xc2, 0x4f, 0x64, - 0x64, 0xc2, 0xf3, 0x2b, 0x70, 0xc4, 0x45, 0x71, 0x74, 0x70, 0x65, 0xae, 0xa8, 0x02, 0x27, 0xdc, - 0xe0, 0x99, 0x8b, 0xdb, 0x52, 0xb8, 0x25, 0x38, 0x5f, 0x86, 0xf6, 0x41, 0x1e, 0x27, 0xfa, 0x52, - 0x56, 0xa0, 0x23, 0x9b, 0x2a, 0x33, 0xf8, 0x1a, 0x5c, 0x24, 0x2e, 0x7a, 0x1c, 0x27, 0xf1, 0x38, - 0x1e, 0xcd, 0x0e, 0xa6, 0x87, 0xd9, 0x20, 0x0d, 0x13, 0xf4, 0x08, 0xf8, 0xdf, 0x7a, 0xb0, 0xe1, - 0xf4, 0xaa, 0x50, 0xc6, 0x17, 0x24, 0x4b, 0x9b, 0x94, 0x8e, 0x64, 0xbc, 0x75, 0x4b, 0x1d, 0x4a, - 0x44, 0x19, 0x44, 0x7a, 0xa2, 0xb2, 0x3c, 0xb7, 0x60, 0x55, 0xaf, 0x4c, 0x0f, 0x94, 0x5c, 0xd8, - 0xad, 0x72, 0xa1, 0x1a, 0xbf, 0xa2, 0x06, 0x68, 0x12, 0xbf, 0x22, 0xed, 0x6a, 0x31, 0xa4, 0x3d, - 0x6a, 0x9f, 0xb6, 0xa7, 0xc7, 0xdb, 0xc6, 0xbc, 0x5e, 0xc1, 0xc0, 0x00, 0x33, 0xfe, 0x07, 0x1e, - 0x40, 0xb1, 0x3a, 0x64, 0x8c, 0x42, 0xa5, 0xcb, 0x62, 0x35, 0x4b, 0x7d, 0xbf, 0x01, 0x1d, 0x13, - 0xcd, 0x2f, 0x5e, 0x89, 0xb6, 0x86, 0xa1, 0xc1, 0x75, 0x15, 0x56, 0x47, 0xe3, 0xf8, 0x90, 0x9e, - 0x58, 0x4a, 0x35, 0x67, 0x2a, 0x3f, 0xba, 0x22, 0xc1, 0xf7, 0x15, 0xb4, 0x78, 0x52, 0x9a, 0xd6, - 0x93, 0xc2, 0xbf, 0xd3, 0x30, 0x31, 0xe0, 0x62, 0xcf, 0x67, 0x4a, 0x19, 0xdb, 0xad, 0x28, 0xc7, - 0x33, 0x42, 0xae, 0x14, 0xbd, 0xd9, 0x7f, 0xa9, 0x23, 0x7b, 0x13, 0x56, 0x52, 0xa9, 0x7d, 0xb4, - 0x6a, 0x6a, 0xbe, 0x40, 0x35, 0x2d, 0xa7, 0xce, 0xbb, 0xf3, 0xff, 0x60, 0x2d, 0x18, 0x9e, 0x88, - 0x34, 0x0f, 0xc9, 0xa3, 0xa1, 0x47, 0x5f, 0x2a, 0xd4, 0x55, 0x0b, 0x4e, 0x6f, 0xf1, 0x55, 0x58, - 0x55, 0x39, 0x69, 0x83, 0xa9, 0x2a, 0x91, 0x0a, 0x30, 0x22, 0xf2, 0x1f, 0xe8, 0x70, 0xb3, 0x7b, - 0x87, 0x67, 0x9f, 0x88, 0xbd, 0xbb, 0x46, 0x69, 0x77, 0x9f, 0x55, 0xa1, 0xdf, 0xa1, 0x76, 0x9b, - 0x54, 0x10, 0x5e, 0x02, 0x55, 0xa8, 0xde, 0x3d, 0xd2, 0xe6, 0xab, 0x1c, 0x29, 0xff, 0xde, 0x1c, - 0x2c, 0xbe, 0x1f, 0x9d, 0xc4, 0xe1, 0x80, 0x02, 0xb1, 0x13, 0x31, 0x89, 0x75, 0xb9, 0x07, 0xfe, - 0xc6, 0x17, 0x9d, 0x52, 0x9f, 0x49, 0xae, 0x22, 0xa9, 0xba, 0x89, 0xaf, 0x5b, 0x5a, 0x94, 0x40, - 0x49, 0x4e, 0xb1, 0x20, 0x68, 0xc7, 0xa6, 0x76, 0xfd, 0x97, 0x6a, 0x15, 0xf5, 0x32, 0xf3, 0x56, - 0xbd, 0x0c, 0x85, 0xed, 0x65, 0x56, 0x97, 0x8e, 0x73, 0xc9, 0xd7, 0x4d, 0xb2, 0xbb, 0x53, 0x21, - 0x9d, 0x7a, 0x7a, 0x27, 0x17, 0x95, 0xdd, 0x6d, 0x03, 0xf1, 0x2d, 0x95, 0x03, 0x24, 0x8e, 0xd4, - 0x35, 0x36, 0x08, 0x6d, 0x8b, 0x72, 0x09, 0x59, 0x4b, 0x5e, 0x71, 0x09, 0x8c, 0x0a, 0x69, 0x28, - 0x8c, 0xde, 0x90, 0x7b, 0x00, 0x59, 0xe2, 0x55, 0x86, 0x5b, 0xd6, 0xba, 0xcc, 0x4e, 0x6b, 0x6b, - 0x1d, 0x6d, 0x90, 0x60, 0x3c, 0x3e, 0x0c, 0x06, 0x4f, 0xa9, 0xb0, 0x8f, 0x92, 0xd1, 0x2d, 0xdf, - 0x05, 0xe2, 0xaa, 0xa9, 0x4e, 0x4d, 0x91, 0x58, 0x96, 0xc9, 0x64, 0x0b, 0xc4, 0xbf, 0x01, 0xec, - 0xd6, 0x70, 0xa8, 0x6e, 0xc8, 0xf8, 0x34, 0xc5, 0xd9, 0x7a, 0xce, 0xd9, 0xd6, 0xec, 0xb1, 0x51, - 0xbb, 0x47, 0x7e, 0x0f, 0xda, 0xfb, 0x56, 0x3d, 0x1e, 0x5d, 0xa6, 0xae, 0xc4, 0x53, 0x0c, 0x60, - 0x41, 0xac, 0x09, 0x1b, 0xf6, 0x84, 0xfc, 0x17, 0x81, 0x3d, 0x0c, 0xb3, 0xdc, 0xac, 0x4f, 0x1e, - 0xe0, 0x1b, 0xd0, 0x31, 0x1e, 0x60, 0x91, 0x7f, 0x6e, 0x2b, 0x18, 0xe5, 0x85, 0x6f, 0xc9, 0xc4, - 0x75, 0x79, 0x63, 0xdb, 0xb0, 0x14, 0x4a, 0x90, 0xd6, 0xc3, 0x3a, 0x2d, 0xac, 0x31, 0x4d, 0x3f, - 0x1a, 0x14, 0x0a, 0xe8, 0xa8, 0xf9, 0x1f, 0x7a, 0xb0, 0xa8, 0xb6, 0x86, 0xcf, 0xa1, 0x53, 0x89, - 0x28, 0x37, 0xe6, 0xc0, 0xea, 0xeb, 0xb7, 0xaa, 0x5c, 0x37, 0x57, 0xc7, 0x75, 0x0c, 0x9a, 0x49, - 0x90, 0x1f, 0x93, 0x05, 0xdd, 0xf2, 0xe9, 0x37, 0xfa, 0xad, 0xe8, 0xd5, 0x49, 0xee, 0x26, 0x8f, - 0xae, 0xae, 0x64, 0x50, 0xea, 0x8c, 0x0a, 0x1c, 0x37, 0x45, 0xa9, 0x5e, 0x09, 0x37, 0x11, 0x5c, - 0x95, 0x46, 0x2f, 0xc0, 0xc5, 0x79, 0x29, 0x12, 0xe5, 0xf3, 0x52, 0xa8, 0xbe, 0xe9, 0xe7, 0x3d, - 0xe8, 0xde, 0x15, 0x63, 0x91, 0x8b, 0x5b, 0xe3, 0x71, 0x99, 0xfe, 0x6b, 0x70, 0xb1, 0xa6, 0x4f, - 0xbd, 0xaa, 0xf7, 0x61, 0xfd, 0xae, 0x38, 0x9c, 0x8e, 0x1e, 0x8a, 0x93, 0x22, 0xcd, 0xc2, 0xa0, - 0x99, 0x1d, 0xc7, 0xa7, 0xea, 0x6e, 0xe9, 0x37, 0x3a, 0xe8, 0x63, 0xc4, 0xe9, 0x67, 0x89, 0x18, - 0xe8, 0xca, 0x25, 0x82, 0x1c, 0x24, 0x62, 0xc0, 0xdf, 0x01, 0x66, 0xd3, 0x51, 0x5b, 0x40, 0xc9, - 0x9d, 0x1e, 0xf6, 0xb3, 0x59, 0x96, 0x8b, 0x89, 0x2e, 0xc9, 0xb2, 0x41, 0xfc, 0x2a, 0x74, 0xf6, - 0x83, 0x99, 0x2f, 0x3e, 0x56, 0xc5, 0xa0, 0xe8, 0xbc, 0x05, 0x33, 0x64, 0x65, 0xe3, 0xbc, 0x51, - 0x37, 0xff, 0x9b, 0x06, 0x2c, 0x48, 0x4c, 0xa4, 0x3a, 0x14, 0x59, 0x1e, 0x46, 0x32, 0xc5, 0xa0, - 0xa8, 0x5a, 0xa0, 0x0a, 0x6f, 0x34, 0x6a, 0x78, 0x43, 0x99, 0x53, 0xba, 0x0a, 0x44, 0x31, 0x81, - 0x03, 0xc3, 0x77, 0xb7, 0x48, 0xdd, 0x4a, 0xef, 0xa1, 0x00, 0x94, 0xbc, 0xf9, 0x42, 0x3f, 0xc8, - 0xf5, 0x69, 0xa6, 0x55, 0xec, 0x60, 0x83, 0x6a, 0xb5, 0xd0, 0xa2, 0xe4, 0x9a, 0x8a, 0x16, 0xaa, - 0x68, 0x9b, 0xa5, 0x57, 0xd0, 0x36, 0xd2, 0xc6, 0x72, 0xb4, 0x0d, 0x83, 0xb5, 0xfb, 0x42, 0xf8, - 0x22, 0x89, 0x53, 0x5d, 0x51, 0xcb, 0xbf, 0xeb, 0xc1, 0x9a, 0x7a, 0x3d, 0x4c, 0x1f, 0x7b, 0xc3, - 0x79, 0x6a, 0xbc, 0xba, 0xa8, 0xf3, 0x9b, 0xb0, 0x4c, 0xce, 0x96, 0x09, 0x41, 0xa8, 0x78, 0x89, - 0x03, 0xc4, 0x35, 0xe9, 0x38, 0xea, 0x24, 0x1c, 0xab, 0x03, 0xb6, 0x41, 0x3a, 0x8a, 0x81, 0xce, - 0x18, 0x1d, 0xaf, 0xe7, 0x9b, 0x36, 0xff, 0x6b, 0x0f, 0xd6, 0xad, 0x05, 0x2b, 0x8e, 0xba, 0x09, - 0x3a, 0x4d, 0x2b, 0x23, 0x15, 0x52, 0x30, 0x2e, 0xb8, 0x2f, 0x61, 0x31, 0xcc, 0x41, 0xa6, 0x8b, - 0x09, 0x66, 0xb4, 0xc0, 0x6c, 0x2a, 0x6b, 0xdb, 0x9a, 0xbe, 0x0d, 0x42, 0xa6, 0x38, 0x15, 0xe2, - 0xa9, 0x41, 0x99, 0x23, 0x14, 0x07, 0x46, 0x59, 0xb8, 0x38, 0xca, 0x8f, 0x0d, 0x92, 0x2c, 0x3c, - 0x71, 0x81, 0xfc, 0xef, 0x3d, 0xd8, 0x90, 0x16, 0x88, 0xb2, 0xef, 0x4c, 0x51, 0xdc, 0x82, 0x34, - 0xb9, 0xa4, 0x74, 0xed, 0x9d, 0xf3, 0x55, 0x9b, 0x7d, 0xf1, 0x15, 0xad, 0x26, 0x93, 0x7d, 0x3d, - 0xe3, 0x2e, 0xe6, 0xea, 0xee, 0xe2, 0x05, 0x27, 0x5d, 0xe7, 0x99, 0xcf, 0xd7, 0x7a, 0xe6, 0xb7, - 0x17, 0x61, 0x3e, 0x1b, 0xc4, 0x89, 0xe0, 0x5b, 0xb0, 0xe9, 0x6e, 0x4e, 0xa9, 0x93, 0xef, 0x7b, - 0xd0, 0xbd, 0x2f, 0xe3, 0x54, 0x61, 0x34, 0xda, 0x0b, 0xb3, 0x3c, 0x4e, 0x4d, 0x15, 0xf0, 0x65, - 0x80, 0x2c, 0x0f, 0xd2, 0x5c, 0x56, 0xc7, 0x28, 0x9f, 0xba, 0x80, 0xe0, 0x1a, 0x45, 0x34, 0x94, - 0xbd, 0xf2, 0x6e, 0x4c, 0x1b, 0x2f, 0x86, 0x32, 0xc3, 0xfd, 0xf8, 0xe8, 0x28, 0x13, 0xc6, 0x46, - 0xb2, 0x61, 0xe8, 0x66, 0xa1, 0xf4, 0xa2, 0x63, 0x21, 0x4e, 0x48, 0x6d, 0x4a, 0x1f, 0xaa, 0x04, - 0xe5, 0x7f, 0xe5, 0xc1, 0x6a, 0xb1, 0xc8, 0x7b, 0x08, 0x74, 0x25, 0x5d, 0x2e, 0xcd, 0x92, 0x74, - 0xed, 0xed, 0x87, 0xc3, 0x7e, 0x18, 0xa9, 0xb5, 0x59, 0x10, 0x92, 0x3e, 0xd5, 0x8a, 0xa7, 0xba, - 0x12, 0xc9, 0x06, 0xc9, 0x34, 0x63, 0x8e, 0xa3, 0x65, 0x19, 0x92, 0x6a, 0x51, 0x71, 0xd3, 0x24, - 0xa7, 0x51, 0x0b, 0x32, 0x26, 0xa9, 0x9a, 0xfa, 0xad, 0x59, 0x24, 0x28, 0xfe, 0xe4, 0x7f, 0xe8, - 0xc1, 0xc5, 0x9a, 0xc3, 0x55, 0x92, 0x71, 0x17, 0xd6, 0x8f, 0x4c, 0xa7, 0x3e, 0x00, 0x29, 0x1e, - 0x5b, 0x8a, 0x8b, 0x4a, 0x9b, 0xf6, 0xab, 0x03, 0xd8, 0x5b, 0xb0, 0x4e, 0x41, 0x0a, 0x79, 0xa4, - 0x4e, 0x86, 0xbe, 0xda, 0xb1, 0xfb, 0x83, 0x06, 0xac, 0xc8, 0xb8, 0xb8, 0xfc, 0x0e, 0x44, 0xa4, - 0xec, 0x03, 0x58, 0x54, 0x5f, 0xdd, 0xb0, 0xf3, 0x6a, 0x5a, 0xf7, 0x3b, 0x9f, 0xde, 0x56, 0x19, - 0xac, 0x78, 0x67, 0xe3, 0x77, 0x7f, 0xfc, 0x4f, 0x7f, 0xd4, 0x58, 0x66, 0xed, 0x9d, 0x93, 0xb7, - 0x77, 0x46, 0x22, 0xca, 0x90, 0xc6, 0xaf, 0x03, 0x14, 0x1f, 0xae, 0xb0, 0xae, 0x31, 0x18, 0x4a, - 0x1f, 0xda, 0xf4, 0x2e, 0xd6, 0xf4, 0x28, 0xba, 0x17, 0x89, 0xee, 0x06, 0x5f, 0x41, 0xba, 0x61, - 0x14, 0xe6, 0xf2, 0x2b, 0x96, 0xf7, 0xbc, 0x6d, 0x36, 0x84, 0x8e, 0xfd, 0x01, 0x0b, 0xd3, 0xfe, - 0x59, 0xcd, 0x57, 0x31, 0xbd, 0xd7, 0x6a, 0xfb, 0xb4, 0x73, 0x4a, 0x73, 0x9c, 0xe7, 0x6b, 0x38, - 0xc7, 0x94, 0x30, 0xcc, 0x2c, 0xbb, 0xff, 0xf0, 0x1a, 0xb4, 0x4c, 0x8c, 0x83, 0x7d, 0x1b, 0x96, - 0x9d, 0x54, 0x02, 0xd3, 0x84, 0xeb, 0x32, 0x0f, 0xbd, 0x4b, 0xf5, 0x9d, 0x6a, 0xda, 0xcb, 0x34, - 0x6d, 0x97, 0x6d, 0xe1, 0xb4, 0x2a, 0x16, 0xbf, 0x43, 0x09, 0x14, 0x59, 0xcc, 0xf4, 0x14, 0x56, - 0xdc, 0xf0, 0x3f, 0xbb, 0xe4, 0x2a, 0x94, 0xd2, 0x6c, 0x9f, 0x39, 0xa3, 0x57, 0x4d, 0x77, 0x89, - 0xa6, 0xdb, 0x62, 0x9b, 0xf6, 0x74, 0x26, 0xf6, 0x20, 0xa8, 0xfc, 0xcc, 0xfe, 0xb2, 0x85, 0x7d, - 0xc6, 0x5c, 0x75, 0xdd, 0x17, 0x2f, 0xe6, 0xd2, 0xaa, 0x9f, 0xbd, 0xf0, 0x2e, 0x4d, 0xc5, 0x18, - 0x1d, 0xa8, 0xfd, 0x61, 0x0b, 0xfb, 0x08, 0x5a, 0xa6, 0x9a, 0x9d, 0x5d, 0xb0, 0x3e, 0x21, 0xb0, - 0x4b, 0xec, 0x7b, 0xdd, 0x6a, 0x47, 0xdd, 0x55, 0xd9, 0x94, 0x91, 0x21, 0x1e, 0xc2, 0x79, 0x65, - 0x70, 0x1e, 0x8a, 0x9f, 0x66, 0x27, 0x35, 0xdf, 0xe3, 0xdc, 0xf0, 0xd8, 0x4d, 0x58, 0xd2, 0x1f, - 0x09, 0xb0, 0xad, 0xfa, 0x8f, 0x1d, 0x7a, 0x17, 0x2a, 0x70, 0x25, 0xcf, 0xb7, 0x00, 0x8a, 0x02, - 0x77, 0xc3, 0xf9, 0x95, 0xb2, 0x7b, 0x73, 0x88, 0x35, 0xd5, 0xf0, 0x23, 0x2a, 0xe7, 0x77, 0xeb, - 0xe7, 0xd9, 0xeb, 0x05, 0x7e, 0x6d, 0x65, 0xfd, 0x0b, 0x08, 0xf2, 0x2d, 0x3a, 0xbb, 0x35, 0x46, - 0xa2, 0x14, 0x89, 0x53, 0x5d, 0x88, 0x79, 0x17, 0xda, 0x56, 0xd1, 0x3c, 0xd3, 0x14, 0xaa, 0x05, - 0xf7, 0xbd, 0x5e, 0x5d, 0x97, 0x5a, 0xee, 0x57, 0x60, 0xd9, 0xa9, 0x7e, 0x37, 0x92, 0x51, 0x57, - 0x5b, 0x6f, 0x24, 0xa3, 0xbe, 0x60, 0xfe, 0x9b, 0xd0, 0xb6, 0x6a, 0xd5, 0x99, 0x55, 0x80, 0x52, - 0xaa, 0x52, 0x37, 0x2b, 0xaa, 0x2b, 0x6d, 0xdf, 0xa4, 0xfd, 0xae, 0xf0, 0x16, 0xee, 0x97, 0xaa, - 0x11, 0x91, 0x49, 0xbe, 0x0d, 0x2b, 0x6e, 0xf5, 0xba, 0x91, 0xaa, 0xda, 0x3a, 0x78, 0x23, 0x55, - 0x67, 0x94, 0xbc, 0x2b, 0x86, 0xdc, 0xde, 0x30, 0x93, 0xec, 0x7c, 0xaa, 0x22, 0xfc, 0xcf, 0xd9, - 0xd7, 0x51, 0x75, 0xa8, 0xf2, 0x50, 0x56, 0xd4, 0xec, 0xbb, 0x45, 0xa4, 0x86, 0xdb, 0x2b, 0x95, - 0xa4, 0x7c, 0x9d, 0x88, 0xb7, 0x59, 0xb1, 0x03, 0xa9, 0xa1, 0xa9, 0x4c, 0xd4, 0xd2, 0xd0, 0x76, - 0x25, 0xa9, 0xa5, 0xa1, 0x9d, 0x6a, 0xd2, 0xb2, 0x86, 0xce, 0x43, 0xa4, 0x11, 0xc1, 0x6a, 0x29, - 0xe9, 0x6c, 0x84, 0xa5, 0xbe, 0x64, 0xa5, 0x77, 0xf9, 0xc5, 0xb9, 0x6a, 0x57, 0xcd, 0x68, 0xf5, - 0xb2, 0xa3, 0x2b, 0x8c, 0x7e, 0x03, 0x3a, 0x76, 0xd5, 0xb1, 0xd1, 0xd9, 0x35, 0xb5, 0xd2, 0x46, - 0x67, 0xd7, 0x95, 0x29, 0xeb, 0xcb, 0x65, 0x1d, 0x7b, 0x1a, 0xf6, 0x4d, 0x58, 0xb5, 0xca, 0x1b, - 0x0e, 0x66, 0xd1, 0xc0, 0x30, 0x4f, 0xb5, 0x20, 0xad, 0x57, 0x67, 0x9f, 0xf1, 0x0b, 0x44, 0x78, - 0x9d, 0x3b, 0x84, 0x91, 0x71, 0xee, 0x40, 0xdb, 0x2e, 0x9d, 0x78, 0x01, 0xdd, 0x0b, 0x56, 0x97, - 0x5d, 0x9b, 0x75, 0xc3, 0x63, 0x7f, 0xe2, 0x41, 0xc7, 0x2e, 0x75, 0x64, 0x4e, 0x50, 0xb1, 0x44, - 0xa7, 0x6b, 0xf7, 0xd9, 0x84, 0xb8, 0x4f, 0x8b, 0x7c, 0xb8, 0xfd, 0x15, 0xe7, 0x90, 0x3f, 0x75, - 0xec, 0xfc, 0xeb, 0xe5, 0x0f, 0xca, 0x9e, 0x97, 0x11, 0xec, 0xa2, 0xbd, 0xe7, 0x37, 0x3c, 0xf6, - 0x9e, 0xfc, 0xe8, 0x50, 0xfb, 0xe8, 0xcc, 0x52, 0x6e, 0xe5, 0x23, 0xb3, 0xbf, 0xcf, 0xbb, 0xe6, - 0xdd, 0xf0, 0xd8, 0xb7, 0xe4, 0x77, 0x63, 0x6a, 0x2c, 0x9d, 0xfc, 0xab, 0x8e, 0xe7, 0x6f, 0xd2, - 0x6e, 0x2e, 0xf3, 0x8b, 0xce, 0x6e, 0xca, 0xda, 0x7d, 0x1f, 0xa0, 0x08, 0xb8, 0xb0, 0x52, 0xf4, - 0xc1, 0xe8, 0xbd, 0x6a, 0x4c, 0xc6, 0xbd, 0x51, 0x1d, 0xa4, 0x40, 0x8a, 0x1f, 0x49, 0x66, 0x54, - 0xf8, 0x99, 0xb9, 0xd2, 0x6a, 0xe0, 0xa4, 0xd7, 0xab, 0xeb, 0xaa, 0x63, 0x45, 0x4d, 0x9f, 0x3d, - 0x81, 0xe5, 0x87, 0x71, 0xfc, 0x74, 0x9a, 0x98, 0x20, 0x9e, 0xeb, 0xff, 0xef, 0x05, 0xd9, 0x71, - 0xaf, 0xb4, 0x0b, 0x7e, 0x85, 0x48, 0xf5, 0x58, 0xd7, 0x22, 0xb5, 0xf3, 0x69, 0x11, 0xee, 0x79, - 0xce, 0x02, 0x58, 0x37, 0x6f, 0x9c, 0x59, 0x78, 0xcf, 0x25, 0x63, 0x47, 0x5d, 0x2a, 0x53, 0x38, - 0x56, 0x87, 0x5e, 0xed, 0x4e, 0xa6, 0x69, 0xde, 0xf0, 0xd8, 0x3e, 0x74, 0xee, 0x8a, 0x41, 0x3c, - 0x14, 0xca, 0x63, 0xdf, 0x28, 0x16, 0x6e, 0x5c, 0xfd, 0xde, 0xb2, 0x03, 0x74, 0xa5, 0x3e, 0x09, - 0x66, 0xa9, 0xf8, 0x78, 0xe7, 0x53, 0x15, 0x0b, 0x78, 0xae, 0xa5, 0x5e, 0xc7, 0x2f, 0x1c, 0xa9, - 0x2f, 0x05, 0x3c, 0x1c, 0xa9, 0xaf, 0x04, 0x3c, 0x9c, 0xa3, 0xd6, 0xf1, 0x13, 0x36, 0x86, 0xf5, - 0x4a, 0x8c, 0xc4, 0xbc, 0x94, 0x67, 0x45, 0x56, 0x7a, 0x57, 0xce, 0x46, 0x70, 0x67, 0xdb, 0x76, - 0x67, 0x3b, 0x80, 0xe5, 0xbb, 0x42, 0x1e, 0x96, 0x4c, 0x8c, 0xf5, 0x5c, 0x35, 0x62, 0x27, 0xd1, - 0xca, 0x2a, 0x86, 0xfa, 0x5c, 0xb5, 0x4e, 0x59, 0x29, 0xf6, 0x11, 0xb4, 0x1f, 0x88, 0x5c, 0x67, - 0xc2, 0x8c, 0xbd, 0x51, 0x4a, 0x8d, 0xf5, 0x6a, 0x12, 0x69, 0x2e, 0xcf, 0x10, 0xb5, 0x1d, 0x31, - 0x1c, 0x09, 0x29, 0xec, 0xfd, 0x70, 0xf8, 0x9c, 0xfd, 0x2a, 0x11, 0x37, 0xc9, 0xf3, 0x2d, 0x2b, - 0x81, 0x62, 0x13, 0x5f, 0x2d, 0xc1, 0xeb, 0x28, 0x47, 0xf1, 0x50, 0x58, 0x0f, 0x5c, 0x04, 0x6d, - 0xab, 0xb2, 0xc3, 0x08, 0x50, 0xb5, 0x9a, 0xc4, 0x08, 0x50, 0x4d, 0x21, 0x08, 0xbf, 0x46, 0xf3, - 0x70, 0x76, 0xa5, 0x98, 0x47, 0x16, 0x7f, 0x14, 0x33, 0xed, 0x7c, 0x1a, 0x4c, 0xf2, 0xe7, 0xec, - 0x43, 0xfa, 0x6e, 0xc2, 0xce, 0xf6, 0x15, 0xf6, 0x4e, 0x39, 0x31, 0x68, 0x0e, 0xcb, 0xea, 0x72, - 0x6d, 0x20, 0x39, 0x15, 0xbd, 0x83, 0x5f, 0x04, 0x38, 0xc8, 0xe3, 0xe4, 0x6e, 0x20, 0x26, 0x71, - 0x54, 0x68, 0xae, 0x22, 0xa3, 0x55, 0x68, 0x2e, 0x2b, 0xad, 0xc5, 0x3e, 0xb4, 0x2c, 0x4e, 0x27, - 0x59, 0xaa, 0x99, 0xeb, 0xcc, 0xa4, 0x97, 0x39, 0x90, 0x9a, 0xc4, 0xd7, 0x0d, 0x0f, 0xed, 0xc7, - 0x22, 0x22, 0x67, 0xec, 0xc7, 0x4a, 0xb0, 0xcf, 0xa8, 0xbd, 0x9a, 0xf0, 0xdd, 0x3e, 0xb4, 0x8a, - 0xb0, 0x90, 0x7e, 0x92, 0xca, 0x41, 0x24, 0xf3, 0xc6, 0x54, 0x82, 0x35, 0x7c, 0x8d, 0x8e, 0x0a, - 0xd8, 0x12, 0x1e, 0x15, 0x45, 0x60, 0x42, 0xd8, 0x90, 0x0b, 0x34, 0x0f, 0x26, 0xe5, 0x68, 0xf4, - 0x4e, 0x6a, 0x02, 0x26, 0x46, 0x9a, 0x6b, 0xe3, 0x0d, 0x8e, 0x6f, 0x87, 0xdc, 0x2a, 0xf3, 0x43, - 0xa8, 0x9a, 0x27, 0xb0, 0x5e, 0x71, 0x96, 0x8d, 0x48, 0x9f, 0x15, 0xa3, 0x30, 0x22, 0x7d, 0xa6, - 0x9f, 0xcd, 0xcf, 0xd3, 0x94, 0xab, 0x1c, 0x70, 0xca, 0xec, 0x34, 0xcc, 0x07, 0xc7, 0xef, 0x79, - 0xdb, 0x87, 0x0b, 0xf4, 0xb7, 0x16, 0x9f, 0xff, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbc, 0xb9, - 0x7b, 0x12, 0x08, 0x43, 0x00, 0x00, + // 5560 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0xcd, 0x93, 0x1c, 0xc9, + 0x55, 0x57, 0xf5, 0xf4, 0x7c, 0xf4, 0xeb, 0x9e, 0x9e, 0x99, 0x9c, 0xd1, 0xa8, 0xd5, 0xd2, 0x6a, + 0xb5, 0xe5, 0x8d, 0x95, 0x18, 0x16, 0x8d, 0x76, 0x6c, 0x2f, 0xeb, 0x15, 0xac, 0xd1, 0xf7, 0xac, + 0xad, 0x95, 0xc7, 0x35, 0x92, 0x17, 0xbc, 0x40, 0xbb, 0xa6, 0x3b, 0xa7, 0xa7, 0xac, 0xea, 0xaa, + 0xda, 0xaa, 0xea, 0x19, 0xf5, 0x2e, 0x8a, 0xe0, 0x23, 0x82, 0x13, 0x0e, 0x0e, 0x70, 0x31, 0x04, + 0x41, 0x84, 0x7d, 0x81, 0x03, 0x47, 0x4e, 0xe6, 0x2f, 0x70, 0x04, 0x41, 0x10, 0x7b, 0x72, 0x70, + 0xe3, 0xe3, 0x00, 0x04, 0x17, 0x22, 0xb8, 0x70, 0x20, 0x88, 0xf7, 0xf2, 0xa3, 0x32, 0xab, 0x6a, + 0x24, 0xd9, 0x06, 0xdf, 0x3a, 0x7f, 0xf9, 0xea, 0xe5, 0xd7, 0x7b, 0x2f, 0xdf, 0x7b, 0x99, 0xd9, + 0xd0, 0x4a, 0x93, 0xe1, 0xb5, 0x24, 0x8d, 0xf3, 0x98, 0xcd, 0x87, 0x51, 0x9a, 0x0c, 0xfb, 0x17, + 0xc7, 0x71, 0x3c, 0x0e, 0xf9, 0xb6, 0x9f, 0x04, 0xdb, 0x7e, 0x14, 0xc5, 0xb9, 0x9f, 0x07, 0x71, + 0x94, 0x09, 0x22, 0xf7, 0x5b, 0xd0, 0xbd, 0xcf, 0xa3, 0x7d, 0xce, 0x47, 0x1e, 0xff, 0x78, 0xca, + 0xb3, 0x9c, 0xfd, 0x3c, 0xac, 0xf9, 0xfc, 0x13, 0xce, 0x47, 0x83, 0xc4, 0xcf, 0xb2, 0xe4, 0x28, + 0xf5, 0x33, 0xde, 0x73, 0x2e, 0x3b, 0x57, 0x3b, 0xde, 0xaa, 0xa8, 0xd8, 0xd3, 0x38, 0x7b, 0x0d, + 0x3a, 0x19, 0x92, 0xf2, 0x28, 0x4f, 0xe3, 0x64, 0xd6, 0x6b, 0x10, 0x5d, 0x1b, 0xb1, 0xbb, 0x02, + 0x72, 0x43, 0x58, 0xd1, 0x2d, 0x64, 0x49, 0x1c, 0x65, 0x9c, 0x5d, 0x87, 0x8d, 0x61, 0x90, 0x1c, + 0xf1, 0x74, 0x40, 0x1f, 0x4f, 0x22, 0x3e, 0x89, 0xa3, 0x60, 0xd8, 0x73, 0x2e, 0xcf, 0x5d, 0x6d, + 0x79, 0x4c, 0xd4, 0xe1, 0x17, 0x1f, 0xc8, 0x1a, 0x76, 0x05, 0x56, 0x78, 0x24, 0x70, 0x3e, 0xa2, + 0xaf, 0x64, 0x53, 0xdd, 0x02, 0xc6, 0x0f, 0xdc, 0x3f, 0x75, 0x60, 0xed, 0xfd, 0x28, 0xc8, 0x3f, + 0xf4, 0xc3, 0x90, 0xe7, 0x6a, 0x4c, 0x57, 0x60, 0xe5, 0x84, 0x00, 0x1a, 0xd3, 0x49, 0x9c, 0x8e, + 0xe4, 0x88, 0xba, 0x02, 0xde, 0x93, 0xe8, 0xa9, 0x3d, 0x6b, 0x9c, 0xda, 0xb3, 0xda, 0xe9, 0x9a, + 0xab, 0x9f, 0x2e, 0x77, 0x03, 0x98, 0xd9, 0x39, 0x31, 0x1d, 0xee, 0x7b, 0xb0, 0xfe, 0x38, 0x0a, + 0xe3, 0xe1, 0x93, 0x9f, 0xac, 0xd3, 0xee, 0x26, 0x6c, 0xd8, 0xdf, 0x4b, 0xbe, 0xdf, 0x6d, 0x40, + 0xfb, 0x51, 0xea, 0x47, 0x99, 0x3f, 0xc4, 0x25, 0x67, 0x3d, 0x58, 0xcc, 0x9f, 0x0e, 0x8e, 0xfc, + 0xec, 0x88, 0x18, 0xb5, 0x3c, 0x55, 0x64, 0x9b, 0xb0, 0xe0, 0x4f, 0xe2, 0x69, 0x94, 0xd3, 0xac, + 0xce, 0x79, 0xb2, 0xc4, 0xde, 0x84, 0xb5, 0x68, 0x3a, 0x19, 0x0c, 0xe3, 0xe8, 0x30, 0x48, 0x27, + 0x42, 0x70, 0x68, 0x70, 0xf3, 0x5e, 0xb5, 0x82, 0x5d, 0x02, 0x38, 0xc0, 0x6e, 0x88, 0x26, 0x9a, + 0xd4, 0x84, 0x81, 0x30, 0x17, 0x3a, 0xb2, 0xc4, 0x83, 0xf1, 0x51, 0xde, 0x9b, 0x27, 0x46, 0x16, + 0x86, 0x3c, 0xf2, 0x60, 0xc2, 0x07, 0x59, 0xee, 0x4f, 0x92, 0xde, 0x02, 0xf5, 0xc6, 0x40, 0xa8, + 0x3e, 0xce, 0xfd, 0x70, 0x70, 0xc8, 0x79, 0xd6, 0x5b, 0x94, 0xf5, 0x1a, 0x61, 0x6f, 0x40, 0x77, + 0xc4, 0xb3, 0x7c, 0xe0, 0x8f, 0x46, 0x29, 0xcf, 0x32, 0x9e, 0xf5, 0x96, 0x68, 0xe9, 0x4a, 0xa8, + 0xdb, 0x83, 0xcd, 0xfb, 0x3c, 0x37, 0x66, 0x27, 0x93, 0xd3, 0xee, 0x3e, 0x00, 0x66, 0xc0, 0x77, + 0x78, 0xee, 0x07, 0x61, 0xc6, 0xde, 0x86, 0x4e, 0x6e, 0x10, 0x93, 0xa8, 0xb6, 0x77, 0xd8, 0x35, + 0xd2, 0xb1, 0x6b, 0xc6, 0x07, 0x9e, 0x45, 0xe7, 0xfe, 0xb7, 0x03, 0xed, 0x7d, 0x1e, 0x69, 0xed, + 0x62, 0xd0, 0xc4, 0x9e, 0xc8, 0x95, 0xa4, 0xdf, 0xec, 0x55, 0x68, 0x53, 0xef, 0xb2, 0x3c, 0x0d, + 0xa2, 0x31, 0x2d, 0x41, 0xcb, 0x03, 0x84, 0xf6, 0x09, 0x61, 0xab, 0x30, 0xe7, 0x4f, 0x72, 0x9a, + 0xf8, 0x39, 0x0f, 0x7f, 0xa2, 0xde, 0x25, 0xfe, 0x6c, 0xc2, 0xa3, 0xbc, 0x98, 0xec, 0x8e, 0xd7, + 0x96, 0xd8, 0x2e, 0xce, 0xf6, 0x35, 0x58, 0x37, 0x49, 0x14, 0xf7, 0x79, 0xe2, 0xbe, 0x66, 0x50, + 0xca, 0x46, 0xae, 0xc0, 0x8a, 0xa2, 0x4f, 0x45, 0x67, 0x69, 0xfa, 0x5b, 0x5e, 0x57, 0xc2, 0x6a, + 0x08, 0x57, 0x61, 0xf5, 0x30, 0x88, 0xfc, 0x70, 0x30, 0x0c, 0xf3, 0xe3, 0xc1, 0x88, 0x87, 0xb9, + 0x4f, 0x0b, 0x31, 0xef, 0x75, 0x09, 0xbf, 0x1d, 0xe6, 0xc7, 0x77, 0x10, 0x75, 0xff, 0xd8, 0x81, + 0x8e, 0x18, 0xbc, 0x54, 0xfc, 0xd7, 0x61, 0x59, 0xb5, 0xc1, 0xd3, 0x34, 0x4e, 0xa5, 0x1c, 0xda, + 0x20, 0xdb, 0x82, 0x55, 0x05, 0x24, 0x29, 0x0f, 0x26, 0xfe, 0x98, 0x4b, 0x6d, 0xaf, 0xe0, 0x6c, + 0xa7, 0xe0, 0x98, 0xc6, 0xd3, 0x5c, 0xa8, 0x5e, 0x7b, 0xa7, 0x23, 0x17, 0xc6, 0x43, 0xcc, 0xb3, + 0x49, 0xdc, 0xef, 0x39, 0xd0, 0xb9, 0x7d, 0xe4, 0x47, 0x11, 0x0f, 0xf7, 0xe2, 0x20, 0xca, 0xd9, + 0x75, 0x60, 0x87, 0xd3, 0x68, 0x14, 0x44, 0xe3, 0x41, 0xfe, 0x34, 0x18, 0x0d, 0x0e, 0x66, 0x39, + 0xcf, 0xc4, 0x12, 0xed, 0x9e, 0xf1, 0x6a, 0xea, 0xd8, 0x9b, 0xb0, 0x6a, 0xa1, 0x59, 0x9e, 0x8a, + 0x75, 0xdb, 0x3d, 0xe3, 0x55, 0x6a, 0x50, 0xf0, 0xe3, 0x69, 0x9e, 0x4c, 0xf3, 0x41, 0x10, 0x8d, + 0xf8, 0x53, 0xea, 0xe3, 0xb2, 0x67, 0x61, 0xb7, 0xba, 0xd0, 0x31, 0xbf, 0x73, 0xdf, 0x83, 0xd5, + 0x07, 0xa8, 0x11, 0x51, 0x10, 0x8d, 0x6f, 0x0a, 0xb1, 0x45, 0x35, 0x4d, 0xa6, 0x07, 0x4f, 0xf8, + 0x4c, 0xce, 0x9b, 0x2c, 0xa1, 0x50, 0x1d, 0xc5, 0x59, 0x2e, 0x25, 0x87, 0x7e, 0xbb, 0xff, 0xe4, + 0xc0, 0x0a, 0xce, 0xfd, 0x07, 0x7e, 0x34, 0x53, 0x2b, 0xf7, 0x00, 0x3a, 0xc8, 0xea, 0x51, 0x7c, + 0x53, 0x28, 0xbb, 0x10, 0xe2, 0xab, 0x72, 0xae, 0x4a, 0xd4, 0xd7, 0x4c, 0x52, 0x34, 0xe6, 0x33, + 0xcf, 0xfa, 0x1a, 0xc5, 0x36, 0xf7, 0xd3, 0x31, 0xcf, 0xc9, 0x0c, 0x48, 0xb3, 0x00, 0x02, 0xba, + 0x1d, 0x47, 0x87, 0xec, 0x32, 0x74, 0x32, 0x3f, 0x1f, 0x24, 0x3c, 0xa5, 0x59, 0x23, 0xd1, 0x9b, + 0xf3, 0x20, 0xf3, 0xf3, 0x3d, 0x9e, 0xde, 0x9a, 0xe5, 0xbc, 0xff, 0x65, 0x58, 0xab, 0xb4, 0x82, + 0xd2, 0x5e, 0x0c, 0x11, 0x7f, 0xb2, 0x0d, 0x98, 0x3f, 0xf6, 0xc3, 0x29, 0x97, 0xd6, 0x49, 0x14, + 0xde, 0x6d, 0xbc, 0xe3, 0xb8, 0x6f, 0xc0, 0x6a, 0xd1, 0x6d, 0x29, 0x64, 0x0c, 0x9a, 0x38, 0x83, + 0x92, 0x01, 0xfd, 0x76, 0x7f, 0xc7, 0x11, 0x84, 0xb7, 0xe3, 0x40, 0x6b, 0x3a, 0x12, 0xa2, 0x41, + 0x50, 0x84, 0xf8, 0xfb, 0x54, 0x4b, 0xf8, 0xd3, 0x0f, 0xd6, 0xbd, 0x02, 0x6b, 0x46, 0x17, 0x9e, + 0xd3, 0xd9, 0xef, 0x38, 0xb0, 0xf6, 0x90, 0x9f, 0xc8, 0x55, 0x57, 0xbd, 0x7d, 0x07, 0x9a, 0xf9, + 0x2c, 0x11, 0x5b, 0x71, 0x77, 0xe7, 0x75, 0xb9, 0x68, 0x15, 0xba, 0x6b, 0xb2, 0xf8, 0x68, 0x96, + 0x70, 0x8f, 0xbe, 0x70, 0xdf, 0x83, 0xb6, 0x01, 0xb2, 0x73, 0xb0, 0xfe, 0xe1, 0xfb, 0x8f, 0x1e, + 0xde, 0xdd, 0xdf, 0x1f, 0xec, 0x3d, 0xbe, 0xf5, 0xd5, 0xbb, 0xbf, 0x36, 0xd8, 0xbd, 0xb9, 0xbf, + 0xbb, 0x7a, 0x86, 0x6d, 0x02, 0x7b, 0x78, 0x77, 0xff, 0xd1, 0xdd, 0x3b, 0x16, 0xee, 0xb8, 0x7d, + 0xe8, 0x3d, 0xe4, 0x27, 0x1f, 0x06, 0x79, 0xc4, 0xb3, 0xcc, 0x6e, 0xcd, 0xbd, 0x06, 0xcc, 0xec, + 0x82, 0x1c, 0x55, 0x0f, 0x16, 0xa5, 0xa9, 0x55, 0x3b, 0x8d, 0x2c, 0xba, 0x6f, 0x00, 0xdb, 0x0f, + 0xc6, 0xd1, 0x07, 0x3c, 0xcb, 0xfc, 0x31, 0x57, 0x63, 0x5b, 0x85, 0xb9, 0x49, 0x36, 0x96, 0x46, + 0x11, 0x7f, 0xba, 0x9f, 0x87, 0x75, 0x8b, 0x4e, 0x32, 0xbe, 0x08, 0xad, 0x2c, 0x18, 0x47, 0x7e, + 0x3e, 0x4d, 0xb9, 0x64, 0x5d, 0x00, 0xee, 0x3d, 0xd8, 0xf8, 0x06, 0x4f, 0x83, 0xc3, 0xd9, 0x8b, + 0xd8, 0xdb, 0x7c, 0x1a, 0x65, 0x3e, 0x77, 0xe1, 0x6c, 0x89, 0x8f, 0x6c, 0x5e, 0x08, 0xa2, 0x5c, + 0xae, 0x25, 0x4f, 0x14, 0x0c, 0xb5, 0x6c, 0x98, 0x6a, 0xe9, 0x3e, 0x06, 0x76, 0x3b, 0x8e, 0x22, + 0x3e, 0xcc, 0xf7, 0x38, 0x4f, 0x0b, 0xff, 0xaa, 0x90, 0xba, 0xf6, 0xce, 0x39, 0xb9, 0x8e, 0x65, + 0x5d, 0x97, 0xe2, 0xc8, 0xa0, 0x99, 0xf0, 0x74, 0x42, 0x8c, 0x97, 0x3c, 0xfa, 0xed, 0x9e, 0x85, + 0x75, 0x8b, 0xad, 0xdc, 0xed, 0xdf, 0x82, 0xb3, 0x77, 0x82, 0x6c, 0x58, 0x6d, 0xb0, 0x07, 0x8b, + 0xc9, 0xf4, 0x60, 0x50, 0xe8, 0x94, 0x2a, 0xe2, 0x26, 0x58, 0xfe, 0x44, 0x32, 0xfb, 0x7d, 0x07, + 0x9a, 0xbb, 0x8f, 0x1e, 0xdc, 0x66, 0x7d, 0x58, 0x0a, 0xa2, 0x61, 0x3c, 0xc1, 0xad, 0x43, 0x0c, + 0x5a, 0x97, 0x4f, 0xd5, 0x95, 0x8b, 0xd0, 0xa2, 0x1d, 0x07, 0xf7, 0x75, 0xe9, 0x0a, 0x15, 0x00, + 0xfa, 0x14, 0xfc, 0x69, 0x12, 0xa4, 0xe4, 0x34, 0x28, 0x57, 0xa0, 0x49, 0x16, 0xb1, 0x5a, 0xe1, + 0xfe, 0x4f, 0x13, 0x16, 0xa5, 0xad, 0xa6, 0xf6, 0x86, 0x79, 0x70, 0xcc, 0x65, 0x4f, 0x64, 0x09, + 0x77, 0x95, 0x94, 0x4f, 0xe2, 0x9c, 0x0f, 0xac, 0x65, 0xb0, 0x41, 0xa4, 0x1a, 0x0a, 0x46, 0x83, + 0x04, 0xad, 0x3e, 0xf5, 0xac, 0xe5, 0xd9, 0x20, 0x4e, 0x16, 0x02, 0x83, 0x60, 0x44, 0x7d, 0x6a, + 0x7a, 0xaa, 0x88, 0x33, 0x31, 0xf4, 0x13, 0x7f, 0x18, 0xe4, 0x33, 0xa9, 0xdc, 0xba, 0x8c, 0xbc, + 0xc3, 0x78, 0xe8, 0x87, 0x83, 0x03, 0x3f, 0xf4, 0xa3, 0x21, 0x97, 0x8e, 0x8b, 0x0d, 0xa2, 0x6f, + 0x22, 0xbb, 0xa4, 0xc8, 0x84, 0xff, 0x52, 0x42, 0xd1, 0xc7, 0x19, 0xc6, 0x93, 0x49, 0x90, 0xa3, + 0x4b, 0xd3, 0x5b, 0x12, 0x86, 0xa4, 0x40, 0x68, 0x24, 0xa2, 0x74, 0x22, 0x66, 0xaf, 0x25, 0x5a, + 0xb3, 0x40, 0xe4, 0x72, 0xc8, 0x39, 0x19, 0xa4, 0x27, 0x27, 0x3d, 0x10, 0x5c, 0x0a, 0x04, 0xd7, + 0x61, 0x1a, 0x65, 0x3c, 0xcf, 0x43, 0x3e, 0xd2, 0x1d, 0x6a, 0x13, 0x59, 0xb5, 0x82, 0x5d, 0x87, + 0x75, 0xe1, 0x65, 0x65, 0x7e, 0x1e, 0x67, 0x47, 0x41, 0x36, 0xc8, 0x78, 0x94, 0xf7, 0x3a, 0x44, + 0x5f, 0x57, 0xc5, 0xde, 0x81, 0x73, 0x25, 0x38, 0xe5, 0x43, 0x1e, 0x1c, 0xf3, 0x51, 0x6f, 0x99, + 0xbe, 0x3a, 0xad, 0x9a, 0x5d, 0x86, 0x36, 0x3a, 0x97, 0xd3, 0x64, 0xe4, 0xe3, 0x3e, 0xdc, 0xa5, + 0x75, 0x30, 0x21, 0xf6, 0x16, 0x2c, 0x27, 0x5c, 0x6c, 0x96, 0x47, 0x79, 0x38, 0xcc, 0x7a, 0x2b, + 0xb4, 0x93, 0xb5, 0xa5, 0x32, 0xa1, 0xe4, 0x7a, 0x36, 0x05, 0x0a, 0xe5, 0x30, 0x23, 0x77, 0xc5, + 0x9f, 0xf5, 0x56, 0x49, 0xdc, 0x0a, 0x80, 0x74, 0x24, 0x0d, 0x8e, 0xfd, 0x9c, 0xf7, 0xd6, 0x48, + 0xb6, 0x54, 0xd1, 0xfd, 0x73, 0x07, 0xd6, 0x1f, 0x04, 0x59, 0x2e, 0x85, 0x50, 0x9b, 0xe3, 0x57, + 0xa1, 0x2d, 0xc4, 0x6f, 0x10, 0x47, 0xe1, 0x4c, 0x4a, 0x24, 0x08, 0xe8, 0x6b, 0x51, 0x38, 0x63, + 0x9f, 0x83, 0xe5, 0x20, 0x32, 0x49, 0x84, 0x0e, 0x77, 0x14, 0x48, 0x44, 0xaf, 0x42, 0x3b, 0x99, + 0x1e, 0x84, 0xc1, 0x50, 0x90, 0xcc, 0x09, 0x2e, 0x02, 0x22, 0x02, 0x74, 0xf4, 0x44, 0x4f, 0x04, + 0x45, 0x93, 0x28, 0xda, 0x12, 0x43, 0x12, 0xf7, 0x16, 0x6c, 0xd8, 0x1d, 0x94, 0xc6, 0x6a, 0x0b, + 0x96, 0xa4, 0x6c, 0x67, 0xbd, 0x36, 0xcd, 0x4f, 0x57, 0xce, 0x8f, 0x24, 0xf5, 0x74, 0xbd, 0xfb, + 0x6f, 0x0e, 0x34, 0xd1, 0x00, 0x9c, 0x6e, 0x2c, 0x4c, 0x9b, 0x3e, 0x67, 0xd9, 0x74, 0xf2, 0xfb, + 0xd1, 0x2b, 0x12, 0x22, 0x21, 0xd4, 0xc6, 0x40, 0x8a, 0xfa, 0x94, 0x0f, 0x8f, 0x49, 0x77, 0x74, + 0x3d, 0x22, 0xa8, 0x59, 0xb8, 0x75, 0xd2, 0xd7, 0x42, 0x71, 0x74, 0x59, 0xd5, 0xd1, 0x97, 0x8b, + 0x45, 0x1d, 0x7d, 0xd7, 0x83, 0xc5, 0x20, 0x3a, 0x88, 0xa7, 0xd1, 0x88, 0x94, 0x64, 0xc9, 0x53, + 0x45, 0x5c, 0xec, 0x84, 0x3c, 0xa9, 0x60, 0xc2, 0xa5, 0x76, 0x14, 0x80, 0xcb, 0xd0, 0xb5, 0xca, + 0xc8, 0xe0, 0xe9, 0x7d, 0xec, 0x6d, 0x58, 0x33, 0x30, 0x39, 0x83, 0xaf, 0xc1, 0x7c, 0x82, 0x80, + 0x74, 0x94, 0x94, 0x78, 0x91, 0xa5, 0x14, 0x35, 0xee, 0x2a, 0xc6, 0xcf, 0xf9, 0xfb, 0xd1, 0x61, + 0xac, 0x38, 0xfd, 0x68, 0x0e, 0x03, 0x5e, 0x09, 0x49, 0x46, 0x57, 0x61, 0x25, 0x18, 0xf1, 0x28, + 0x0f, 0xf2, 0xd9, 0xc0, 0xf2, 0xe0, 0xca, 0x30, 0xee, 0x30, 0x7e, 0x18, 0xf8, 0x99, 0xb4, 0x61, + 0xa2, 0xc0, 0x76, 0x60, 0x03, 0xc5, 0x5f, 0x49, 0xb4, 0x5e, 0x56, 0xe1, 0x48, 0xd6, 0xd6, 0xa1, + 0xc6, 0x22, 0x2e, 0x25, 0x50, 0x7f, 0x22, 0x2c, 0x6d, 0x5d, 0x15, 0xce, 0x9a, 0xe0, 0x84, 0x43, + 0x9e, 0x17, 0x2a, 0xa2, 0x81, 0x4a, 0xf4, 0xb6, 0x20, 0x9c, 0xd8, 0x72, 0xf4, 0x66, 0x44, 0x80, + 0x4b, 0x95, 0x08, 0xf0, 0x2a, 0xac, 0x64, 0xb3, 0x68, 0xc8, 0x47, 0x83, 0x3c, 0xc6, 0x76, 0x83, + 0x88, 0x56, 0x67, 0xc9, 0x2b, 0xc3, 0x14, 0xab, 0xf2, 0x2c, 0x8f, 0x78, 0x4e, 0xa6, 0x6b, 0xc9, + 0x53, 0x45, 0xdc, 0x05, 0x88, 0x44, 0x08, 0x75, 0xcb, 0x93, 0x25, 0xdc, 0x2a, 0xa7, 0x69, 0x90, + 0xf5, 0x3a, 0x84, 0xd2, 0x6f, 0xf6, 0x05, 0x38, 0x7b, 0x80, 0x91, 0xd5, 0x11, 0xf7, 0x47, 0x3c, + 0xa5, 0xd5, 0x17, 0x81, 0xa5, 0xb0, 0x40, 0xf5, 0x95, 0xd8, 0xf6, 0x31, 0x4f, 0xb3, 0x20, 0x8e, + 0xc8, 0xf6, 0xb4, 0x3c, 0x55, 0x74, 0x3f, 0xa1, 0x1d, 0x5d, 0x87, 0xbc, 0x8f, 0xc9, 0x1c, 0xb1, + 0x0b, 0xd0, 0x12, 0x63, 0xcc, 0x8e, 0x7c, 0xe9, 0x64, 0x2c, 0x11, 0xb0, 0x7f, 0xe4, 0xa3, 0x02, + 0x5b, 0xd3, 0xd6, 0x20, 0xcf, 0xb1, 0x4d, 0xd8, 0xae, 0x98, 0xb5, 0xd7, 0xa1, 0xab, 0x82, 0xe9, + 0x6c, 0x10, 0xf2, 0xc3, 0x5c, 0x05, 0x08, 0xd1, 0x74, 0x82, 0xcd, 0x65, 0x0f, 0xf8, 0x61, 0xee, + 0x3e, 0x84, 0x35, 0xa9, 0xb7, 0x5f, 0x4b, 0xb8, 0x6a, 0xfa, 0x4b, 0xe5, 0x4d, 0x4d, 0x78, 0x15, + 0xeb, 0xb6, 0xa2, 0x53, 0x94, 0x53, 0xda, 0xe9, 0x5c, 0x0f, 0x98, 0xac, 0xbe, 0x1d, 0xc6, 0x19, + 0x97, 0x0c, 0x5d, 0xe8, 0x0c, 0xc3, 0x38, 0x53, 0x61, 0x88, 0x1c, 0x8e, 0x85, 0xe1, 0xfc, 0x64, + 0xd3, 0xe1, 0x10, 0x2d, 0x81, 0xb0, 0x69, 0xaa, 0xe8, 0xfe, 0x85, 0x03, 0xeb, 0xc4, 0x4d, 0x59, + 0x18, 0xed, 0xbb, 0xbe, 0x7c, 0x37, 0x3b, 0x43, 0x33, 0x34, 0xdb, 0x80, 0xf9, 0xc3, 0x38, 0x1d, + 0x72, 0xd9, 0x92, 0x28, 0xfc, 0xf8, 0xde, 0x78, 0xb3, 0xe2, 0x8d, 0xff, 0xc8, 0x81, 0x35, 0xea, + 0xea, 0x7e, 0xee, 0xe7, 0xd3, 0x4c, 0x0e, 0xff, 0x97, 0x60, 0x19, 0x87, 0xca, 0x95, 0x3a, 0xc9, + 0x8e, 0x6e, 0x68, 0xcd, 0x27, 0x54, 0x10, 0xef, 0x9e, 0xf1, 0x6c, 0x62, 0xf6, 0x65, 0xe8, 0x98, + 0x19, 0x11, 0xea, 0x73, 0x7b, 0xe7, 0xbc, 0x1a, 0x65, 0x45, 0x72, 0x76, 0xcf, 0x78, 0xd6, 0x07, + 0xec, 0x06, 0x00, 0xb9, 0x1b, 0xc4, 0x56, 0x86, 0xb2, 0xe7, 0xed, 0x49, 0x32, 0x16, 0x6b, 0xf7, + 0x8c, 0x67, 0x90, 0xdf, 0x5a, 0x82, 0x05, 0xb1, 0x3f, 0xba, 0xf7, 0x61, 0xd9, 0xea, 0xa9, 0x15, + 0x65, 0x74, 0x44, 0x94, 0x51, 0x09, 0x4a, 0x1b, 0xd5, 0xa0, 0xd4, 0xfd, 0x97, 0x06, 0x30, 0x94, + 0xb6, 0xd2, 0x72, 0xe2, 0x06, 0x1d, 0x8f, 0x2c, 0x77, 0xab, 0xe3, 0x99, 0x10, 0xbb, 0x06, 0xcc, + 0x28, 0xaa, 0xdc, 0x83, 0xd8, 0x37, 0x6a, 0x6a, 0xd0, 0xc0, 0x09, 0x5f, 0x49, 0xc5, 0xc0, 0xd2, + 0xb1, 0x14, 0xeb, 0x56, 0x5b, 0x87, 0x5b, 0x43, 0x32, 0xcd, 0x8e, 0xd0, 0x81, 0x50, 0x0e, 0x99, + 0x2a, 0x97, 0x05, 0x64, 0xe1, 0x85, 0x02, 0xb2, 0x58, 0x16, 0x10, 0xd3, 0x25, 0x58, 0xb2, 0x5c, + 0x02, 0xf4, 0xbf, 0x26, 0x41, 0x44, 0x7e, 0xc5, 0x60, 0x82, 0xad, 0x4b, 0xff, 0xcb, 0x02, 0xd9, + 0x16, 0xac, 0x4a, 0xbf, 0xae, 0xf0, 0x3b, 0x80, 0xe6, 0xb8, 0x82, 0xbb, 0x9f, 0x39, 0xb0, 0x8a, + 0xf3, 0x6c, 0xc9, 0xe2, 0xbb, 0x40, 0xaa, 0xf0, 0x92, 0xa2, 0x68, 0xd1, 0xfe, 0xf4, 0x92, 0xf8, + 0x0e, 0xb4, 0x88, 0x61, 0x9c, 0xf0, 0x48, 0x0a, 0x62, 0xcf, 0x16, 0xc4, 0xc2, 0x0a, 0xed, 0x9e, + 0xf1, 0x0a, 0x62, 0x43, 0x0c, 0xff, 0xce, 0x81, 0xb6, 0xec, 0xe6, 0x4f, 0x1c, 0x4b, 0xf4, 0x61, + 0x09, 0x25, 0xd2, 0x70, 0xd8, 0x75, 0x19, 0x77, 0x93, 0x09, 0x06, 0x6c, 0xb8, 0x7d, 0x5a, 0x71, + 0x44, 0x19, 0xc6, 0xbd, 0x90, 0x0c, 0x6e, 0x36, 0xc8, 0x83, 0x70, 0xa0, 0x6a, 0x65, 0x02, 0xb2, + 0xae, 0x0a, 0xed, 0x4e, 0x96, 0xfb, 0x63, 0x2e, 0xb7, 0x39, 0x51, 0xc0, 0x80, 0x49, 0x0e, 0xa8, + 0xe4, 0x0e, 0xba, 0x3f, 0x04, 0x38, 0x57, 0xa9, 0xd2, 0xe9, 0x6e, 0xe9, 0x20, 0x87, 0xc1, 0xe4, + 0x20, 0xd6, 0xbe, 0xb6, 0x63, 0xfa, 0xce, 0x56, 0x15, 0x1b, 0xc3, 0x59, 0xb5, 0x9f, 0xe3, 0x9c, + 0x16, 0xbb, 0x77, 0x83, 0x1c, 0x91, 0xb7, 0x6c, 0x19, 0x28, 0x37, 0xa8, 0x70, 0x53, 0x73, 0xeb, + 0xf9, 0xb1, 0x23, 0xe8, 0x69, 0xc7, 0x41, 0x9a, 0x78, 0xc3, 0xb9, 0xc0, 0xb6, 0xde, 0x7c, 0x41, + 0x5b, 0x64, 0x8f, 0x46, 0xaa, 0x99, 0x53, 0xb9, 0xb1, 0x19, 0x5c, 0x52, 0x75, 0x64, 0xc3, 0xab, + 0xed, 0x35, 0x5f, 0x6a, 0x6c, 0xf7, 0xf0, 0x63, 0xbb, 0xd1, 0x17, 0x30, 0xee, 0xff, 0xd0, 0x81, + 0xae, 0xcd, 0x0e, 0x45, 0x47, 0x2a, 0xa1, 0x32, 0x46, 0xca, 0x21, 0x2b, 0xc1, 0xd5, 0xb0, 0xb1, + 0x51, 0x17, 0x36, 0x9a, 0xc1, 0xe1, 0xdc, 0x8b, 0x82, 0xc3, 0xe6, 0xcb, 0x05, 0x87, 0xf3, 0x75, + 0xc1, 0x61, 0xff, 0xbf, 0x1c, 0x60, 0xd5, 0xf5, 0x65, 0xf7, 0x45, 0xdc, 0x1a, 0xf1, 0x50, 0xda, + 0x89, 0x5f, 0x78, 0x39, 0x19, 0x51, 0x73, 0xa8, 0xbe, 0x46, 0x61, 0x35, 0x0d, 0x81, 0xe9, 0xb6, + 0x2c, 0x7b, 0x75, 0x55, 0xa5, 0x70, 0xb5, 0xf9, 0xe2, 0x70, 0x75, 0xfe, 0xc5, 0xe1, 0xea, 0x42, + 0x39, 0x5c, 0xed, 0xff, 0x16, 0x2c, 0x5b, 0xab, 0xfe, 0x7f, 0x37, 0xe2, 0xb2, 0xcb, 0x23, 0x16, + 0xd8, 0xc2, 0xfa, 0xff, 0xde, 0x00, 0x56, 0x95, 0xbc, 0x9f, 0x69, 0x1f, 0x48, 0x8e, 0x2c, 0x03, + 0x32, 0x27, 0xe5, 0xc8, 0x32, 0x1d, 0xff, 0x9f, 0x46, 0xf1, 0x4d, 0x58, 0x4b, 0xf9, 0x30, 0x3e, + 0xa6, 0x43, 0x38, 0x3b, 0xd5, 0x51, 0xad, 0x40, 0xa7, 0xcf, 0x0e, 0xd2, 0x97, 0xac, 0x33, 0x13, + 0x63, 0x67, 0x28, 0xc5, 0xea, 0xee, 0x26, 0x6c, 0x88, 0xa3, 0xac, 0x5b, 0x82, 0x95, 0x32, 0xb2, + 0x7f, 0xe6, 0xc0, 0xd9, 0x52, 0x45, 0x71, 0xb0, 0x20, 0xec, 0xa8, 0x6d, 0x5c, 0x6d, 0x10, 0xfb, + 0x2f, 0x05, 0xd8, 0xe8, 0xbf, 0xd8, 0x6f, 0xaa, 0x15, 0x38, 0x3f, 0xd3, 0xa8, 0x4a, 0x2f, 0x66, + 0xbd, 0xae, 0xca, 0x3d, 0x07, 0x67, 0xe5, 0xca, 0x96, 0x3a, 0x7e, 0x08, 0x9b, 0xe5, 0x8a, 0x22, + 0x53, 0x6a, 0x77, 0x59, 0x15, 0xd1, 0x25, 0xb2, 0x6c, 0xb6, 0xdd, 0xdf, 0xda, 0x3a, 0xf7, 0x37, + 0x81, 0x7d, 0x7d, 0xca, 0xd3, 0x19, 0x1d, 0x7b, 0xe8, 0x54, 0xc5, 0xb9, 0x72, 0x4c, 0xbf, 0x90, + 0x4c, 0x0f, 0xbe, 0xca, 0x67, 0xea, 0x5c, 0xa9, 0x51, 0x9c, 0x2b, 0xbd, 0x02, 0x80, 0xa1, 0x08, + 0x9d, 0x93, 0xa8, 0x93, 0x3e, 0x8c, 0x01, 0x05, 0x43, 0xf7, 0x06, 0xac, 0x5b, 0xfc, 0xf5, 0xec, + 0x2f, 0xc8, 0x2f, 0x44, 0xa0, 0x6c, 0x9f, 0xbe, 0xc8, 0x3a, 0xf7, 0x3f, 0x1c, 0x98, 0xdb, 0x8d, + 0x13, 0x33, 0xc5, 0xe6, 0xd8, 0x29, 0x36, 0x69, 0x6b, 0x07, 0xda, 0x94, 0x36, 0xa4, 0xa5, 0x30, + 0x41, 0xb6, 0x05, 0x5d, 0x7f, 0x92, 0x63, 0xa8, 0x78, 0x18, 0xa7, 0x27, 0x7e, 0x3a, 0x12, 0x4b, + 0x72, 0xab, 0xd1, 0x73, 0xbc, 0x52, 0x0d, 0xdb, 0x80, 0x39, 0x6d, 0x94, 0x88, 0x00, 0x8b, 0xe8, + 0x6c, 0x50, 0xa6, 0x71, 0x26, 0xa3, 0x5c, 0x59, 0xc2, 0x15, 0xb7, 0xbf, 0x17, 0xee, 0x9d, 0x90, + 0xf0, 0xba, 0x2a, 0xb4, 0xfb, 0x68, 0xa3, 0x88, 0x4c, 0xa6, 0x27, 0x54, 0xd9, 0xfd, 0x57, 0x07, + 0xe6, 0x69, 0x06, 0x50, 0x27, 0x85, 0x20, 0xd2, 0x41, 0x26, 0xa5, 0x45, 0x1d, 0xa1, 0x93, 0x25, + 0x98, 0xb9, 0xd6, 0xf1, 0x66, 0x43, 0x77, 0xdb, 0x3c, 0xe2, 0xbc, 0x0c, 0x2d, 0x51, 0xd2, 0x67, + 0x82, 0x44, 0x52, 0x80, 0xec, 0x12, 0x34, 0x8f, 0xe2, 0x44, 0xed, 0xa8, 0xa0, 0xb2, 0x62, 0x71, + 0xe2, 0x11, 0x5e, 0xf4, 0x07, 0xf9, 0x89, 0xce, 0x0b, 0x9b, 0x5c, 0x86, 0x71, 0x57, 0xd2, 0x6c, + 0xcd, 0xc9, 0x28, 0xa1, 0xee, 0x16, 0xac, 0x3c, 0x8c, 0x47, 0xdc, 0xc8, 0x83, 0x9c, 0x2a, 0x75, + 0xee, 0x6f, 0x3b, 0xb0, 0xa4, 0x88, 0xd9, 0x55, 0x68, 0xe2, 0x56, 0x5b, 0x72, 0x6e, 0x75, 0x36, + 0x1c, 0xe9, 0x3c, 0xa2, 0x40, 0x13, 0x49, 0x51, 0x72, 0xe1, 0x0a, 0xa9, 0x18, 0xb9, 0x70, 0x32, + 0x74, 0x77, 0x4b, 0x9b, 0x71, 0x09, 0x75, 0xff, 0xd2, 0x81, 0x65, 0xab, 0x0d, 0x0c, 0x69, 0x42, + 0x3f, 0xcb, 0x65, 0x86, 0x51, 0x2e, 0x8f, 0x09, 0x99, 0x99, 0xb1, 0x86, 0x9d, 0x19, 0xd3, 0x39, + 0x9b, 0x39, 0x33, 0x67, 0x73, 0x1d, 0x5a, 0xc5, 0x21, 0x74, 0xd3, 0x32, 0x7d, 0xd8, 0xa2, 0xca, + 0xf3, 0x17, 0x44, 0xc8, 0x67, 0x18, 0x87, 0x71, 0x2a, 0xcf, 0x68, 0x45, 0xc1, 0xbd, 0x01, 0x6d, + 0x83, 0x1e, 0xbb, 0x11, 0xf1, 0xfc, 0x24, 0x4e, 0x9f, 0xa8, 0x04, 0x9d, 0x2c, 0xea, 0xe3, 0xac, + 0x46, 0x71, 0x9c, 0xe5, 0xfe, 0x95, 0x03, 0xcb, 0x28, 0x83, 0x41, 0x34, 0xde, 0x8b, 0xc3, 0x60, + 0x38, 0xa3, 0xb5, 0x57, 0xe2, 0x26, 0x0f, 0x6f, 0x95, 0x2c, 0xda, 0x30, 0xca, 0xb6, 0x8a, 0x68, + 0xa4, 0x22, 0xea, 0x32, 0x6a, 0x2a, 0xca, 0xf9, 0x81, 0x9f, 0x49, 0xe1, 0x97, 0x7b, 0x91, 0x05, + 0xa2, 0x3e, 0x21, 0x90, 0xfa, 0x39, 0x1f, 0x4c, 0x82, 0x30, 0x0c, 0x04, 0xad, 0x70, 0x11, 0xea, + 0xaa, 0xdc, 0x1f, 0x34, 0xa0, 0x2d, 0x2d, 0xe5, 0xdd, 0xd1, 0x58, 0xa4, 0xc2, 0xa5, 0xa3, 0xa5, + 0xcd, 0x85, 0x81, 0xa8, 0x7a, 0xcb, 0x35, 0x33, 0x90, 0xf2, 0xb2, 0xce, 0x55, 0x97, 0xf5, 0x22, + 0xb4, 0x50, 0xbc, 0xde, 0x22, 0x1f, 0x50, 0xdc, 0x59, 0x28, 0x00, 0x55, 0xbb, 0x43, 0xb5, 0xf3, + 0x45, 0x2d, 0x01, 0x96, 0xd7, 0xb7, 0x50, 0xf2, 0xfa, 0xde, 0x81, 0x8e, 0x64, 0x43, 0xf3, 0x4e, + 0xd6, 0xa1, 0x10, 0x70, 0x6b, 0x4d, 0x3c, 0x8b, 0x52, 0x7d, 0xb9, 0xa3, 0xbe, 0x5c, 0x7a, 0xd1, + 0x97, 0x8a, 0x92, 0x4e, 0x86, 0xc4, 0xdc, 0xdc, 0x4f, 0xfd, 0xe4, 0x48, 0xed, 0x3e, 0x23, 0x7d, + 0xdc, 0x4d, 0x30, 0xdb, 0x82, 0x79, 0xfc, 0x4c, 0x59, 0xeb, 0x7a, 0xa5, 0x13, 0x24, 0xec, 0x2a, + 0xcc, 0xf3, 0xd1, 0x98, 0xab, 0xc8, 0x83, 0xd9, 0x31, 0x20, 0xae, 0x91, 0x27, 0x08, 0xd0, 0x04, + 0x20, 0x5a, 0x32, 0x01, 0xb6, 0xa5, 0x5f, 0xc0, 0xe2, 0xfb, 0x23, 0x77, 0x03, 0xd8, 0x43, 0x21, + 0xb5, 0x66, 0xe6, 0xf4, 0xf7, 0xe6, 0xa0, 0x6d, 0xc0, 0xa8, 0xcd, 0x63, 0xec, 0xf0, 0x60, 0x14, + 0xf8, 0x13, 0x9e, 0xf3, 0x54, 0x4a, 0x6a, 0x09, 0x45, 0x3a, 0xff, 0x78, 0x3c, 0x88, 0xa7, 0xf9, + 0x60, 0xc4, 0xc7, 0x29, 0x17, 0x7b, 0x24, 0x6e, 0x06, 0x16, 0x8a, 0x74, 0x13, 0xff, 0xa9, 0x49, + 0x27, 0xe4, 0xa1, 0x84, 0xaa, 0x3c, 0xa8, 0x98, 0xa3, 0x66, 0x91, 0x07, 0x15, 0x33, 0x52, 0xb6, + 0x43, 0xf3, 0x35, 0x76, 0xe8, 0x6d, 0xd8, 0x14, 0x16, 0x47, 0xea, 0xe6, 0xa0, 0x24, 0x26, 0xa7, + 0xd4, 0xb2, 0x2d, 0x58, 0xc5, 0x3e, 0x2b, 0x01, 0xcf, 0x82, 0x4f, 0x44, 0x66, 0xc2, 0xf1, 0x2a, + 0x38, 0xd2, 0xa2, 0x3a, 0x5a, 0xb4, 0xe2, 0xac, 0xa8, 0x82, 0x13, 0xad, 0xff, 0xd4, 0xa6, 0x6d, + 0x49, 0xda, 0x12, 0xee, 0x2e, 0x43, 0x7b, 0x3f, 0x8f, 0x13, 0xb5, 0x28, 0x5d, 0xe8, 0x88, 0xa2, + 0x3c, 0x19, 0xbc, 0x00, 0xe7, 0x49, 0x8a, 0x1e, 0xc5, 0x49, 0x1c, 0xc6, 0xe3, 0xd9, 0xfe, 0xf4, + 0x20, 0x1b, 0xa6, 0x41, 0x82, 0x11, 0x81, 0xfb, 0xb7, 0x0e, 0xac, 0x5b, 0xb5, 0x32, 0x95, 0xf1, + 0x05, 0x21, 0xd2, 0xfa, 0x48, 0x47, 0x08, 0xde, 0x9a, 0x61, 0x0e, 0x05, 0xa1, 0x48, 0x22, 0x3d, + 0x96, 0xa7, 0x3c, 0x37, 0x61, 0x45, 0xf5, 0x4c, 0x7d, 0x28, 0xa4, 0xb0, 0x57, 0x95, 0x42, 0xf9, + 0x7d, 0x57, 0x7e, 0xa0, 0x58, 0xfc, 0xb2, 0xf0, 0xab, 0xf9, 0x88, 0xc6, 0xa8, 0x62, 0xda, 0xbe, + 0xfa, 0xde, 0x74, 0xe6, 0x55, 0x0f, 0x86, 0x1a, 0xcc, 0xdc, 0x3f, 0x70, 0x00, 0x8a, 0xde, 0xa1, + 0x60, 0x14, 0x26, 0x5d, 0x5c, 0x56, 0x33, 0xcc, 0xf7, 0x6b, 0xd0, 0xd1, 0xd9, 0xfc, 0x62, 0x97, + 0x68, 0x2b, 0x0c, 0x1d, 0xae, 0x2b, 0xb0, 0x32, 0x0e, 0xe3, 0x03, 0xda, 0x62, 0xe9, 0xa8, 0x39, + 0x93, 0xe7, 0xa3, 0x5d, 0x01, 0xdf, 0x93, 0x68, 0xb1, 0xa5, 0x34, 0x8d, 0x2d, 0xc5, 0xfd, 0x4e, + 0x43, 0xe7, 0x80, 0x8b, 0x31, 0x9f, 0xaa, 0x65, 0x6c, 0xa7, 0x62, 0x1c, 0x4f, 0x49, 0xb9, 0x52, + 0xf6, 0x66, 0xef, 0x85, 0x81, 0xec, 0x0d, 0xe8, 0xa6, 0xc2, 0xfa, 0x28, 0xd3, 0xd4, 0x7c, 0x8e, + 0x69, 0x5a, 0x4e, 0xad, 0x7d, 0xe7, 0xe7, 0x60, 0xd5, 0x1f, 0x1d, 0xf3, 0x34, 0x0f, 0x28, 0xa2, + 0xa1, 0x4d, 0x5f, 0x18, 0xd4, 0x15, 0x03, 0xa7, 0xbd, 0xf8, 0x0a, 0xac, 0xc8, 0x33, 0x69, 0x4d, + 0x29, 0x6f, 0x22, 0x15, 0x30, 0x12, 0xba, 0xdf, 0x57, 0xe9, 0x66, 0x7b, 0x0d, 0x4f, 0x9f, 0x11, + 0x73, 0x74, 0x8d, 0xd2, 0xe8, 0x3e, 0x27, 0x53, 0xbf, 0x23, 0x15, 0x36, 0xc9, 0x24, 0xbc, 0x00, + 0x65, 0xaa, 0xde, 0x9e, 0xd2, 0xe6, 0xcb, 0x4c, 0xa9, 0xfb, 0x99, 0x03, 0x8b, 0xbb, 0x71, 0xb2, + 0x2b, 0x8f, 0x97, 0x49, 0x11, 0xf4, 0x8d, 0x0f, 0x55, 0x34, 0xbd, 0xe2, 0x46, 0xc5, 0x2b, 0xae, + 0xee, 0xb5, 0xcb, 0xe5, 0xbd, 0xf6, 0x57, 0xe0, 0x02, 0x45, 0xcb, 0x69, 0x9c, 0xc4, 0x29, 0x2a, + 0xa3, 0x1f, 0x8a, 0x8d, 0x35, 0x8e, 0xf2, 0x23, 0x65, 0xc6, 0x9e, 0x47, 0x42, 0xd1, 0x51, 0x98, + 0x1f, 0x0f, 0x84, 0x33, 0x2c, 0x7d, 0x03, 0x61, 0xdd, 0xaa, 0x15, 0xee, 0x97, 0xa0, 0x45, 0xce, + 0x2d, 0x0d, 0xeb, 0x4d, 0x68, 0x1d, 0xc5, 0xc9, 0xe0, 0x28, 0x88, 0x72, 0xa5, 0xdc, 0xdd, 0xc2, + 0xeb, 0xdc, 0xa5, 0x09, 0xd1, 0x04, 0xee, 0xdf, 0xcf, 0xc1, 0xe2, 0xfb, 0xd1, 0x71, 0x1c, 0x0c, + 0x29, 0x33, 0x3d, 0xe1, 0x93, 0x58, 0xdd, 0x7f, 0xc1, 0xdf, 0x38, 0x15, 0x74, 0x16, 0x9c, 0xe4, + 0x32, 0xb5, 0xac, 0x8a, 0xb8, 0xdd, 0xa7, 0xc5, 0x9d, 0x30, 0xa1, 0x3a, 0x06, 0x82, 0x8e, 0x7d, + 0x6a, 0x5e, 0x88, 0x93, 0xa5, 0xe2, 0x02, 0xd1, 0xbc, 0x71, 0x81, 0x88, 0xce, 0x31, 0xc4, 0x31, + 0x37, 0xc9, 0xd7, 0x92, 0xa7, 0x8a, 0x14, 0x88, 0xa4, 0x5c, 0x64, 0x39, 0xc8, 0x71, 0x58, 0x94, + 0x81, 0x88, 0x09, 0xa2, 0x73, 0x21, 0x3e, 0x10, 0x34, 0xc2, 0xf8, 0x9a, 0x10, 0x3a, 0x5b, 0xe5, + 0x3b, 0x75, 0x2d, 0x21, 0xf3, 0x25, 0x18, 0x2d, 0xf4, 0x88, 0x6b, 0x43, 0x2a, 0xc6, 0x00, 0xe2, + 0xce, 0x5b, 0x19, 0x37, 0xc2, 0x17, 0x71, 0x5c, 0xaf, 0xc2, 0x17, 0x14, 0x14, 0x3f, 0x0c, 0x0f, + 0xfc, 0xe1, 0x13, 0xba, 0xe9, 0x48, 0xa7, 0xf3, 0x2d, 0xcf, 0x06, 0xb1, 0xd7, 0xc6, 0x6a, 0xd2, + 0x49, 0x58, 0xd3, 0x33, 0x21, 0xb6, 0x03, 0x6d, 0x0a, 0xd9, 0xe4, 0x7a, 0x76, 0x69, 0x3d, 0x57, + 0xcd, 0x98, 0x8e, 0x56, 0xd4, 0x24, 0x72, 0xbf, 0x01, 0xec, 0xe6, 0x68, 0x24, 0x57, 0x55, 0x07, + 0x86, 0xc5, 0x7a, 0x38, 0xd6, 0x7a, 0xd4, 0xcc, 0x4b, 0xa3, 0x76, 0x5e, 0xdc, 0xbb, 0xd0, 0xde, + 0x33, 0x2e, 0x35, 0x92, 0x00, 0xa8, 0xeb, 0x8c, 0x52, 0x68, 0x0c, 0xc4, 0x68, 0xb0, 0x61, 0x36, + 0xe8, 0xfe, 0x22, 0xb0, 0x07, 0x41, 0x96, 0xeb, 0xfe, 0x89, 0x49, 0x7f, 0x0d, 0x3a, 0x3a, 0x8c, + 0x2e, 0x0e, 0xf1, 0xdb, 0x12, 0xa3, 0xc3, 0xf5, 0x9b, 0xe2, 0xf4, 0xbf, 0x3c, 0xb0, 0x2d, 0x58, + 0x0a, 0x04, 0x54, 0x96, 0x77, 0x45, 0xa9, 0xeb, 0xd1, 0x2b, 0x93, 0xa0, 0xb5, 0x57, 0xfe, 0xc0, + 0x81, 0x45, 0x39, 0x34, 0xf4, 0x29, 0xac, 0xeb, 0x9c, 0x62, 0x60, 0x16, 0x56, 0x7f, 0x09, 0xae, + 0x2a, 0xa9, 0x73, 0x75, 0x92, 0xca, 0xa0, 0x99, 0xf8, 0xf9, 0x11, 0x85, 0x21, 0x2d, 0x8f, 0x7e, + 0x63, 0xf0, 0x8f, 0xa1, 0xb1, 0xd0, 0x08, 0x0a, 0x8b, 0xeb, 0xee, 0x5d, 0x0a, 0xc3, 0x5b, 0xc1, + 0x71, 0x50, 0x74, 0x5e, 0x2e, 0x70, 0x9d, 0x06, 0x97, 0x77, 0x11, 0x0a, 0xb8, 0x98, 0x2f, 0xc9, + 0xa2, 0x3c, 0x5f, 0x92, 0xd4, 0xd3, 0xf5, 0x6e, 0x1f, 0x7a, 0x77, 0x78, 0xc8, 0x73, 0x7e, 0x33, + 0x0c, 0xcb, 0xfc, 0x2f, 0xc0, 0xf9, 0x9a, 0x3a, 0xe9, 0x9a, 0xdc, 0x83, 0xb5, 0x3b, 0xfc, 0x60, + 0x3a, 0x7e, 0xc0, 0x8f, 0x8b, 0xb3, 0x2a, 0x06, 0xcd, 0xec, 0x28, 0x3e, 0x91, 0x6b, 0x4b, 0xbf, + 0xd9, 0x2b, 0x00, 0x21, 0xd2, 0x0c, 0xb2, 0x84, 0x0f, 0xd5, 0xf5, 0x2f, 0x42, 0xf6, 0x13, 0x3e, + 0x74, 0xdf, 0x06, 0x66, 0xf2, 0x91, 0x43, 0x40, 0x6d, 0x9f, 0x1e, 0x0c, 0xb2, 0x59, 0x96, 0xf3, + 0x89, 0xba, 0xd7, 0x66, 0x42, 0xee, 0x15, 0xe8, 0xec, 0xf9, 0x33, 0x8f, 0x7f, 0x2c, 0x6f, 0xd4, + 0x62, 0x04, 0xec, 0xcf, 0x50, 0x94, 0x75, 0x04, 0x4c, 0xd5, 0xee, 0x7f, 0x36, 0x60, 0x41, 0x50, + 0x22, 0xd7, 0x11, 0xcf, 0xf2, 0x20, 0x12, 0xe7, 0x34, 0x92, 0xab, 0x01, 0x55, 0x64, 0xa3, 0x51, + 0x23, 0x1b, 0xd2, 0x27, 0x55, 0x57, 0x69, 0xa4, 0x10, 0x58, 0x18, 0x3a, 0x2f, 0xc5, 0xf9, 0xb7, + 0x08, 0xc1, 0x0a, 0xa0, 0x94, 0x12, 0x29, 0x6c, 0x8a, 0xe8, 0x9f, 0x12, 0x5a, 0x29, 0x0e, 0x26, + 0x54, 0x6b, 0xb9, 0x16, 0x85, 0xd4, 0x54, 0x2c, 0x57, 0xc5, 0x42, 0x2d, 0xbd, 0x84, 0x85, 0x12, + 0x8e, 0xea, 0xf3, 0x2c, 0x14, 0xbc, 0x8c, 0x85, 0x62, 0xb0, 0x7a, 0x8f, 0x73, 0x8f, 0xe3, 0xde, + 0xa7, 0xc4, 0xe9, 0xbb, 0x0e, 0xac, 0xca, 0x6d, 0x5b, 0xd7, 0xb1, 0xd7, 0xac, 0x3d, 0xde, 0xa9, + 0x4b, 0xf7, 0xbf, 0x0e, 0xcb, 0xb4, 0xf3, 0xea, 0xdc, 0x8f, 0x4c, 0x54, 0x59, 0x20, 0x8e, 0x43, + 0x25, 0xb0, 0x27, 0x41, 0x28, 0x17, 0xc5, 0x84, 0x54, 0xfa, 0x08, 0xa3, 0x60, 0x5a, 0x12, 0xc7, + 0xd3, 0x65, 0xf7, 0x6f, 0x1c, 0x58, 0x33, 0x3a, 0x2c, 0xa5, 0xf0, 0x06, 0xa8, 0xf3, 0x71, 0x91, + 0x22, 0x12, 0xca, 0x74, 0xce, 0x76, 0x41, 0x8a, 0xcf, 0x2c, 0x62, 0x5a, 0x4c, 0x7f, 0x46, 0x1d, + 0xcc, 0xa6, 0x13, 0xe9, 0x67, 0x98, 0x10, 0x0a, 0xd2, 0x09, 0xe7, 0x4f, 0x34, 0xc9, 0x1c, 0x91, + 0x58, 0x18, 0x1d, 0x7f, 0xa2, 0xc7, 0xa0, 0x89, 0xc4, 0x8d, 0x1f, 0x1b, 0x74, 0xff, 0xc1, 0x81, + 0x75, 0xe1, 0xfa, 0x49, 0xc7, 0x5a, 0xdf, 0x46, 0x5c, 0x10, 0xbe, 0xae, 0xd0, 0xc8, 0xdd, 0x33, + 0x9e, 0x2c, 0xb3, 0x2f, 0xbe, 0xa4, 0xbb, 0xaa, 0x8f, 0xbd, 0x4f, 0x59, 0x8b, 0xb9, 0xba, 0xb5, + 0x78, 0xce, 0x4c, 0xd7, 0xa5, 0x44, 0xe6, 0x6b, 0x53, 0x22, 0xb7, 0x16, 0x61, 0x3e, 0x1b, 0xc6, + 0x09, 0x77, 0x37, 0x61, 0xc3, 0x1e, 0x9c, 0x34, 0x41, 0xdf, 0x73, 0xa0, 0x77, 0x4f, 0x24, 0x08, + 0x83, 0x68, 0xbc, 0x1b, 0x64, 0x79, 0x9c, 0xea, 0xeb, 0xd7, 0x97, 0x00, 0xb2, 0xdc, 0x4f, 0x73, + 0x71, 0x2d, 0x49, 0x26, 0x33, 0x0a, 0x04, 0xfb, 0xc8, 0xa3, 0x91, 0xa8, 0x15, 0x6b, 0xa3, 0xcb, + 0xb8, 0x30, 0x74, 0x24, 0x3f, 0x88, 0x0f, 0x0f, 0x33, 0xae, 0x9d, 0x53, 0x13, 0xc3, 0xf8, 0x16, + 0x35, 0x1e, 0x23, 0x3a, 0x7e, 0x4c, 0xa6, 0x56, 0x78, 0x7d, 0x25, 0xd4, 0xfd, 0x6b, 0x07, 0x56, + 0x8a, 0x4e, 0xde, 0x45, 0xd0, 0xb6, 0x0e, 0xa2, 0x6b, 0x86, 0x75, 0x50, 0x69, 0x96, 0x60, 0x34, + 0x08, 0x22, 0xd9, 0x37, 0x03, 0x21, 0x8d, 0x95, 0xa5, 0x78, 0xaa, 0xae, 0x80, 0x99, 0x90, 0x38, + 0xdf, 0xcd, 0xf1, 0x6b, 0x71, 0xff, 0x4b, 0x96, 0xe8, 0x56, 0xd9, 0x24, 0xa7, 0xaf, 0x16, 0x84, + 0xdb, 0x2b, 0x8b, 0x6a, 0x7f, 0x5a, 0x24, 0x14, 0x7f, 0xba, 0x7f, 0xe8, 0xc0, 0xf9, 0x9a, 0xc9, + 0x95, 0x9a, 0x71, 0x07, 0xd6, 0x0e, 0x75, 0xa5, 0x9a, 0x00, 0xa1, 0x1e, 0x9b, 0x52, 0x8a, 0x4a, + 0x83, 0xf6, 0xaa, 0x1f, 0xa0, 0x13, 0x4c, 0xd9, 0x21, 0x31, 0xa5, 0xd6, 0xd5, 0x88, 0x6a, 0xc5, + 0xce, 0xf7, 0x1b, 0xd0, 0x15, 0x07, 0x12, 0xe2, 0x01, 0x0e, 0x4f, 0xd9, 0x07, 0xb0, 0x28, 0x9f, + 0x3b, 0xb1, 0xb3, 0xb2, 0x59, 0xfb, 0x81, 0x55, 0x7f, 0xb3, 0x0c, 0x4b, 0xd9, 0x59, 0xff, 0xdd, + 0xcf, 0xfe, 0xf9, 0x8f, 0x1a, 0xcb, 0xac, 0xbd, 0x7d, 0xfc, 0xd6, 0xf6, 0x98, 0x47, 0x19, 0xf2, + 0xf8, 0x75, 0x80, 0xe2, 0xc5, 0x10, 0xeb, 0x69, 0x27, 0xa3, 0xf4, 0xc2, 0xa9, 0x7f, 0xbe, 0xa6, + 0x46, 0xf2, 0x3d, 0x4f, 0x7c, 0xd7, 0xdd, 0x2e, 0xf2, 0x0d, 0xa2, 0x20, 0x17, 0xcf, 0x87, 0xde, + 0x75, 0xb6, 0xd8, 0x08, 0x3a, 0xe6, 0xcb, 0x21, 0xa6, 0x02, 0xe3, 0x9a, 0xe7, 0x48, 0xfd, 0x0b, + 0xb5, 0x75, 0x2a, 0x2b, 0x40, 0x6d, 0x9c, 0x75, 0x57, 0xb1, 0x8d, 0x29, 0x51, 0xe8, 0x56, 0x76, + 0xfe, 0xf1, 0x02, 0xb4, 0x74, 0x72, 0x89, 0x7d, 0x1b, 0x96, 0xad, 0x33, 0x1c, 0xa6, 0x18, 0xd7, + 0x1d, 0xf9, 0xf4, 0x2f, 0xd6, 0x57, 0xca, 0x66, 0x2f, 0x51, 0xb3, 0x3d, 0xb6, 0x89, 0xcd, 0xca, + 0x43, 0x90, 0x6d, 0x3a, 0xb9, 0x12, 0xb7, 0xc8, 0x9e, 0x40, 0xd7, 0x3e, 0x77, 0x61, 0x17, 0x6d, + 0x83, 0x52, 0x6a, 0xed, 0x95, 0x53, 0x6a, 0x65, 0x73, 0x17, 0xa9, 0xb9, 0x4d, 0xb6, 0x61, 0x36, + 0xa7, 0x93, 0x3e, 0x9c, 0xee, 0xfd, 0x99, 0x4f, 0x8a, 0xd8, 0x2b, 0x7a, 0xa9, 0xeb, 0x9e, 0x1a, + 0xe9, 0x45, 0xab, 0xbe, 0x37, 0x72, 0x7b, 0xd4, 0x14, 0x63, 0x34, 0xa1, 0xe6, 0x8b, 0x22, 0xf6, + 0x11, 0xb4, 0xf4, 0x33, 0x02, 0x76, 0xce, 0x78, 0xbb, 0x61, 0xbe, 0x6d, 0xe8, 0xf7, 0xaa, 0x15, + 0x75, 0x4b, 0x65, 0x72, 0x46, 0x81, 0x78, 0x00, 0x67, 0xa5, 0x93, 0x7a, 0xc0, 0x7f, 0x9c, 0x91, + 0xd4, 0x3c, 0x84, 0xba, 0xee, 0xb0, 0x1b, 0xb0, 0xa4, 0x5e, 0x67, 0xb0, 0xcd, 0xfa, 0x57, 0x26, + 0xfd, 0x73, 0x15, 0x5c, 0xea, 0xf3, 0x4d, 0x80, 0xe2, 0x65, 0x81, 0x96, 0xfc, 0xca, 0x7b, 0x07, + 0x3d, 0x89, 0x35, 0xcf, 0x10, 0xc6, 0xf4, 0x8e, 0xc2, 0x7e, 0xb8, 0xc0, 0x5e, 0x2d, 0xe8, 0x6b, + 0x9f, 0x34, 0x3c, 0x87, 0xa1, 0xbb, 0x49, 0x73, 0xb7, 0xca, 0x48, 0x95, 0x22, 0x7e, 0xa2, 0x6e, + 0xc0, 0xde, 0x81, 0xb6, 0xf1, 0x5a, 0x81, 0x29, 0x0e, 0xd5, 0x97, 0x0e, 0xfd, 0x7e, 0x5d, 0x95, + 0xec, 0xee, 0x57, 0x60, 0xd9, 0x7a, 0x76, 0xa0, 0x35, 0xa3, 0xee, 0x51, 0x83, 0xd6, 0x8c, 0xfa, + 0x97, 0x0a, 0xdf, 0x84, 0xb6, 0xf1, 0x48, 0x80, 0x19, 0x37, 0x7f, 0x4a, 0xcf, 0x03, 0x74, 0x8f, + 0xea, 0xde, 0x14, 0x6c, 0xd0, 0x78, 0xbb, 0x6e, 0x0b, 0xc7, 0x4b, 0xd7, 0x40, 0x51, 0x48, 0xbe, + 0x0d, 0x5d, 0xfb, 0xd9, 0x80, 0xd6, 0xaa, 0xda, 0x07, 0x08, 0x5a, 0xab, 0x4e, 0x79, 0x6b, 0x20, + 0x05, 0x72, 0x6b, 0x5d, 0x37, 0xb2, 0xfd, 0xa9, 0x3c, 0x5a, 0x79, 0xc6, 0xbe, 0x8e, 0xa6, 0x43, + 0xde, 0xcb, 0x65, 0xc5, 0x63, 0x09, 0xfb, 0xf6, 0xae, 0x96, 0xf6, 0xca, 0x15, 0x5e, 0x77, 0x8d, + 0x98, 0xb7, 0x59, 0x31, 0x02, 0x61, 0xa1, 0xe9, 0x7e, 0xae, 0x61, 0xa1, 0xcd, 0x2b, 0xbc, 0x86, + 0x85, 0xb6, 0xae, 0xf1, 0x96, 0x2d, 0x74, 0x1e, 0x20, 0x8f, 0x08, 0x56, 0x4a, 0xa7, 0xfd, 0x5a, + 0x59, 0xea, 0xef, 0x0a, 0xf5, 0x2f, 0x3d, 0xff, 0x92, 0x80, 0x6d, 0x66, 0x94, 0x79, 0xd9, 0x56, + 0x57, 0xbb, 0x7e, 0x03, 0x3a, 0xe6, 0x75, 0x6f, 0x6d, 0xb3, 0x6b, 0x2e, 0xa9, 0x6b, 0x9b, 0x5d, + 0x77, 0x3f, 0x5c, 0x2d, 0x2e, 0xeb, 0x98, 0xcd, 0xb0, 0x6f, 0xc2, 0x8a, 0x71, 0xaf, 0x64, 0x7f, + 0x16, 0x0d, 0xb5, 0xf0, 0x54, 0x6f, 0x02, 0xf6, 0xeb, 0xfc, 0x33, 0xf7, 0x1c, 0x31, 0x5e, 0x73, + 0x2d, 0xc6, 0x28, 0x38, 0xb7, 0xa1, 0x6d, 0xde, 0x59, 0x79, 0x0e, 0xdf, 0x73, 0x46, 0x95, 0x79, + 0x29, 0xee, 0xba, 0xc3, 0xfe, 0xc4, 0x81, 0x8e, 0x79, 0xc7, 0x94, 0x59, 0xd9, 0xdc, 0x12, 0x9f, + 0x9e, 0x59, 0x67, 0x32, 0x72, 0x3d, 0xea, 0xe4, 0x83, 0xad, 0xaf, 0x58, 0x93, 0xfc, 0xa9, 0xe5, + 0xe7, 0x5f, 0x2b, 0xbf, 0xe4, 0x7b, 0x56, 0x26, 0x30, 0x6f, 0x4b, 0x3e, 0xbb, 0xee, 0xb0, 0x77, + 0xc5, 0x6b, 0x4f, 0x15, 0xd7, 0x33, 0xc3, 0xb8, 0x95, 0xa7, 0xcc, 0x7c, 0x18, 0x79, 0xd5, 0xb9, + 0xee, 0xb0, 0x6f, 0x89, 0x07, 0x7b, 0xf2, 0x5b, 0x9a, 0xf9, 0x97, 0xfd, 0xde, 0x7d, 0x9d, 0x46, + 0x73, 0xc9, 0x3d, 0x6f, 0x8d, 0xa6, 0x6c, 0xdd, 0xf7, 0x00, 0x8a, 0x24, 0x0d, 0x2b, 0x65, 0x2c, + 0xb4, 0xdd, 0xab, 0xe6, 0x71, 0xec, 0x15, 0x55, 0x89, 0x0d, 0xe4, 0xf8, 0x91, 0x10, 0x46, 0x49, + 0x9f, 0xe9, 0x25, 0xad, 0x26, 0x5b, 0xfa, 0xfd, 0xba, 0xaa, 0x3a, 0x51, 0x54, 0xfc, 0xd9, 0x63, + 0x58, 0x7e, 0x10, 0xc7, 0x4f, 0xa6, 0x89, 0x4e, 0x16, 0xda, 0x39, 0x83, 0x5d, 0x3f, 0x3b, 0xea, + 0x97, 0x46, 0xe1, 0x5e, 0x26, 0x56, 0x7d, 0xd6, 0x33, 0x58, 0x6d, 0x7f, 0x5a, 0xa4, 0x88, 0x9e, + 0x31, 0x1f, 0xd6, 0xf4, 0x1e, 0xa7, 0x3b, 0xde, 0xb7, 0xd9, 0x98, 0x99, 0x9a, 0x4a, 0x13, 0x96, + 0xd7, 0xa1, 0x7a, 0xbb, 0x9d, 0x29, 0x9e, 0xd7, 0x1d, 0xb6, 0x07, 0x9d, 0x3b, 0x7c, 0x18, 0x8f, + 0xb8, 0x8c, 0xf2, 0xd7, 0x8b, 0x8e, 0xeb, 0xf4, 0x40, 0x7f, 0xd9, 0x02, 0x6d, 0xad, 0x4f, 0xfc, + 0x59, 0xca, 0x3f, 0xde, 0xfe, 0x54, 0xe6, 0x0f, 0x9e, 0x29, 0xad, 0x57, 0x39, 0x0f, 0x4b, 0xeb, + 0x4b, 0x49, 0x12, 0x4b, 0xeb, 0x2b, 0x49, 0x12, 0x6b, 0xaa, 0x55, 0xce, 0x85, 0x85, 0xb0, 0x56, + 0xc9, 0xab, 0xe8, 0x9d, 0xf2, 0xb4, 0x6c, 0x4c, 0xff, 0xf2, 0xe9, 0x04, 0x76, 0x6b, 0x5b, 0x76, + 0x6b, 0xfb, 0xb0, 0x7c, 0x87, 0x8b, 0xc9, 0x12, 0x27, 0x92, 0x7d, 0xdb, 0x8c, 0x98, 0xa7, 0x97, + 0x65, 0x13, 0x43, 0x75, 0xb6, 0x59, 0xa7, 0xe3, 0x40, 0xf6, 0x11, 0xb4, 0xef, 0xf3, 0x5c, 0x1d, + 0x41, 0x6a, 0x7f, 0xa3, 0x74, 0x26, 0xd9, 0xaf, 0x39, 0xc1, 0xb4, 0x65, 0x86, 0xb8, 0x6d, 0xf3, + 0xd1, 0x98, 0x0b, 0x65, 0x1f, 0x04, 0xa3, 0x67, 0xec, 0x57, 0x89, 0xb9, 0xbe, 0xb5, 0xb0, 0x69, + 0x9c, 0x5c, 0x99, 0xcc, 0x57, 0x4a, 0x78, 0x1d, 0xe7, 0x28, 0x1e, 0x71, 0x63, 0x83, 0x8b, 0xa0, + 0x6d, 0x5c, 0xa9, 0xd1, 0x0a, 0x54, 0xbd, 0xc6, 0xa3, 0x15, 0xa8, 0xe6, 0x06, 0x8e, 0x7b, 0x95, + 0xda, 0x71, 0xd9, 0xe5, 0xa2, 0x1d, 0x71, 0xeb, 0xa6, 0x68, 0x69, 0xfb, 0x53, 0x7f, 0x92, 0x3f, + 0x63, 0x1f, 0xd2, 0x83, 0x15, 0xf3, 0x98, 0xb5, 0xf0, 0x77, 0xca, 0x27, 0xb2, 0x7a, 0xb2, 0x8c, + 0x2a, 0xdb, 0x07, 0x12, 0x4d, 0xd1, 0x3e, 0xf8, 0x45, 0x80, 0xfd, 0x3c, 0x4e, 0xee, 0xf8, 0x7c, + 0x12, 0x47, 0x85, 0xe5, 0x2a, 0x8e, 0x12, 0x0b, 0xcb, 0x65, 0x9c, 0x27, 0xb2, 0x0f, 0x0d, 0x8f, + 0xd3, 0x3a, 0xa5, 0x56, 0xc2, 0x75, 0xea, 0x69, 0xa3, 0x9e, 0x90, 0x9a, 0x13, 0xc7, 0xeb, 0x0e, + 0xfa, 0x8f, 0x45, 0x16, 0x4f, 0xfb, 0x8f, 0x95, 0x04, 0xa1, 0x36, 0x7b, 0x35, 0x29, 0xbf, 0x3d, + 0x68, 0x15, 0x69, 0x21, 0xb5, 0x25, 0x95, 0x93, 0x48, 0x7a, 0x8f, 0xa9, 0x24, 0x6b, 0xdc, 0x55, + 0x9a, 0x2a, 0x60, 0x4b, 0x38, 0x55, 0x94, 0x81, 0x09, 0x60, 0x5d, 0x74, 0x50, 0x6f, 0x98, 0x74, + 0x38, 0xa6, 0x46, 0x52, 0x93, 0x30, 0xd1, 0xda, 0x5c, 0x9b, 0x6f, 0xb0, 0x62, 0x3b, 0x94, 0x56, + 0x71, 0x30, 0x87, 0xa6, 0x79, 0x02, 0x6b, 0x95, 0x60, 0x59, 0xab, 0xf4, 0x69, 0x39, 0x0a, 0xad, + 0xd2, 0xa7, 0xc6, 0xd9, 0xee, 0x59, 0x6a, 0x72, 0xc5, 0x05, 0x6c, 0x32, 0x3b, 0x09, 0xf2, 0xe1, + 0xd1, 0xbb, 0xce, 0xd6, 0xc1, 0x02, 0xfd, 0x9f, 0xc8, 0xe7, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, + 0xbe, 0xb8, 0xff, 0xb8, 0x81, 0x44, 0x00, 0x00, } diff --git a/lnrpc/rpc.pb.gw.go b/lnrpc/rpc.pb.gw.go index 1bfcec38..0453e1c8 100644 --- a/lnrpc/rpc.pb.gw.go +++ b/lnrpc/rpc.pb.gw.go @@ -592,18 +592,10 @@ func RegisterWalletUnlockerHandlerFromEndpoint(ctx context.Context, mux *runtime // RegisterWalletUnlockerHandler registers the http handlers for service WalletUnlocker to "mux". // The handlers forward requests to the grpc endpoint over "conn". func RegisterWalletUnlockerHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterWalletUnlockerHandlerClient(ctx, mux, NewWalletUnlockerClient(conn)) -} - -// RegisterWalletUnlockerHandler registers the http handlers for service WalletUnlocker to "mux". -// The handlers forward requests to the grpc endpoint over the given implementation of "WalletUnlockerClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "WalletUnlockerClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "WalletUnlockerClient" to call the correct interceptors. -func RegisterWalletUnlockerHandlerClient(ctx context.Context, mux *runtime.ServeMux, client WalletUnlockerClient) error { + client := NewWalletUnlockerClient(conn) mux.Handle("GET", pattern_WalletUnlocker_GenSeed_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -632,7 +624,7 @@ func RegisterWalletUnlockerHandlerClient(ctx context.Context, mux *runtime.Serve }) mux.Handle("POST", pattern_WalletUnlocker_InitWallet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -661,7 +653,7 @@ func RegisterWalletUnlockerHandlerClient(ctx context.Context, mux *runtime.Serve }) mux.Handle("POST", pattern_WalletUnlocker_UnlockWallet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -736,18 +728,10 @@ func RegisterLightningHandlerFromEndpoint(ctx context.Context, mux *runtime.Serv // RegisterLightningHandler registers the http handlers for service Lightning to "mux". // The handlers forward requests to the grpc endpoint over "conn". func RegisterLightningHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterLightningHandlerClient(ctx, mux, NewLightningClient(conn)) -} - -// RegisterLightningHandler registers the http handlers for service Lightning to "mux". -// The handlers forward requests to the grpc endpoint over the given implementation of "LightningClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "LightningClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "LightningClient" to call the correct interceptors. -func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, client LightningClient) error { + client := NewLightningClient(conn) mux.Handle("GET", pattern_Lightning_WalletBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -776,7 +760,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_ChannelBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -805,7 +789,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_GetTransactions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -834,7 +818,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("POST", pattern_Lightning_SendCoins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -863,7 +847,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_NewWitnessAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -892,7 +876,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("POST", pattern_Lightning_ConnectPeer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -921,7 +905,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("DELETE", pattern_Lightning_DisconnectPeer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -950,7 +934,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_ListPeers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -979,7 +963,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1008,7 +992,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_PendingChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1037,7 +1021,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_ListChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1066,7 +1050,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("POST", pattern_Lightning_OpenChannelSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1095,7 +1079,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("DELETE", pattern_Lightning_CloseChannel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1124,7 +1108,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("POST", pattern_Lightning_SendPaymentSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1153,7 +1137,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("POST", pattern_Lightning_AddInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1182,7 +1166,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_ListInvoices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1211,7 +1195,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_LookupInvoice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1240,7 +1224,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_SubscribeInvoices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1269,7 +1253,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_DecodePayReq_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1298,7 +1282,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_ListPayments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1327,7 +1311,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("DELETE", pattern_Lightning_DeleteAllPayments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1356,7 +1340,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_DescribeGraph_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1385,7 +1369,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_GetChanInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1414,7 +1398,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_GetNodeInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1443,7 +1427,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_QueryRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1472,7 +1456,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_GetNetworkInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1501,7 +1485,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("GET", pattern_Lightning_FeeReport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1530,7 +1514,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("POST", pattern_Lightning_UpdateChannelPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { @@ -1559,7 +1543,7 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) mux.Handle("POST", pattern_Lightning_ForwardingHistory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) + ctx, cancel := context.WithCancel(ctx) defer cancel() if cn, ok := w.(http.CloseNotifier); ok { go func(done <-chan struct{}, closed <-chan bool) { diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index d14f3908..5113369a 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -1369,6 +1369,34 @@ message ClosedChannelUpdate { ChannelPoint chan_point = 4; } +message HopHint { + /// The public key of the node at the start of the channel. + string node_id = 1 [json_name = "node_id"]; + + /// The unique identifier of the channel. + uint64 chan_id = 2 [json_name = "chan_id"]; + + /// The base fee of the channel denominated in millisatoshis. + uint32 fee_base_msat = 3 [json_name = "fee_base_msat"]; + + /** + The fee rate of the channel for sending one satoshi across it denominated in + millionths of a satoshi. + */ + uint32 fee_proportional_millionths = 4 [json_name = "fee_proportional_millionths"]; + + /// The time-lock delta of the channel. + uint32 cltv_expiry_delta = 5 [json_name = "cltv_expiry_delta"]; +} + +message RouteHint { + /** + A list of hop hints that when chained together can assist in reaching a + specific destination. + */ + repeated HopHint hop_hints = 1 [json_name = "hop_hints"]; +} + message Invoice { /** An optional memo to attach along with the invoice. Used for record keeping @@ -1424,6 +1452,12 @@ message Invoice { /// Delta to use for the time-lock of the CLTV extended to the final hop. uint64 cltv_expiry = 13 [json_name = "cltv_expiry"]; + + /** + Route hints that can each be individually used to assist in reaching the + invoice's destination. + */ + repeated RouteHint route_hints = 14 [json_name = "route_hints"]; } message AddInvoiceResponse { bytes r_hash = 1 [json_name = "r_hash"]; @@ -1513,6 +1547,7 @@ message PayReq { string description_hash = 7 [json_name = "description_hash"]; string fallback_addr = 8 [json_name = "fallback_addr"]; int64 cltv_expiry = 9 [json_name = "cltv_expiry"]; + repeated RouteHint route_hints = 10 [json_name = "route_hints"]; } message FeeReportRequest {} diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index e9b696e9..b598ad04 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -789,14 +789,6 @@ } }, "definitions": { - "NewAddressRequestAddressType": { - "type": "string", - "enum": [ - "WITNESS_PUBKEY_HASH", - "NESTED_PUBKEY_HASH" - ], - "default": "WITNESS_PUBKEY_HASH" - }, "PendingChannelsResponseClosedChannel": { "type": "object", "properties": { @@ -1515,6 +1507,35 @@ } } }, + "lnrpcHopHint": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "/ The public key of the node at the start of the channel." + }, + "chan_id": { + "type": "string", + "format": "uint64", + "description": "/ The unique identifier of the channel." + }, + "fee_base_msat": { + "type": "integer", + "format": "int64", + "description": "/ The base fee of the channel denominated in millisatoshis." + }, + "fee_proportional_millionths": { + "type": "integer", + "format": "int64", + "description": "*\nThe fee rate of the channel for sending one satoshi across it denominated in\nmillionths of a satoshi." + }, + "cltv_expiry_delta": { + "type": "integer", + "format": "int64", + "description": "/ The time-lock delta of the channel." + } + } + }, "lnrpcInitWalletRequest": { "type": "object", "properties": { @@ -1604,6 +1625,13 @@ "type": "string", "format": "uint64", "description": "/ Delta to use for the time-lock of the CLTV extended to the final hop." + }, + "route_hints": { + "type": "array", + "items": { + "$ref": "#/definitions/lnrpcRouteHint" + }, + "description": "*\nRoute hints that can each be individually used to assist in reaching the\ninvoice's destination." } } }, @@ -1887,6 +1915,12 @@ "cltv_expiry": { "type": "string", "format": "int64" + }, + "route_hints": { + "type": "array", + "items": { + "$ref": "#/definitions/lnrpcRouteHint" + } } } }, @@ -2127,6 +2161,18 @@ }, "description": "*\nA path through the channel graph which runs over one or more channels in\nsuccession. This struct carries all the information required to craft the\nSphinx onion packet, and send the payment along the first hop in the path. A\nroute is only selected as valid if all the channels have sufficient capacity to\ncarry the initial payment amount after fees are accounted for." }, + "lnrpcRouteHint": { + "type": "object", + "properties": { + "hop_hints": { + "type": "array", + "items": { + "$ref": "#/definitions/lnrpcHopHint" + }, + "description": "*\nA list of hop hints that when chained together can assist in reaching a\nspecific destination." + } + } + }, "lnrpcRoutingPolicy": { "type": "object", "properties": { From 1b137bf14cb8e13f96107dc77f11f2b609045c27 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 28 Mar 2018 00:01:21 -0400 Subject: [PATCH 08/14] rpcserver: populate the routing hints of an invoice when decoding it --- rpcserver.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/rpcserver.go b/rpcserver.go index 8ebf61e9..792f8607 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2282,6 +2282,9 @@ func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) { // The expiry will default to 9 blocks if not specified explicitly. cltvExpiry := decoded.MinFinalCLTVExpiry() + // Convert between the `lnrpc` and `routing` types. + routeHints := createRPCRouteHints(decoded.RouteHints) + preimage := invoice.Terms.PaymentPreimage satAmt := invoice.Terms.Value.ToSatoshis() @@ -2299,9 +2302,40 @@ func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) { Expiry: expiry, CltvExpiry: cltvExpiry, FallbackAddr: fallbackAddr, + RouteHints: routeHints, }, nil } +// createRPCRouteHints takes in the decoded form of an invoice's route hints +// and converts them into the lnrpc type. +func createRPCRouteHints(routeHints [][]routing.HopHint) []*lnrpc.RouteHint { + var res []*lnrpc.RouteHint + + for _, route := range routeHints { + hopHints := make([]*lnrpc.HopHint, 0, len(route)) + for _, hop := range route { + pubKey := hex.EncodeToString( + hop.NodeID.SerializeCompressed(), + ) + + hint := &lnrpc.HopHint{ + NodeId: pubKey, + ChanId: hop.ChannelID, + FeeBaseMsat: hop.FeeBaseMSat, + FeeProportionalMillionths: hop.FeeProportionalMillionths, + CltvExpiryDelta: uint32(hop.CLTVExpiryDelta), + } + + hopHints = append(hopHints, hint) + } + + routeHint := &lnrpc.RouteHint{HopHints: hopHints} + res = append(res, routeHint) + } + + return res +} + // LookupInvoice attempts to look up an invoice according to its payment hash. // The passed payment hash *must* be exactly 32 bytes, if not an error is // returned. @@ -3120,6 +3154,9 @@ func (r *rpcServer) DecodePayReq(ctx context.Context, // explicitly. expiry := int64(payReq.Expiry().Seconds()) + // Convert between the `lnrpc` and `routing` types. + routeHints := createRPCRouteHints(payReq.RouteHints) + amt := int64(0) if payReq.MilliSat != nil { amt = int64(payReq.MilliSat.ToSatoshis()) @@ -3136,6 +3173,7 @@ func (r *rpcServer) DecodePayReq(ctx context.Context, FallbackAddr: fallbackAddr, Expiry: expiry, CltvExpiry: int64(payReq.MinFinalCLTVExpiry()), + RouteHints: routeHints, }, nil } From 1713394eb3215270debc09b3c847c1b2f1aa7ae6 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 28 Mar 2018 00:03:33 -0400 Subject: [PATCH 09/14] lnrpc: add `private` field to addinvoice request In this commit, we add a `private` field to the `AddInvoice` RPC's request to denote whether the invoice being created should include routing hints for private channels to assist the payer in reaching the destination. --- lnrpc/rpc.pb.go | 697 +++++++++++++++++++++-------------------- lnrpc/rpc.proto | 3 + lnrpc/rpc.swagger.json | 5 + 3 files changed, 361 insertions(+), 344 deletions(-) diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 5f8377a4..d78e9f28 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -3343,6 +3343,8 @@ type Invoice struct { // Route hints that can each be individually used to assist in reaching the // invoice's destination. RouteHints []*RouteHint `protobuf:"bytes,14,rep,name=route_hints" json:"route_hints,omitempty"` + // / Whether this invoice should include routing hints for private channels. + Private bool `protobuf:"varint,15,opt,name=private" json:"private,omitempty"` } func (m *Invoice) Reset() { *m = Invoice{} } @@ -3448,6 +3450,13 @@ func (m *Invoice) GetRouteHints() []*RouteHint { return nil } +func (m *Invoice) GetPrivate() bool { + if m != nil { + return m.Private + } + return false +} + type AddInvoiceResponse struct { RHash []byte `protobuf:"bytes,1,opt,name=r_hash,proto3" json:"r_hash,omitempty"` // * @@ -6292,353 +6301,353 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 5560 bytes of a gzipped FileDescriptorProto + // 5566 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0xcd, 0x93, 0x1c, 0xc9, 0x55, 0x57, 0xf5, 0xf4, 0x7c, 0xf4, 0xeb, 0x9e, 0x9e, 0x99, 0x9c, 0xd1, 0xa8, 0xd5, 0xd2, 0x6a, 0xb5, 0xe5, 0x8d, 0x95, 0x18, 0x16, 0x8d, 0x76, 0x6c, 0x2f, 0xeb, 0x15, 0xac, 0xd1, 0xf7, 0xac, 0xad, 0x95, 0xc7, 0x35, 0x92, 0x17, 0xbc, 0x40, 0xbb, 0xa6, 0x3b, 0xa7, 0xa7, 0xac, 0xea, 0xaa, 0xda, 0xaa, 0xea, 0x19, 0xf5, 0x2e, 0x8a, 0xe0, 0x23, 0x82, 0x13, 0x0e, 0x0e, 0x70, 0x31, 0x04, - 0x41, 0x84, 0x7d, 0x81, 0x03, 0x47, 0x4e, 0xe6, 0x2f, 0x70, 0x04, 0x41, 0x10, 0x7b, 0x72, 0x70, - 0xe3, 0xe3, 0x00, 0x04, 0x17, 0x22, 0xb8, 0x70, 0x20, 0x88, 0xf7, 0xf2, 0xa3, 0x32, 0xab, 0x6a, - 0x24, 0xd9, 0x06, 0xdf, 0x3a, 0x7f, 0xf9, 0xea, 0xe5, 0xd7, 0x7b, 0x2f, 0xdf, 0x7b, 0x99, 0xd9, - 0xd0, 0x4a, 0x93, 0xe1, 0xb5, 0x24, 0x8d, 0xf3, 0x98, 0xcd, 0x87, 0x51, 0x9a, 0x0c, 0xfb, 0x17, - 0xc7, 0x71, 0x3c, 0x0e, 0xf9, 0xb6, 0x9f, 0x04, 0xdb, 0x7e, 0x14, 0xc5, 0xb9, 0x9f, 0x07, 0x71, - 0x94, 0x09, 0x22, 0xf7, 0x5b, 0xd0, 0xbd, 0xcf, 0xa3, 0x7d, 0xce, 0x47, 0x1e, 0xff, 0x78, 0xca, - 0xb3, 0x9c, 0xfd, 0x3c, 0xac, 0xf9, 0xfc, 0x13, 0xce, 0x47, 0x83, 0xc4, 0xcf, 0xb2, 0xe4, 0x28, - 0xf5, 0x33, 0xde, 0x73, 0x2e, 0x3b, 0x57, 0x3b, 0xde, 0xaa, 0xa8, 0xd8, 0xd3, 0x38, 0x7b, 0x0d, - 0x3a, 0x19, 0x92, 0xf2, 0x28, 0x4f, 0xe3, 0x64, 0xd6, 0x6b, 0x10, 0x5d, 0x1b, 0xb1, 0xbb, 0x02, - 0x72, 0x43, 0x58, 0xd1, 0x2d, 0x64, 0x49, 0x1c, 0x65, 0x9c, 0x5d, 0x87, 0x8d, 0x61, 0x90, 0x1c, - 0xf1, 0x74, 0x40, 0x1f, 0x4f, 0x22, 0x3e, 0x89, 0xa3, 0x60, 0xd8, 0x73, 0x2e, 0xcf, 0x5d, 0x6d, - 0x79, 0x4c, 0xd4, 0xe1, 0x17, 0x1f, 0xc8, 0x1a, 0x76, 0x05, 0x56, 0x78, 0x24, 0x70, 0x3e, 0xa2, - 0xaf, 0x64, 0x53, 0xdd, 0x02, 0xc6, 0x0f, 0xdc, 0x3f, 0x75, 0x60, 0xed, 0xfd, 0x28, 0xc8, 0x3f, - 0xf4, 0xc3, 0x90, 0xe7, 0x6a, 0x4c, 0x57, 0x60, 0xe5, 0x84, 0x00, 0x1a, 0xd3, 0x49, 0x9c, 0x8e, - 0xe4, 0x88, 0xba, 0x02, 0xde, 0x93, 0xe8, 0xa9, 0x3d, 0x6b, 0x9c, 0xda, 0xb3, 0xda, 0xe9, 0x9a, - 0xab, 0x9f, 0x2e, 0x77, 0x03, 0x98, 0xd9, 0x39, 0x31, 0x1d, 0xee, 0x7b, 0xb0, 0xfe, 0x38, 0x0a, - 0xe3, 0xe1, 0x93, 0x9f, 0xac, 0xd3, 0xee, 0x26, 0x6c, 0xd8, 0xdf, 0x4b, 0xbe, 0xdf, 0x6d, 0x40, - 0xfb, 0x51, 0xea, 0x47, 0x99, 0x3f, 0xc4, 0x25, 0x67, 0x3d, 0x58, 0xcc, 0x9f, 0x0e, 0x8e, 0xfc, - 0xec, 0x88, 0x18, 0xb5, 0x3c, 0x55, 0x64, 0x9b, 0xb0, 0xe0, 0x4f, 0xe2, 0x69, 0x94, 0xd3, 0xac, - 0xce, 0x79, 0xb2, 0xc4, 0xde, 0x84, 0xb5, 0x68, 0x3a, 0x19, 0x0c, 0xe3, 0xe8, 0x30, 0x48, 0x27, - 0x42, 0x70, 0x68, 0x70, 0xf3, 0x5e, 0xb5, 0x82, 0x5d, 0x02, 0x38, 0xc0, 0x6e, 0x88, 0x26, 0x9a, - 0xd4, 0x84, 0x81, 0x30, 0x17, 0x3a, 0xb2, 0xc4, 0x83, 0xf1, 0x51, 0xde, 0x9b, 0x27, 0x46, 0x16, - 0x86, 0x3c, 0xf2, 0x60, 0xc2, 0x07, 0x59, 0xee, 0x4f, 0x92, 0xde, 0x02, 0xf5, 0xc6, 0x40, 0xa8, - 0x3e, 0xce, 0xfd, 0x70, 0x70, 0xc8, 0x79, 0xd6, 0x5b, 0x94, 0xf5, 0x1a, 0x61, 0x6f, 0x40, 0x77, - 0xc4, 0xb3, 0x7c, 0xe0, 0x8f, 0x46, 0x29, 0xcf, 0x32, 0x9e, 0xf5, 0x96, 0x68, 0xe9, 0x4a, 0xa8, - 0xdb, 0x83, 0xcd, 0xfb, 0x3c, 0x37, 0x66, 0x27, 0x93, 0xd3, 0xee, 0x3e, 0x00, 0x66, 0xc0, 0x77, - 0x78, 0xee, 0x07, 0x61, 0xc6, 0xde, 0x86, 0x4e, 0x6e, 0x10, 0x93, 0xa8, 0xb6, 0x77, 0xd8, 0x35, - 0xd2, 0xb1, 0x6b, 0xc6, 0x07, 0x9e, 0x45, 0xe7, 0xfe, 0xb7, 0x03, 0xed, 0x7d, 0x1e, 0x69, 0xed, - 0x62, 0xd0, 0xc4, 0x9e, 0xc8, 0x95, 0xa4, 0xdf, 0xec, 0x55, 0x68, 0x53, 0xef, 0xb2, 0x3c, 0x0d, - 0xa2, 0x31, 0x2d, 0x41, 0xcb, 0x03, 0x84, 0xf6, 0x09, 0x61, 0xab, 0x30, 0xe7, 0x4f, 0x72, 0x9a, - 0xf8, 0x39, 0x0f, 0x7f, 0xa2, 0xde, 0x25, 0xfe, 0x6c, 0xc2, 0xa3, 0xbc, 0x98, 0xec, 0x8e, 0xd7, - 0x96, 0xd8, 0x2e, 0xce, 0xf6, 0x35, 0x58, 0x37, 0x49, 0x14, 0xf7, 0x79, 0xe2, 0xbe, 0x66, 0x50, - 0xca, 0x46, 0xae, 0xc0, 0x8a, 0xa2, 0x4f, 0x45, 0x67, 0x69, 0xfa, 0x5b, 0x5e, 0x57, 0xc2, 0x6a, - 0x08, 0x57, 0x61, 0xf5, 0x30, 0x88, 0xfc, 0x70, 0x30, 0x0c, 0xf3, 0xe3, 0xc1, 0x88, 0x87, 0xb9, - 0x4f, 0x0b, 0x31, 0xef, 0x75, 0x09, 0xbf, 0x1d, 0xe6, 0xc7, 0x77, 0x10, 0x75, 0xff, 0xd8, 0x81, - 0x8e, 0x18, 0xbc, 0x54, 0xfc, 0xd7, 0x61, 0x59, 0xb5, 0xc1, 0xd3, 0x34, 0x4e, 0xa5, 0x1c, 0xda, - 0x20, 0xdb, 0x82, 0x55, 0x05, 0x24, 0x29, 0x0f, 0x26, 0xfe, 0x98, 0x4b, 0x6d, 0xaf, 0xe0, 0x6c, - 0xa7, 0xe0, 0x98, 0xc6, 0xd3, 0x5c, 0xa8, 0x5e, 0x7b, 0xa7, 0x23, 0x17, 0xc6, 0x43, 0xcc, 0xb3, - 0x49, 0xdc, 0xef, 0x39, 0xd0, 0xb9, 0x7d, 0xe4, 0x47, 0x11, 0x0f, 0xf7, 0xe2, 0x20, 0xca, 0xd9, - 0x75, 0x60, 0x87, 0xd3, 0x68, 0x14, 0x44, 0xe3, 0x41, 0xfe, 0x34, 0x18, 0x0d, 0x0e, 0x66, 0x39, - 0xcf, 0xc4, 0x12, 0xed, 0x9e, 0xf1, 0x6a, 0xea, 0xd8, 0x9b, 0xb0, 0x6a, 0xa1, 0x59, 0x9e, 0x8a, - 0x75, 0xdb, 0x3d, 0xe3, 0x55, 0x6a, 0x50, 0xf0, 0xe3, 0x69, 0x9e, 0x4c, 0xf3, 0x41, 0x10, 0x8d, - 0xf8, 0x53, 0xea, 0xe3, 0xb2, 0x67, 0x61, 0xb7, 0xba, 0xd0, 0x31, 0xbf, 0x73, 0xdf, 0x83, 0xd5, - 0x07, 0xa8, 0x11, 0x51, 0x10, 0x8d, 0x6f, 0x0a, 0xb1, 0x45, 0x35, 0x4d, 0xa6, 0x07, 0x4f, 0xf8, - 0x4c, 0xce, 0x9b, 0x2c, 0xa1, 0x50, 0x1d, 0xc5, 0x59, 0x2e, 0x25, 0x87, 0x7e, 0xbb, 0xff, 0xe4, - 0xc0, 0x0a, 0xce, 0xfd, 0x07, 0x7e, 0x34, 0x53, 0x2b, 0xf7, 0x00, 0x3a, 0xc8, 0xea, 0x51, 0x7c, - 0x53, 0x28, 0xbb, 0x10, 0xe2, 0xab, 0x72, 0xae, 0x4a, 0xd4, 0xd7, 0x4c, 0x52, 0x34, 0xe6, 0x33, - 0xcf, 0xfa, 0x1a, 0xc5, 0x36, 0xf7, 0xd3, 0x31, 0xcf, 0xc9, 0x0c, 0x48, 0xb3, 0x00, 0x02, 0xba, - 0x1d, 0x47, 0x87, 0xec, 0x32, 0x74, 0x32, 0x3f, 0x1f, 0x24, 0x3c, 0xa5, 0x59, 0x23, 0xd1, 0x9b, - 0xf3, 0x20, 0xf3, 0xf3, 0x3d, 0x9e, 0xde, 0x9a, 0xe5, 0xbc, 0xff, 0x65, 0x58, 0xab, 0xb4, 0x82, - 0xd2, 0x5e, 0x0c, 0x11, 0x7f, 0xb2, 0x0d, 0x98, 0x3f, 0xf6, 0xc3, 0x29, 0x97, 0xd6, 0x49, 0x14, - 0xde, 0x6d, 0xbc, 0xe3, 0xb8, 0x6f, 0xc0, 0x6a, 0xd1, 0x6d, 0x29, 0x64, 0x0c, 0x9a, 0x38, 0x83, - 0x92, 0x01, 0xfd, 0x76, 0x7f, 0xc7, 0x11, 0x84, 0xb7, 0xe3, 0x40, 0x6b, 0x3a, 0x12, 0xa2, 0x41, - 0x50, 0x84, 0xf8, 0xfb, 0x54, 0x4b, 0xf8, 0xd3, 0x0f, 0xd6, 0xbd, 0x02, 0x6b, 0x46, 0x17, 0x9e, - 0xd3, 0xd9, 0xef, 0x38, 0xb0, 0xf6, 0x90, 0x9f, 0xc8, 0x55, 0x57, 0xbd, 0x7d, 0x07, 0x9a, 0xf9, - 0x2c, 0x11, 0x5b, 0x71, 0x77, 0xe7, 0x75, 0xb9, 0x68, 0x15, 0xba, 0x6b, 0xb2, 0xf8, 0x68, 0x96, - 0x70, 0x8f, 0xbe, 0x70, 0xdf, 0x83, 0xb6, 0x01, 0xb2, 0x73, 0xb0, 0xfe, 0xe1, 0xfb, 0x8f, 0x1e, - 0xde, 0xdd, 0xdf, 0x1f, 0xec, 0x3d, 0xbe, 0xf5, 0xd5, 0xbb, 0xbf, 0x36, 0xd8, 0xbd, 0xb9, 0xbf, - 0xbb, 0x7a, 0x86, 0x6d, 0x02, 0x7b, 0x78, 0x77, 0xff, 0xd1, 0xdd, 0x3b, 0x16, 0xee, 0xb8, 0x7d, - 0xe8, 0x3d, 0xe4, 0x27, 0x1f, 0x06, 0x79, 0xc4, 0xb3, 0xcc, 0x6e, 0xcd, 0xbd, 0x06, 0xcc, 0xec, - 0x82, 0x1c, 0x55, 0x0f, 0x16, 0xa5, 0xa9, 0x55, 0x3b, 0x8d, 0x2c, 0xba, 0x6f, 0x00, 0xdb, 0x0f, - 0xc6, 0xd1, 0x07, 0x3c, 0xcb, 0xfc, 0x31, 0x57, 0x63, 0x5b, 0x85, 0xb9, 0x49, 0x36, 0x96, 0x46, - 0x11, 0x7f, 0xba, 0x9f, 0x87, 0x75, 0x8b, 0x4e, 0x32, 0xbe, 0x08, 0xad, 0x2c, 0x18, 0x47, 0x7e, - 0x3e, 0x4d, 0xb9, 0x64, 0x5d, 0x00, 0xee, 0x3d, 0xd8, 0xf8, 0x06, 0x4f, 0x83, 0xc3, 0xd9, 0x8b, - 0xd8, 0xdb, 0x7c, 0x1a, 0x65, 0x3e, 0x77, 0xe1, 0x6c, 0x89, 0x8f, 0x6c, 0x5e, 0x08, 0xa2, 0x5c, - 0xae, 0x25, 0x4f, 0x14, 0x0c, 0xb5, 0x6c, 0x98, 0x6a, 0xe9, 0x3e, 0x06, 0x76, 0x3b, 0x8e, 0x22, - 0x3e, 0xcc, 0xf7, 0x38, 0x4f, 0x0b, 0xff, 0xaa, 0x90, 0xba, 0xf6, 0xce, 0x39, 0xb9, 0x8e, 0x65, - 0x5d, 0x97, 0xe2, 0xc8, 0xa0, 0x99, 0xf0, 0x74, 0x42, 0x8c, 0x97, 0x3c, 0xfa, 0xed, 0x9e, 0x85, - 0x75, 0x8b, 0xad, 0xdc, 0xed, 0xdf, 0x82, 0xb3, 0x77, 0x82, 0x6c, 0x58, 0x6d, 0xb0, 0x07, 0x8b, - 0xc9, 0xf4, 0x60, 0x50, 0xe8, 0x94, 0x2a, 0xe2, 0x26, 0x58, 0xfe, 0x44, 0x32, 0xfb, 0x7d, 0x07, - 0x9a, 0xbb, 0x8f, 0x1e, 0xdc, 0x66, 0x7d, 0x58, 0x0a, 0xa2, 0x61, 0x3c, 0xc1, 0xad, 0x43, 0x0c, - 0x5a, 0x97, 0x4f, 0xd5, 0x95, 0x8b, 0xd0, 0xa2, 0x1d, 0x07, 0xf7, 0x75, 0xe9, 0x0a, 0x15, 0x00, - 0xfa, 0x14, 0xfc, 0x69, 0x12, 0xa4, 0xe4, 0x34, 0x28, 0x57, 0xa0, 0x49, 0x16, 0xb1, 0x5a, 0xe1, - 0xfe, 0x4f, 0x13, 0x16, 0xa5, 0xad, 0xa6, 0xf6, 0x86, 0x79, 0x70, 0xcc, 0x65, 0x4f, 0x64, 0x09, - 0x77, 0x95, 0x94, 0x4f, 0xe2, 0x9c, 0x0f, 0xac, 0x65, 0xb0, 0x41, 0xa4, 0x1a, 0x0a, 0x46, 0x83, - 0x04, 0xad, 0x3e, 0xf5, 0xac, 0xe5, 0xd9, 0x20, 0x4e, 0x16, 0x02, 0x83, 0x60, 0x44, 0x7d, 0x6a, - 0x7a, 0xaa, 0x88, 0x33, 0x31, 0xf4, 0x13, 0x7f, 0x18, 0xe4, 0x33, 0xa9, 0xdc, 0xba, 0x8c, 0xbc, - 0xc3, 0x78, 0xe8, 0x87, 0x83, 0x03, 0x3f, 0xf4, 0xa3, 0x21, 0x97, 0x8e, 0x8b, 0x0d, 0xa2, 0x6f, - 0x22, 0xbb, 0xa4, 0xc8, 0x84, 0xff, 0x52, 0x42, 0xd1, 0xc7, 0x19, 0xc6, 0x93, 0x49, 0x90, 0xa3, - 0x4b, 0xd3, 0x5b, 0x12, 0x86, 0xa4, 0x40, 0x68, 0x24, 0xa2, 0x74, 0x22, 0x66, 0xaf, 0x25, 0x5a, - 0xb3, 0x40, 0xe4, 0x72, 0xc8, 0x39, 0x19, 0xa4, 0x27, 0x27, 0x3d, 0x10, 0x5c, 0x0a, 0x04, 0xd7, - 0x61, 0x1a, 0x65, 0x3c, 0xcf, 0x43, 0x3e, 0xd2, 0x1d, 0x6a, 0x13, 0x59, 0xb5, 0x82, 0x5d, 0x87, - 0x75, 0xe1, 0x65, 0x65, 0x7e, 0x1e, 0x67, 0x47, 0x41, 0x36, 0xc8, 0x78, 0x94, 0xf7, 0x3a, 0x44, - 0x5f, 0x57, 0xc5, 0xde, 0x81, 0x73, 0x25, 0x38, 0xe5, 0x43, 0x1e, 0x1c, 0xf3, 0x51, 0x6f, 0x99, - 0xbe, 0x3a, 0xad, 0x9a, 0x5d, 0x86, 0x36, 0x3a, 0x97, 0xd3, 0x64, 0xe4, 0xe3, 0x3e, 0xdc, 0xa5, - 0x75, 0x30, 0x21, 0xf6, 0x16, 0x2c, 0x27, 0x5c, 0x6c, 0x96, 0x47, 0x79, 0x38, 0xcc, 0x7a, 0x2b, - 0xb4, 0x93, 0xb5, 0xa5, 0x32, 0xa1, 0xe4, 0x7a, 0x36, 0x05, 0x0a, 0xe5, 0x30, 0x23, 0x77, 0xc5, - 0x9f, 0xf5, 0x56, 0x49, 0xdc, 0x0a, 0x80, 0x74, 0x24, 0x0d, 0x8e, 0xfd, 0x9c, 0xf7, 0xd6, 0x48, - 0xb6, 0x54, 0xd1, 0xfd, 0x73, 0x07, 0xd6, 0x1f, 0x04, 0x59, 0x2e, 0x85, 0x50, 0x9b, 0xe3, 0x57, - 0xa1, 0x2d, 0xc4, 0x6f, 0x10, 0x47, 0xe1, 0x4c, 0x4a, 0x24, 0x08, 0xe8, 0x6b, 0x51, 0x38, 0x63, - 0x9f, 0x83, 0xe5, 0x20, 0x32, 0x49, 0x84, 0x0e, 0x77, 0x14, 0x48, 0x44, 0xaf, 0x42, 0x3b, 0x99, - 0x1e, 0x84, 0xc1, 0x50, 0x90, 0xcc, 0x09, 0x2e, 0x02, 0x22, 0x02, 0x74, 0xf4, 0x44, 0x4f, 0x04, - 0x45, 0x93, 0x28, 0xda, 0x12, 0x43, 0x12, 0xf7, 0x16, 0x6c, 0xd8, 0x1d, 0x94, 0xc6, 0x6a, 0x0b, - 0x96, 0xa4, 0x6c, 0x67, 0xbd, 0x36, 0xcd, 0x4f, 0x57, 0xce, 0x8f, 0x24, 0xf5, 0x74, 0xbd, 0xfb, - 0x6f, 0x0e, 0x34, 0xd1, 0x00, 0x9c, 0x6e, 0x2c, 0x4c, 0x9b, 0x3e, 0x67, 0xd9, 0x74, 0xf2, 0xfb, - 0xd1, 0x2b, 0x12, 0x22, 0x21, 0xd4, 0xc6, 0x40, 0x8a, 0xfa, 0x94, 0x0f, 0x8f, 0x49, 0x77, 0x74, - 0x3d, 0x22, 0xa8, 0x59, 0xb8, 0x75, 0xd2, 0xd7, 0x42, 0x71, 0x74, 0x59, 0xd5, 0xd1, 0x97, 0x8b, - 0x45, 0x1d, 0x7d, 0xd7, 0x83, 0xc5, 0x20, 0x3a, 0x88, 0xa7, 0xd1, 0x88, 0x94, 0x64, 0xc9, 0x53, - 0x45, 0x5c, 0xec, 0x84, 0x3c, 0xa9, 0x60, 0xc2, 0xa5, 0x76, 0x14, 0x80, 0xcb, 0xd0, 0xb5, 0xca, - 0xc8, 0xe0, 0xe9, 0x7d, 0xec, 0x6d, 0x58, 0x33, 0x30, 0x39, 0x83, 0xaf, 0xc1, 0x7c, 0x82, 0x80, - 0x74, 0x94, 0x94, 0x78, 0x91, 0xa5, 0x14, 0x35, 0xee, 0x2a, 0xc6, 0xcf, 0xf9, 0xfb, 0xd1, 0x61, - 0xac, 0x38, 0xfd, 0x68, 0x0e, 0x03, 0x5e, 0x09, 0x49, 0x46, 0x57, 0x61, 0x25, 0x18, 0xf1, 0x28, - 0x0f, 0xf2, 0xd9, 0xc0, 0xf2, 0xe0, 0xca, 0x30, 0xee, 0x30, 0x7e, 0x18, 0xf8, 0x99, 0xb4, 0x61, - 0xa2, 0xc0, 0x76, 0x60, 0x03, 0xc5, 0x5f, 0x49, 0xb4, 0x5e, 0x56, 0xe1, 0x48, 0xd6, 0xd6, 0xa1, - 0xc6, 0x22, 0x2e, 0x25, 0x50, 0x7f, 0x22, 0x2c, 0x6d, 0x5d, 0x15, 0xce, 0x9a, 0xe0, 0x84, 0x43, - 0x9e, 0x17, 0x2a, 0xa2, 0x81, 0x4a, 0xf4, 0xb6, 0x20, 0x9c, 0xd8, 0x72, 0xf4, 0x66, 0x44, 0x80, - 0x4b, 0x95, 0x08, 0xf0, 0x2a, 0xac, 0x64, 0xb3, 0x68, 0xc8, 0x47, 0x83, 0x3c, 0xc6, 0x76, 0x83, - 0x88, 0x56, 0x67, 0xc9, 0x2b, 0xc3, 0x14, 0xab, 0xf2, 0x2c, 0x8f, 0x78, 0x4e, 0xa6, 0x6b, 0xc9, - 0x53, 0x45, 0xdc, 0x05, 0x88, 0x44, 0x08, 0x75, 0xcb, 0x93, 0x25, 0xdc, 0x2a, 0xa7, 0x69, 0x90, - 0xf5, 0x3a, 0x84, 0xd2, 0x6f, 0xf6, 0x05, 0x38, 0x7b, 0x80, 0x91, 0xd5, 0x11, 0xf7, 0x47, 0x3c, - 0xa5, 0xd5, 0x17, 0x81, 0xa5, 0xb0, 0x40, 0xf5, 0x95, 0xd8, 0xf6, 0x31, 0x4f, 0xb3, 0x20, 0x8e, - 0xc8, 0xf6, 0xb4, 0x3c, 0x55, 0x74, 0x3f, 0xa1, 0x1d, 0x5d, 0x87, 0xbc, 0x8f, 0xc9, 0x1c, 0xb1, - 0x0b, 0xd0, 0x12, 0x63, 0xcc, 0x8e, 0x7c, 0xe9, 0x64, 0x2c, 0x11, 0xb0, 0x7f, 0xe4, 0xa3, 0x02, - 0x5b, 0xd3, 0xd6, 0x20, 0xcf, 0xb1, 0x4d, 0xd8, 0xae, 0x98, 0xb5, 0xd7, 0xa1, 0xab, 0x82, 0xe9, - 0x6c, 0x10, 0xf2, 0xc3, 0x5c, 0x05, 0x08, 0xd1, 0x74, 0x82, 0xcd, 0x65, 0x0f, 0xf8, 0x61, 0xee, - 0x3e, 0x84, 0x35, 0xa9, 0xb7, 0x5f, 0x4b, 0xb8, 0x6a, 0xfa, 0x4b, 0xe5, 0x4d, 0x4d, 0x78, 0x15, - 0xeb, 0xb6, 0xa2, 0x53, 0x94, 0x53, 0xda, 0xe9, 0x5c, 0x0f, 0x98, 0xac, 0xbe, 0x1d, 0xc6, 0x19, - 0x97, 0x0c, 0x5d, 0xe8, 0x0c, 0xc3, 0x38, 0x53, 0x61, 0x88, 0x1c, 0x8e, 0x85, 0xe1, 0xfc, 0x64, - 0xd3, 0xe1, 0x10, 0x2d, 0x81, 0xb0, 0x69, 0xaa, 0xe8, 0xfe, 0x85, 0x03, 0xeb, 0xc4, 0x4d, 0x59, - 0x18, 0xed, 0xbb, 0xbe, 0x7c, 0x37, 0x3b, 0x43, 0x33, 0x34, 0xdb, 0x80, 0xf9, 0xc3, 0x38, 0x1d, - 0x72, 0xd9, 0x92, 0x28, 0xfc, 0xf8, 0xde, 0x78, 0xb3, 0xe2, 0x8d, 0xff, 0xc8, 0x81, 0x35, 0xea, - 0xea, 0x7e, 0xee, 0xe7, 0xd3, 0x4c, 0x0e, 0xff, 0x97, 0x60, 0x19, 0x87, 0xca, 0x95, 0x3a, 0xc9, - 0x8e, 0x6e, 0x68, 0xcd, 0x27, 0x54, 0x10, 0xef, 0x9e, 0xf1, 0x6c, 0x62, 0xf6, 0x65, 0xe8, 0x98, - 0x19, 0x11, 0xea, 0x73, 0x7b, 0xe7, 0xbc, 0x1a, 0x65, 0x45, 0x72, 0x76, 0xcf, 0x78, 0xd6, 0x07, - 0xec, 0x06, 0x00, 0xb9, 0x1b, 0xc4, 0x56, 0x86, 0xb2, 0xe7, 0xed, 0x49, 0x32, 0x16, 0x6b, 0xf7, - 0x8c, 0x67, 0x90, 0xdf, 0x5a, 0x82, 0x05, 0xb1, 0x3f, 0xba, 0xf7, 0x61, 0xd9, 0xea, 0xa9, 0x15, - 0x65, 0x74, 0x44, 0x94, 0x51, 0x09, 0x4a, 0x1b, 0xd5, 0xa0, 0xd4, 0xfd, 0x97, 0x06, 0x30, 0x94, - 0xb6, 0xd2, 0x72, 0xe2, 0x06, 0x1d, 0x8f, 0x2c, 0x77, 0xab, 0xe3, 0x99, 0x10, 0xbb, 0x06, 0xcc, - 0x28, 0xaa, 0xdc, 0x83, 0xd8, 0x37, 0x6a, 0x6a, 0xd0, 0xc0, 0x09, 0x5f, 0x49, 0xc5, 0xc0, 0xd2, - 0xb1, 0x14, 0xeb, 0x56, 0x5b, 0x87, 0x5b, 0x43, 0x32, 0xcd, 0x8e, 0xd0, 0x81, 0x50, 0x0e, 0x99, - 0x2a, 0x97, 0x05, 0x64, 0xe1, 0x85, 0x02, 0xb2, 0x58, 0x16, 0x10, 0xd3, 0x25, 0x58, 0xb2, 0x5c, - 0x02, 0xf4, 0xbf, 0x26, 0x41, 0x44, 0x7e, 0xc5, 0x60, 0x82, 0xad, 0x4b, 0xff, 0xcb, 0x02, 0xd9, - 0x16, 0xac, 0x4a, 0xbf, 0xae, 0xf0, 0x3b, 0x80, 0xe6, 0xb8, 0x82, 0xbb, 0x9f, 0x39, 0xb0, 0x8a, - 0xf3, 0x6c, 0xc9, 0xe2, 0xbb, 0x40, 0xaa, 0xf0, 0x92, 0xa2, 0x68, 0xd1, 0xfe, 0xf4, 0x92, 0xf8, - 0x0e, 0xb4, 0x88, 0x61, 0x9c, 0xf0, 0x48, 0x0a, 0x62, 0xcf, 0x16, 0xc4, 0xc2, 0x0a, 0xed, 0x9e, - 0xf1, 0x0a, 0x62, 0x43, 0x0c, 0xff, 0xce, 0x81, 0xb6, 0xec, 0xe6, 0x4f, 0x1c, 0x4b, 0xf4, 0x61, - 0x09, 0x25, 0xd2, 0x70, 0xd8, 0x75, 0x19, 0x77, 0x93, 0x09, 0x06, 0x6c, 0xb8, 0x7d, 0x5a, 0x71, - 0x44, 0x19, 0xc6, 0xbd, 0x90, 0x0c, 0x6e, 0x36, 0xc8, 0x83, 0x70, 0xa0, 0x6a, 0x65, 0x02, 0xb2, - 0xae, 0x0a, 0xed, 0x4e, 0x96, 0xfb, 0x63, 0x2e, 0xb7, 0x39, 0x51, 0xc0, 0x80, 0x49, 0x0e, 0xa8, - 0xe4, 0x0e, 0xba, 0x3f, 0x04, 0x38, 0x57, 0xa9, 0xd2, 0xe9, 0x6e, 0xe9, 0x20, 0x87, 0xc1, 0xe4, - 0x20, 0xd6, 0xbe, 0xb6, 0x63, 0xfa, 0xce, 0x56, 0x15, 0x1b, 0xc3, 0x59, 0xb5, 0x9f, 0xe3, 0x9c, - 0x16, 0xbb, 0x77, 0x83, 0x1c, 0x91, 0xb7, 0x6c, 0x19, 0x28, 0x37, 0xa8, 0x70, 0x53, 0x73, 0xeb, - 0xf9, 0xb1, 0x23, 0xe8, 0x69, 0xc7, 0x41, 0x9a, 0x78, 0xc3, 0xb9, 0xc0, 0xb6, 0xde, 0x7c, 0x41, - 0x5b, 0x64, 0x8f, 0x46, 0xaa, 0x99, 0x53, 0xb9, 0xb1, 0x19, 0x5c, 0x52, 0x75, 0x64, 0xc3, 0xab, - 0xed, 0x35, 0x5f, 0x6a, 0x6c, 0xf7, 0xf0, 0x63, 0xbb, 0xd1, 0x17, 0x30, 0xee, 0xff, 0xd0, 0x81, - 0xae, 0xcd, 0x0e, 0x45, 0x47, 0x2a, 0xa1, 0x32, 0x46, 0xca, 0x21, 0x2b, 0xc1, 0xd5, 0xb0, 0xb1, - 0x51, 0x17, 0x36, 0x9a, 0xc1, 0xe1, 0xdc, 0x8b, 0x82, 0xc3, 0xe6, 0xcb, 0x05, 0x87, 0xf3, 0x75, - 0xc1, 0x61, 0xff, 0xbf, 0x1c, 0x60, 0xd5, 0xf5, 0x65, 0xf7, 0x45, 0xdc, 0x1a, 0xf1, 0x50, 0xda, - 0x89, 0x5f, 0x78, 0x39, 0x19, 0x51, 0x73, 0xa8, 0xbe, 0x46, 0x61, 0x35, 0x0d, 0x81, 0xe9, 0xb6, - 0x2c, 0x7b, 0x75, 0x55, 0xa5, 0x70, 0xb5, 0xf9, 0xe2, 0x70, 0x75, 0xfe, 0xc5, 0xe1, 0xea, 0x42, - 0x39, 0x5c, 0xed, 0xff, 0x16, 0x2c, 0x5b, 0xab, 0xfe, 0x7f, 0x37, 0xe2, 0xb2, 0xcb, 0x23, 0x16, - 0xd8, 0xc2, 0xfa, 0xff, 0xde, 0x00, 0x56, 0x95, 0xbc, 0x9f, 0x69, 0x1f, 0x48, 0x8e, 0x2c, 0x03, - 0x32, 0x27, 0xe5, 0xc8, 0x32, 0x1d, 0xff, 0x9f, 0x46, 0xf1, 0x4d, 0x58, 0x4b, 0xf9, 0x30, 0x3e, - 0xa6, 0x43, 0x38, 0x3b, 0xd5, 0x51, 0xad, 0x40, 0xa7, 0xcf, 0x0e, 0xd2, 0x97, 0xac, 0x33, 0x13, - 0x63, 0x67, 0x28, 0xc5, 0xea, 0xee, 0x26, 0x6c, 0x88, 0xa3, 0xac, 0x5b, 0x82, 0x95, 0x32, 0xb2, - 0x7f, 0xe6, 0xc0, 0xd9, 0x52, 0x45, 0x71, 0xb0, 0x20, 0xec, 0xa8, 0x6d, 0x5c, 0x6d, 0x10, 0xfb, - 0x2f, 0x05, 0xd8, 0xe8, 0xbf, 0xd8, 0x6f, 0xaa, 0x15, 0x38, 0x3f, 0xd3, 0xa8, 0x4a, 0x2f, 0x66, - 0xbd, 0xae, 0xca, 0x3d, 0x07, 0x67, 0xe5, 0xca, 0x96, 0x3a, 0x7e, 0x08, 0x9b, 0xe5, 0x8a, 0x22, - 0x53, 0x6a, 0x77, 0x59, 0x15, 0xd1, 0x25, 0xb2, 0x6c, 0xb6, 0xdd, 0xdf, 0xda, 0x3a, 0xf7, 0x37, - 0x81, 0x7d, 0x7d, 0xca, 0xd3, 0x19, 0x1d, 0x7b, 0xe8, 0x54, 0xc5, 0xb9, 0x72, 0x4c, 0xbf, 0x90, - 0x4c, 0x0f, 0xbe, 0xca, 0x67, 0xea, 0x5c, 0xa9, 0x51, 0x9c, 0x2b, 0xbd, 0x02, 0x80, 0xa1, 0x08, - 0x9d, 0x93, 0xa8, 0x93, 0x3e, 0x8c, 0x01, 0x05, 0x43, 0xf7, 0x06, 0xac, 0x5b, 0xfc, 0xf5, 0xec, - 0x2f, 0xc8, 0x2f, 0x44, 0xa0, 0x6c, 0x9f, 0xbe, 0xc8, 0x3a, 0xf7, 0x3f, 0x1c, 0x98, 0xdb, 0x8d, - 0x13, 0x33, 0xc5, 0xe6, 0xd8, 0x29, 0x36, 0x69, 0x6b, 0x07, 0xda, 0x94, 0x36, 0xa4, 0xa5, 0x30, - 0x41, 0xb6, 0x05, 0x5d, 0x7f, 0x92, 0x63, 0xa8, 0x78, 0x18, 0xa7, 0x27, 0x7e, 0x3a, 0x12, 0x4b, - 0x72, 0xab, 0xd1, 0x73, 0xbc, 0x52, 0x0d, 0xdb, 0x80, 0x39, 0x6d, 0x94, 0x88, 0x00, 0x8b, 0xe8, - 0x6c, 0x50, 0xa6, 0x71, 0x26, 0xa3, 0x5c, 0x59, 0xc2, 0x15, 0xb7, 0xbf, 0x17, 0xee, 0x9d, 0x90, - 0xf0, 0xba, 0x2a, 0xb4, 0xfb, 0x68, 0xa3, 0x88, 0x4c, 0xa6, 0x27, 0x54, 0xd9, 0xfd, 0x57, 0x07, - 0xe6, 0x69, 0x06, 0x50, 0x27, 0x85, 0x20, 0xd2, 0x41, 0x26, 0xa5, 0x45, 0x1d, 0xa1, 0x93, 0x25, - 0x98, 0xb9, 0xd6, 0xf1, 0x66, 0x43, 0x77, 0xdb, 0x3c, 0xe2, 0xbc, 0x0c, 0x2d, 0x51, 0xd2, 0x67, - 0x82, 0x44, 0x52, 0x80, 0xec, 0x12, 0x34, 0x8f, 0xe2, 0x44, 0xed, 0xa8, 0xa0, 0xb2, 0x62, 0x71, - 0xe2, 0x11, 0x5e, 0xf4, 0x07, 0xf9, 0x89, 0xce, 0x0b, 0x9b, 0x5c, 0x86, 0x71, 0x57, 0xd2, 0x6c, - 0xcd, 0xc9, 0x28, 0xa1, 0xee, 0x16, 0xac, 0x3c, 0x8c, 0x47, 0xdc, 0xc8, 0x83, 0x9c, 0x2a, 0x75, - 0xee, 0x6f, 0x3b, 0xb0, 0xa4, 0x88, 0xd9, 0x55, 0x68, 0xe2, 0x56, 0x5b, 0x72, 0x6e, 0x75, 0x36, - 0x1c, 0xe9, 0x3c, 0xa2, 0x40, 0x13, 0x49, 0x51, 0x72, 0xe1, 0x0a, 0xa9, 0x18, 0xb9, 0x70, 0x32, - 0x74, 0x77, 0x4b, 0x9b, 0x71, 0x09, 0x75, 0xff, 0xd2, 0x81, 0x65, 0xab, 0x0d, 0x0c, 0x69, 0x42, - 0x3f, 0xcb, 0x65, 0x86, 0x51, 0x2e, 0x8f, 0x09, 0x99, 0x99, 0xb1, 0x86, 0x9d, 0x19, 0xd3, 0x39, - 0x9b, 0x39, 0x33, 0x67, 0x73, 0x1d, 0x5a, 0xc5, 0x21, 0x74, 0xd3, 0x32, 0x7d, 0xd8, 0xa2, 0xca, - 0xf3, 0x17, 0x44, 0xc8, 0x67, 0x18, 0x87, 0x71, 0x2a, 0xcf, 0x68, 0x45, 0xc1, 0xbd, 0x01, 0x6d, - 0x83, 0x1e, 0xbb, 0x11, 0xf1, 0xfc, 0x24, 0x4e, 0x9f, 0xa8, 0x04, 0x9d, 0x2c, 0xea, 0xe3, 0xac, - 0x46, 0x71, 0x9c, 0xe5, 0xfe, 0x95, 0x03, 0xcb, 0x28, 0x83, 0x41, 0x34, 0xde, 0x8b, 0xc3, 0x60, - 0x38, 0xa3, 0xb5, 0x57, 0xe2, 0x26, 0x0f, 0x6f, 0x95, 0x2c, 0xda, 0x30, 0xca, 0xb6, 0x8a, 0x68, - 0xa4, 0x22, 0xea, 0x32, 0x6a, 0x2a, 0xca, 0xf9, 0x81, 0x9f, 0x49, 0xe1, 0x97, 0x7b, 0x91, 0x05, - 0xa2, 0x3e, 0x21, 0x90, 0xfa, 0x39, 0x1f, 0x4c, 0x82, 0x30, 0x0c, 0x04, 0xad, 0x70, 0x11, 0xea, - 0xaa, 0xdc, 0x1f, 0x34, 0xa0, 0x2d, 0x2d, 0xe5, 0xdd, 0xd1, 0x58, 0xa4, 0xc2, 0xa5, 0xa3, 0xa5, - 0xcd, 0x85, 0x81, 0xa8, 0x7a, 0xcb, 0x35, 0x33, 0x90, 0xf2, 0xb2, 0xce, 0x55, 0x97, 0xf5, 0x22, - 0xb4, 0x50, 0xbc, 0xde, 0x22, 0x1f, 0x50, 0xdc, 0x59, 0x28, 0x00, 0x55, 0xbb, 0x43, 0xb5, 0xf3, - 0x45, 0x2d, 0x01, 0x96, 0xd7, 0xb7, 0x50, 0xf2, 0xfa, 0xde, 0x81, 0x8e, 0x64, 0x43, 0xf3, 0x4e, - 0xd6, 0xa1, 0x10, 0x70, 0x6b, 0x4d, 0x3c, 0x8b, 0x52, 0x7d, 0xb9, 0xa3, 0xbe, 0x5c, 0x7a, 0xd1, - 0x97, 0x8a, 0x92, 0x4e, 0x86, 0xc4, 0xdc, 0xdc, 0x4f, 0xfd, 0xe4, 0x48, 0xed, 0x3e, 0x23, 0x7d, - 0xdc, 0x4d, 0x30, 0xdb, 0x82, 0x79, 0xfc, 0x4c, 0x59, 0xeb, 0x7a, 0xa5, 0x13, 0x24, 0xec, 0x2a, - 0xcc, 0xf3, 0xd1, 0x98, 0xab, 0xc8, 0x83, 0xd9, 0x31, 0x20, 0xae, 0x91, 0x27, 0x08, 0xd0, 0x04, - 0x20, 0x5a, 0x32, 0x01, 0xb6, 0xa5, 0x5f, 0xc0, 0xe2, 0xfb, 0x23, 0x77, 0x03, 0xd8, 0x43, 0x21, - 0xb5, 0x66, 0xe6, 0xf4, 0xf7, 0xe6, 0xa0, 0x6d, 0xc0, 0xa8, 0xcd, 0x63, 0xec, 0xf0, 0x60, 0x14, - 0xf8, 0x13, 0x9e, 0xf3, 0x54, 0x4a, 0x6a, 0x09, 0x45, 0x3a, 0xff, 0x78, 0x3c, 0x88, 0xa7, 0xf9, - 0x60, 0xc4, 0xc7, 0x29, 0x17, 0x7b, 0x24, 0x6e, 0x06, 0x16, 0x8a, 0x74, 0x13, 0xff, 0xa9, 0x49, - 0x27, 0xe4, 0xa1, 0x84, 0xaa, 0x3c, 0xa8, 0x98, 0xa3, 0x66, 0x91, 0x07, 0x15, 0x33, 0x52, 0xb6, - 0x43, 0xf3, 0x35, 0x76, 0xe8, 0x6d, 0xd8, 0x14, 0x16, 0x47, 0xea, 0xe6, 0xa0, 0x24, 0x26, 0xa7, - 0xd4, 0xb2, 0x2d, 0x58, 0xc5, 0x3e, 0x2b, 0x01, 0xcf, 0x82, 0x4f, 0x44, 0x66, 0xc2, 0xf1, 0x2a, - 0x38, 0xd2, 0xa2, 0x3a, 0x5a, 0xb4, 0xe2, 0xac, 0xa8, 0x82, 0x13, 0xad, 0xff, 0xd4, 0xa6, 0x6d, - 0x49, 0xda, 0x12, 0xee, 0x2e, 0x43, 0x7b, 0x3f, 0x8f, 0x13, 0xb5, 0x28, 0x5d, 0xe8, 0x88, 0xa2, - 0x3c, 0x19, 0xbc, 0x00, 0xe7, 0x49, 0x8a, 0x1e, 0xc5, 0x49, 0x1c, 0xc6, 0xe3, 0xd9, 0xfe, 0xf4, - 0x20, 0x1b, 0xa6, 0x41, 0x82, 0x11, 0x81, 0xfb, 0xb7, 0x0e, 0xac, 0x5b, 0xb5, 0x32, 0x95, 0xf1, - 0x05, 0x21, 0xd2, 0xfa, 0x48, 0x47, 0x08, 0xde, 0x9a, 0x61, 0x0e, 0x05, 0xa1, 0x48, 0x22, 0x3d, - 0x96, 0xa7, 0x3c, 0x37, 0x61, 0x45, 0xf5, 0x4c, 0x7d, 0x28, 0xa4, 0xb0, 0x57, 0x95, 0x42, 0xf9, - 0x7d, 0x57, 0x7e, 0xa0, 0x58, 0xfc, 0xb2, 0xf0, 0xab, 0xf9, 0x88, 0xc6, 0xa8, 0x62, 0xda, 0xbe, - 0xfa, 0xde, 0x74, 0xe6, 0x55, 0x0f, 0x86, 0x1a, 0xcc, 0xdc, 0x3f, 0x70, 0x00, 0x8a, 0xde, 0xa1, - 0x60, 0x14, 0x26, 0x5d, 0x5c, 0x56, 0x33, 0xcc, 0xf7, 0x6b, 0xd0, 0xd1, 0xd9, 0xfc, 0x62, 0x97, - 0x68, 0x2b, 0x0c, 0x1d, 0xae, 0x2b, 0xb0, 0x32, 0x0e, 0xe3, 0x03, 0xda, 0x62, 0xe9, 0xa8, 0x39, - 0x93, 0xe7, 0xa3, 0x5d, 0x01, 0xdf, 0x93, 0x68, 0xb1, 0xa5, 0x34, 0x8d, 0x2d, 0xc5, 0xfd, 0x4e, - 0x43, 0xe7, 0x80, 0x8b, 0x31, 0x9f, 0xaa, 0x65, 0x6c, 0xa7, 0x62, 0x1c, 0x4f, 0x49, 0xb9, 0x52, - 0xf6, 0x66, 0xef, 0x85, 0x81, 0xec, 0x0d, 0xe8, 0xa6, 0xc2, 0xfa, 0x28, 0xd3, 0xd4, 0x7c, 0x8e, - 0x69, 0x5a, 0x4e, 0xad, 0x7d, 0xe7, 0xe7, 0x60, 0xd5, 0x1f, 0x1d, 0xf3, 0x34, 0x0f, 0x28, 0xa2, - 0xa1, 0x4d, 0x5f, 0x18, 0xd4, 0x15, 0x03, 0xa7, 0xbd, 0xf8, 0x0a, 0xac, 0xc8, 0x33, 0x69, 0x4d, - 0x29, 0x6f, 0x22, 0x15, 0x30, 0x12, 0xba, 0xdf, 0x57, 0xe9, 0x66, 0x7b, 0x0d, 0x4f, 0x9f, 0x11, - 0x73, 0x74, 0x8d, 0xd2, 0xe8, 0x3e, 0x27, 0x53, 0xbf, 0x23, 0x15, 0x36, 0xc9, 0x24, 0xbc, 0x00, - 0x65, 0xaa, 0xde, 0x9e, 0xd2, 0xe6, 0xcb, 0x4c, 0xa9, 0xfb, 0x99, 0x03, 0x8b, 0xbb, 0x71, 0xb2, - 0x2b, 0x8f, 0x97, 0x49, 0x11, 0xf4, 0x8d, 0x0f, 0x55, 0x34, 0xbd, 0xe2, 0x46, 0xc5, 0x2b, 0xae, - 0xee, 0xb5, 0xcb, 0xe5, 0xbd, 0xf6, 0x57, 0xe0, 0x02, 0x45, 0xcb, 0x69, 0x9c, 0xc4, 0x29, 0x2a, - 0xa3, 0x1f, 0x8a, 0x8d, 0x35, 0x8e, 0xf2, 0x23, 0x65, 0xc6, 0x9e, 0x47, 0x42, 0xd1, 0x51, 0x98, - 0x1f, 0x0f, 0x84, 0x33, 0x2c, 0x7d, 0x03, 0x61, 0xdd, 0xaa, 0x15, 0xee, 0x97, 0xa0, 0x45, 0xce, - 0x2d, 0x0d, 0xeb, 0x4d, 0x68, 0x1d, 0xc5, 0xc9, 0xe0, 0x28, 0x88, 0x72, 0xa5, 0xdc, 0xdd, 0xc2, - 0xeb, 0xdc, 0xa5, 0x09, 0xd1, 0x04, 0xee, 0xdf, 0xcf, 0xc1, 0xe2, 0xfb, 0xd1, 0x71, 0x1c, 0x0c, - 0x29, 0x33, 0x3d, 0xe1, 0x93, 0x58, 0xdd, 0x7f, 0xc1, 0xdf, 0x38, 0x15, 0x74, 0x16, 0x9c, 0xe4, - 0x32, 0xb5, 0xac, 0x8a, 0xb8, 0xdd, 0xa7, 0xc5, 0x9d, 0x30, 0xa1, 0x3a, 0x06, 0x82, 0x8e, 0x7d, - 0x6a, 0x5e, 0x88, 0x93, 0xa5, 0xe2, 0x02, 0xd1, 0xbc, 0x71, 0x81, 0x88, 0xce, 0x31, 0xc4, 0x31, - 0x37, 0xc9, 0xd7, 0x92, 0xa7, 0x8a, 0x14, 0x88, 0xa4, 0x5c, 0x64, 0x39, 0xc8, 0x71, 0x58, 0x94, - 0x81, 0x88, 0x09, 0xa2, 0x73, 0x21, 0x3e, 0x10, 0x34, 0xc2, 0xf8, 0x9a, 0x10, 0x3a, 0x5b, 0xe5, - 0x3b, 0x75, 0x2d, 0x21, 0xf3, 0x25, 0x18, 0x2d, 0xf4, 0x88, 0x6b, 0x43, 0x2a, 0xc6, 0x00, 0xe2, - 0xce, 0x5b, 0x19, 0x37, 0xc2, 0x17, 0x71, 0x5c, 0xaf, 0xc2, 0x17, 0x14, 0x14, 0x3f, 0x0c, 0x0f, - 0xfc, 0xe1, 0x13, 0xba, 0xe9, 0x48, 0xa7, 0xf3, 0x2d, 0xcf, 0x06, 0xb1, 0xd7, 0xc6, 0x6a, 0xd2, - 0x49, 0x58, 0xd3, 0x33, 0x21, 0xb6, 0x03, 0x6d, 0x0a, 0xd9, 0xe4, 0x7a, 0x76, 0x69, 0x3d, 0x57, - 0xcd, 0x98, 0x8e, 0x56, 0xd4, 0x24, 0x72, 0xbf, 0x01, 0xec, 0xe6, 0x68, 0x24, 0x57, 0x55, 0x07, - 0x86, 0xc5, 0x7a, 0x38, 0xd6, 0x7a, 0xd4, 0xcc, 0x4b, 0xa3, 0x76, 0x5e, 0xdc, 0xbb, 0xd0, 0xde, - 0x33, 0x2e, 0x35, 0x92, 0x00, 0xa8, 0xeb, 0x8c, 0x52, 0x68, 0x0c, 0xc4, 0x68, 0xb0, 0x61, 0x36, - 0xe8, 0xfe, 0x22, 0xb0, 0x07, 0x41, 0x96, 0xeb, 0xfe, 0x89, 0x49, 0x7f, 0x0d, 0x3a, 0x3a, 0x8c, - 0x2e, 0x0e, 0xf1, 0xdb, 0x12, 0xa3, 0xc3, 0xf5, 0x9b, 0xe2, 0xf4, 0xbf, 0x3c, 0xb0, 0x2d, 0x58, - 0x0a, 0x04, 0x54, 0x96, 0x77, 0x45, 0xa9, 0xeb, 0xd1, 0x2b, 0x93, 0xa0, 0xb5, 0x57, 0xfe, 0xc0, - 0x81, 0x45, 0x39, 0x34, 0xf4, 0x29, 0xac, 0xeb, 0x9c, 0x62, 0x60, 0x16, 0x56, 0x7f, 0x09, 0xae, - 0x2a, 0xa9, 0x73, 0x75, 0x92, 0xca, 0xa0, 0x99, 0xf8, 0xf9, 0x11, 0x85, 0x21, 0x2d, 0x8f, 0x7e, - 0x63, 0xf0, 0x8f, 0xa1, 0xb1, 0xd0, 0x08, 0x0a, 0x8b, 0xeb, 0xee, 0x5d, 0x0a, 0xc3, 0x5b, 0xc1, - 0x71, 0x50, 0x74, 0x5e, 0x2e, 0x70, 0x9d, 0x06, 0x97, 0x77, 0x11, 0x0a, 0xb8, 0x98, 0x2f, 0xc9, - 0xa2, 0x3c, 0x5f, 0x92, 0xd4, 0xd3, 0xf5, 0x6e, 0x1f, 0x7a, 0x77, 0x78, 0xc8, 0x73, 0x7e, 0x33, - 0x0c, 0xcb, 0xfc, 0x2f, 0xc0, 0xf9, 0x9a, 0x3a, 0xe9, 0x9a, 0xdc, 0x83, 0xb5, 0x3b, 0xfc, 0x60, - 0x3a, 0x7e, 0xc0, 0x8f, 0x8b, 0xb3, 0x2a, 0x06, 0xcd, 0xec, 0x28, 0x3e, 0x91, 0x6b, 0x4b, 0xbf, - 0xd9, 0x2b, 0x00, 0x21, 0xd2, 0x0c, 0xb2, 0x84, 0x0f, 0xd5, 0xf5, 0x2f, 0x42, 0xf6, 0x13, 0x3e, - 0x74, 0xdf, 0x06, 0x66, 0xf2, 0x91, 0x43, 0x40, 0x6d, 0x9f, 0x1e, 0x0c, 0xb2, 0x59, 0x96, 0xf3, - 0x89, 0xba, 0xd7, 0x66, 0x42, 0xee, 0x15, 0xe8, 0xec, 0xf9, 0x33, 0x8f, 0x7f, 0x2c, 0x6f, 0xd4, - 0x62, 0x04, 0xec, 0xcf, 0x50, 0x94, 0x75, 0x04, 0x4c, 0xd5, 0xee, 0x7f, 0x36, 0x60, 0x41, 0x50, - 0x22, 0xd7, 0x11, 0xcf, 0xf2, 0x20, 0x12, 0xe7, 0x34, 0x92, 0xab, 0x01, 0x55, 0x64, 0xa3, 0x51, - 0x23, 0x1b, 0xd2, 0x27, 0x55, 0x57, 0x69, 0xa4, 0x10, 0x58, 0x18, 0x3a, 0x2f, 0xc5, 0xf9, 0xb7, - 0x08, 0xc1, 0x0a, 0xa0, 0x94, 0x12, 0x29, 0x6c, 0x8a, 0xe8, 0x9f, 0x12, 0x5a, 0x29, 0x0e, 0x26, - 0x54, 0x6b, 0xb9, 0x16, 0x85, 0xd4, 0x54, 0x2c, 0x57, 0xc5, 0x42, 0x2d, 0xbd, 0x84, 0x85, 0x12, - 0x8e, 0xea, 0xf3, 0x2c, 0x14, 0xbc, 0x8c, 0x85, 0x62, 0xb0, 0x7a, 0x8f, 0x73, 0x8f, 0xe3, 0xde, - 0xa7, 0xc4, 0xe9, 0xbb, 0x0e, 0xac, 0xca, 0x6d, 0x5b, 0xd7, 0xb1, 0xd7, 0xac, 0x3d, 0xde, 0xa9, - 0x4b, 0xf7, 0xbf, 0x0e, 0xcb, 0xb4, 0xf3, 0xea, 0xdc, 0x8f, 0x4c, 0x54, 0x59, 0x20, 0x8e, 0x43, - 0x25, 0xb0, 0x27, 0x41, 0x28, 0x17, 0xc5, 0x84, 0x54, 0xfa, 0x08, 0xa3, 0x60, 0x5a, 0x12, 0xc7, - 0xd3, 0x65, 0xf7, 0x6f, 0x1c, 0x58, 0x33, 0x3a, 0x2c, 0xa5, 0xf0, 0x06, 0xa8, 0xf3, 0x71, 0x91, - 0x22, 0x12, 0xca, 0x74, 0xce, 0x76, 0x41, 0x8a, 0xcf, 0x2c, 0x62, 0x5a, 0x4c, 0x7f, 0x46, 0x1d, - 0xcc, 0xa6, 0x13, 0xe9, 0x67, 0x98, 0x10, 0x0a, 0xd2, 0x09, 0xe7, 0x4f, 0x34, 0xc9, 0x1c, 0x91, - 0x58, 0x18, 0x1d, 0x7f, 0xa2, 0xc7, 0xa0, 0x89, 0xc4, 0x8d, 0x1f, 0x1b, 0x74, 0xff, 0xc1, 0x81, - 0x75, 0xe1, 0xfa, 0x49, 0xc7, 0x5a, 0xdf, 0x46, 0x5c, 0x10, 0xbe, 0xae, 0xd0, 0xc8, 0xdd, 0x33, - 0x9e, 0x2c, 0xb3, 0x2f, 0xbe, 0xa4, 0xbb, 0xaa, 0x8f, 0xbd, 0x4f, 0x59, 0x8b, 0xb9, 0xba, 0xb5, - 0x78, 0xce, 0x4c, 0xd7, 0xa5, 0x44, 0xe6, 0x6b, 0x53, 0x22, 0xb7, 0x16, 0x61, 0x3e, 0x1b, 0xc6, - 0x09, 0x77, 0x37, 0x61, 0xc3, 0x1e, 0x9c, 0x34, 0x41, 0xdf, 0x73, 0xa0, 0x77, 0x4f, 0x24, 0x08, - 0x83, 0x68, 0xbc, 0x1b, 0x64, 0x79, 0x9c, 0xea, 0xeb, 0xd7, 0x97, 0x00, 0xb2, 0xdc, 0x4f, 0x73, - 0x71, 0x2d, 0x49, 0x26, 0x33, 0x0a, 0x04, 0xfb, 0xc8, 0xa3, 0x91, 0xa8, 0x15, 0x6b, 0xa3, 0xcb, - 0xb8, 0x30, 0x74, 0x24, 0x3f, 0x88, 0x0f, 0x0f, 0x33, 0xae, 0x9d, 0x53, 0x13, 0xc3, 0xf8, 0x16, - 0x35, 0x1e, 0x23, 0x3a, 0x7e, 0x4c, 0xa6, 0x56, 0x78, 0x7d, 0x25, 0xd4, 0xfd, 0x6b, 0x07, 0x56, - 0x8a, 0x4e, 0xde, 0x45, 0xd0, 0xb6, 0x0e, 0xa2, 0x6b, 0x86, 0x75, 0x50, 0x69, 0x96, 0x60, 0x34, - 0x08, 0x22, 0xd9, 0x37, 0x03, 0x21, 0x8d, 0x95, 0xa5, 0x78, 0xaa, 0xae, 0x80, 0x99, 0x90, 0x38, - 0xdf, 0xcd, 0xf1, 0x6b, 0x71, 0xff, 0x4b, 0x96, 0xe8, 0x56, 0xd9, 0x24, 0xa7, 0xaf, 0x16, 0x84, - 0xdb, 0x2b, 0x8b, 0x6a, 0x7f, 0x5a, 0x24, 0x14, 0x7f, 0xba, 0x7f, 0xe8, 0xc0, 0xf9, 0x9a, 0xc9, - 0x95, 0x9a, 0x71, 0x07, 0xd6, 0x0e, 0x75, 0xa5, 0x9a, 0x00, 0xa1, 0x1e, 0x9b, 0x52, 0x8a, 0x4a, - 0x83, 0xf6, 0xaa, 0x1f, 0xa0, 0x13, 0x4c, 0xd9, 0x21, 0x31, 0xa5, 0xd6, 0xd5, 0x88, 0x6a, 0xc5, - 0xce, 0xf7, 0x1b, 0xd0, 0x15, 0x07, 0x12, 0xe2, 0x01, 0x0e, 0x4f, 0xd9, 0x07, 0xb0, 0x28, 0x9f, - 0x3b, 0xb1, 0xb3, 0xb2, 0x59, 0xfb, 0x81, 0x55, 0x7f, 0xb3, 0x0c, 0x4b, 0xd9, 0x59, 0xff, 0xdd, - 0xcf, 0xfe, 0xf9, 0x8f, 0x1a, 0xcb, 0xac, 0xbd, 0x7d, 0xfc, 0xd6, 0xf6, 0x98, 0x47, 0x19, 0xf2, - 0xf8, 0x75, 0x80, 0xe2, 0xc5, 0x10, 0xeb, 0x69, 0x27, 0xa3, 0xf4, 0xc2, 0xa9, 0x7f, 0xbe, 0xa6, - 0x46, 0xf2, 0x3d, 0x4f, 0x7c, 0xd7, 0xdd, 0x2e, 0xf2, 0x0d, 0xa2, 0x20, 0x17, 0xcf, 0x87, 0xde, - 0x75, 0xb6, 0xd8, 0x08, 0x3a, 0xe6, 0xcb, 0x21, 0xa6, 0x02, 0xe3, 0x9a, 0xe7, 0x48, 0xfd, 0x0b, - 0xb5, 0x75, 0x2a, 0x2b, 0x40, 0x6d, 0x9c, 0x75, 0x57, 0xb1, 0x8d, 0x29, 0x51, 0xe8, 0x56, 0x76, - 0xfe, 0xf1, 0x02, 0xb4, 0x74, 0x72, 0x89, 0x7d, 0x1b, 0x96, 0xad, 0x33, 0x1c, 0xa6, 0x18, 0xd7, - 0x1d, 0xf9, 0xf4, 0x2f, 0xd6, 0x57, 0xca, 0x66, 0x2f, 0x51, 0xb3, 0x3d, 0xb6, 0x89, 0xcd, 0xca, - 0x43, 0x90, 0x6d, 0x3a, 0xb9, 0x12, 0xb7, 0xc8, 0x9e, 0x40, 0xd7, 0x3e, 0x77, 0x61, 0x17, 0x6d, - 0x83, 0x52, 0x6a, 0xed, 0x95, 0x53, 0x6a, 0x65, 0x73, 0x17, 0xa9, 0xb9, 0x4d, 0xb6, 0x61, 0x36, - 0xa7, 0x93, 0x3e, 0x9c, 0xee, 0xfd, 0x99, 0x4f, 0x8a, 0xd8, 0x2b, 0x7a, 0xa9, 0xeb, 0x9e, 0x1a, - 0xe9, 0x45, 0xab, 0xbe, 0x37, 0x72, 0x7b, 0xd4, 0x14, 0x63, 0x34, 0xa1, 0xe6, 0x8b, 0x22, 0xf6, - 0x11, 0xb4, 0xf4, 0x33, 0x02, 0x76, 0xce, 0x78, 0xbb, 0x61, 0xbe, 0x6d, 0xe8, 0xf7, 0xaa, 0x15, - 0x75, 0x4b, 0x65, 0x72, 0x46, 0x81, 0x78, 0x00, 0x67, 0xa5, 0x93, 0x7a, 0xc0, 0x7f, 0x9c, 0x91, - 0xd4, 0x3c, 0x84, 0xba, 0xee, 0xb0, 0x1b, 0xb0, 0xa4, 0x5e, 0x67, 0xb0, 0xcd, 0xfa, 0x57, 0x26, - 0xfd, 0x73, 0x15, 0x5c, 0xea, 0xf3, 0x4d, 0x80, 0xe2, 0x65, 0x81, 0x96, 0xfc, 0xca, 0x7b, 0x07, - 0x3d, 0x89, 0x35, 0xcf, 0x10, 0xc6, 0xf4, 0x8e, 0xc2, 0x7e, 0xb8, 0xc0, 0x5e, 0x2d, 0xe8, 0x6b, - 0x9f, 0x34, 0x3c, 0x87, 0xa1, 0xbb, 0x49, 0x73, 0xb7, 0xca, 0x48, 0x95, 0x22, 0x7e, 0xa2, 0x6e, - 0xc0, 0xde, 0x81, 0xb6, 0xf1, 0x5a, 0x81, 0x29, 0x0e, 0xd5, 0x97, 0x0e, 0xfd, 0x7e, 0x5d, 0x95, - 0xec, 0xee, 0x57, 0x60, 0xd9, 0x7a, 0x76, 0xa0, 0x35, 0xa3, 0xee, 0x51, 0x83, 0xd6, 0x8c, 0xfa, - 0x97, 0x0a, 0xdf, 0x84, 0xb6, 0xf1, 0x48, 0x80, 0x19, 0x37, 0x7f, 0x4a, 0xcf, 0x03, 0x74, 0x8f, - 0xea, 0xde, 0x14, 0x6c, 0xd0, 0x78, 0xbb, 0x6e, 0x0b, 0xc7, 0x4b, 0xd7, 0x40, 0x51, 0x48, 0xbe, - 0x0d, 0x5d, 0xfb, 0xd9, 0x80, 0xd6, 0xaa, 0xda, 0x07, 0x08, 0x5a, 0xab, 0x4e, 0x79, 0x6b, 0x20, - 0x05, 0x72, 0x6b, 0x5d, 0x37, 0xb2, 0xfd, 0xa9, 0x3c, 0x5a, 0x79, 0xc6, 0xbe, 0x8e, 0xa6, 0x43, - 0xde, 0xcb, 0x65, 0xc5, 0x63, 0x09, 0xfb, 0xf6, 0xae, 0x96, 0xf6, 0xca, 0x15, 0x5e, 0x77, 0x8d, - 0x98, 0xb7, 0x59, 0x31, 0x02, 0x61, 0xa1, 0xe9, 0x7e, 0xae, 0x61, 0xa1, 0xcd, 0x2b, 0xbc, 0x86, - 0x85, 0xb6, 0xae, 0xf1, 0x96, 0x2d, 0x74, 0x1e, 0x20, 0x8f, 0x08, 0x56, 0x4a, 0xa7, 0xfd, 0x5a, - 0x59, 0xea, 0xef, 0x0a, 0xf5, 0x2f, 0x3d, 0xff, 0x92, 0x80, 0x6d, 0x66, 0x94, 0x79, 0xd9, 0x56, - 0x57, 0xbb, 0x7e, 0x03, 0x3a, 0xe6, 0x75, 0x6f, 0x6d, 0xb3, 0x6b, 0x2e, 0xa9, 0x6b, 0x9b, 0x5d, - 0x77, 0x3f, 0x5c, 0x2d, 0x2e, 0xeb, 0x98, 0xcd, 0xb0, 0x6f, 0xc2, 0x8a, 0x71, 0xaf, 0x64, 0x7f, - 0x16, 0x0d, 0xb5, 0xf0, 0x54, 0x6f, 0x02, 0xf6, 0xeb, 0xfc, 0x33, 0xf7, 0x1c, 0x31, 0x5e, 0x73, - 0x2d, 0xc6, 0x28, 0x38, 0xb7, 0xa1, 0x6d, 0xde, 0x59, 0x79, 0x0e, 0xdf, 0x73, 0x46, 0x95, 0x79, - 0x29, 0xee, 0xba, 0xc3, 0xfe, 0xc4, 0x81, 0x8e, 0x79, 0xc7, 0x94, 0x59, 0xd9, 0xdc, 0x12, 0x9f, - 0x9e, 0x59, 0x67, 0x32, 0x72, 0x3d, 0xea, 0xe4, 0x83, 0xad, 0xaf, 0x58, 0x93, 0xfc, 0xa9, 0xe5, - 0xe7, 0x5f, 0x2b, 0xbf, 0xe4, 0x7b, 0x56, 0x26, 0x30, 0x6f, 0x4b, 0x3e, 0xbb, 0xee, 0xb0, 0x77, - 0xc5, 0x6b, 0x4f, 0x15, 0xd7, 0x33, 0xc3, 0xb8, 0x95, 0xa7, 0xcc, 0x7c, 0x18, 0x79, 0xd5, 0xb9, - 0xee, 0xb0, 0x6f, 0x89, 0x07, 0x7b, 0xf2, 0x5b, 0x9a, 0xf9, 0x97, 0xfd, 0xde, 0x7d, 0x9d, 0x46, - 0x73, 0xc9, 0x3d, 0x6f, 0x8d, 0xa6, 0x6c, 0xdd, 0xf7, 0x00, 0x8a, 0x24, 0x0d, 0x2b, 0x65, 0x2c, - 0xb4, 0xdd, 0xab, 0xe6, 0x71, 0xec, 0x15, 0x55, 0x89, 0x0d, 0xe4, 0xf8, 0x91, 0x10, 0x46, 0x49, - 0x9f, 0xe9, 0x25, 0xad, 0x26, 0x5b, 0xfa, 0xfd, 0xba, 0xaa, 0x3a, 0x51, 0x54, 0xfc, 0xd9, 0x63, - 0x58, 0x7e, 0x10, 0xc7, 0x4f, 0xa6, 0x89, 0x4e, 0x16, 0xda, 0x39, 0x83, 0x5d, 0x3f, 0x3b, 0xea, - 0x97, 0x46, 0xe1, 0x5e, 0x26, 0x56, 0x7d, 0xd6, 0x33, 0x58, 0x6d, 0x7f, 0x5a, 0xa4, 0x88, 0x9e, - 0x31, 0x1f, 0xd6, 0xf4, 0x1e, 0xa7, 0x3b, 0xde, 0xb7, 0xd9, 0x98, 0x99, 0x9a, 0x4a, 0x13, 0x96, - 0xd7, 0xa1, 0x7a, 0xbb, 0x9d, 0x29, 0x9e, 0xd7, 0x1d, 0xb6, 0x07, 0x9d, 0x3b, 0x7c, 0x18, 0x8f, - 0xb8, 0x8c, 0xf2, 0xd7, 0x8b, 0x8e, 0xeb, 0xf4, 0x40, 0x7f, 0xd9, 0x02, 0x6d, 0xad, 0x4f, 0xfc, - 0x59, 0xca, 0x3f, 0xde, 0xfe, 0x54, 0xe6, 0x0f, 0x9e, 0x29, 0xad, 0x57, 0x39, 0x0f, 0x4b, 0xeb, - 0x4b, 0x49, 0x12, 0x4b, 0xeb, 0x2b, 0x49, 0x12, 0x6b, 0xaa, 0x55, 0xce, 0x85, 0x85, 0xb0, 0x56, - 0xc9, 0xab, 0xe8, 0x9d, 0xf2, 0xb4, 0x6c, 0x4c, 0xff, 0xf2, 0xe9, 0x04, 0x76, 0x6b, 0x5b, 0x76, - 0x6b, 0xfb, 0xb0, 0x7c, 0x87, 0x8b, 0xc9, 0x12, 0x27, 0x92, 0x7d, 0xdb, 0x8c, 0x98, 0xa7, 0x97, - 0x65, 0x13, 0x43, 0x75, 0xb6, 0x59, 0xa7, 0xe3, 0x40, 0xf6, 0x11, 0xb4, 0xef, 0xf3, 0x5c, 0x1d, - 0x41, 0x6a, 0x7f, 0xa3, 0x74, 0x26, 0xd9, 0xaf, 0x39, 0xc1, 0xb4, 0x65, 0x86, 0xb8, 0x6d, 0xf3, - 0xd1, 0x98, 0x0b, 0x65, 0x1f, 0x04, 0xa3, 0x67, 0xec, 0x57, 0x89, 0xb9, 0xbe, 0xb5, 0xb0, 0x69, - 0x9c, 0x5c, 0x99, 0xcc, 0x57, 0x4a, 0x78, 0x1d, 0xe7, 0x28, 0x1e, 0x71, 0x63, 0x83, 0x8b, 0xa0, - 0x6d, 0x5c, 0xa9, 0xd1, 0x0a, 0x54, 0xbd, 0xc6, 0xa3, 0x15, 0xa8, 0xe6, 0x06, 0x8e, 0x7b, 0x95, - 0xda, 0x71, 0xd9, 0xe5, 0xa2, 0x1d, 0x71, 0xeb, 0xa6, 0x68, 0x69, 0xfb, 0x53, 0x7f, 0x92, 0x3f, - 0x63, 0x1f, 0xd2, 0x83, 0x15, 0xf3, 0x98, 0xb5, 0xf0, 0x77, 0xca, 0x27, 0xb2, 0x7a, 0xb2, 0x8c, - 0x2a, 0xdb, 0x07, 0x12, 0x4d, 0xd1, 0x3e, 0xf8, 0x45, 0x80, 0xfd, 0x3c, 0x4e, 0xee, 0xf8, 0x7c, - 0x12, 0x47, 0x85, 0xe5, 0x2a, 0x8e, 0x12, 0x0b, 0xcb, 0x65, 0x9c, 0x27, 0xb2, 0x0f, 0x0d, 0x8f, - 0xd3, 0x3a, 0xa5, 0x56, 0xc2, 0x75, 0xea, 0x69, 0xa3, 0x9e, 0x90, 0x9a, 0x13, 0xc7, 0xeb, 0x0e, - 0xfa, 0x8f, 0x45, 0x16, 0x4f, 0xfb, 0x8f, 0x95, 0x04, 0xa1, 0x36, 0x7b, 0x35, 0x29, 0xbf, 0x3d, - 0x68, 0x15, 0x69, 0x21, 0xb5, 0x25, 0x95, 0x93, 0x48, 0x7a, 0x8f, 0xa9, 0x24, 0x6b, 0xdc, 0x55, - 0x9a, 0x2a, 0x60, 0x4b, 0x38, 0x55, 0x94, 0x81, 0x09, 0x60, 0x5d, 0x74, 0x50, 0x6f, 0x98, 0x74, - 0x38, 0xa6, 0x46, 0x52, 0x93, 0x30, 0xd1, 0xda, 0x5c, 0x9b, 0x6f, 0xb0, 0x62, 0x3b, 0x94, 0x56, - 0x71, 0x30, 0x87, 0xa6, 0x79, 0x02, 0x6b, 0x95, 0x60, 0x59, 0xab, 0xf4, 0x69, 0x39, 0x0a, 0xad, - 0xd2, 0xa7, 0xc6, 0xd9, 0xee, 0x59, 0x6a, 0x72, 0xc5, 0x05, 0x6c, 0x32, 0x3b, 0x09, 0xf2, 0xe1, - 0xd1, 0xbb, 0xce, 0xd6, 0xc1, 0x02, 0xfd, 0x9f, 0xc8, 0xe7, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, - 0xbe, 0xb8, 0xff, 0xb8, 0x81, 0x44, 0x00, 0x00, + 0x41, 0x84, 0x7d, 0x81, 0x03, 0x47, 0x4e, 0xe6, 0x2f, 0x70, 0x04, 0xc1, 0x61, 0x4f, 0x0e, 0x6e, + 0x7c, 0x1c, 0xc0, 0xc1, 0x85, 0x08, 0x2e, 0x1c, 0x08, 0xe2, 0xbd, 0xfc, 0xa8, 0xcc, 0xaa, 0x1a, + 0x49, 0xb6, 0xc1, 0xb7, 0xce, 0x5f, 0xbe, 0x7a, 0xf9, 0xf5, 0xde, 0xcb, 0xf7, 0x5e, 0x66, 0x36, + 0xb4, 0xd2, 0x64, 0x78, 0x2d, 0x49, 0xe3, 0x3c, 0x66, 0xf3, 0x61, 0x94, 0x26, 0xc3, 0xfe, 0xc5, + 0x71, 0x1c, 0x8f, 0x43, 0xbe, 0xed, 0x27, 0xc1, 0xb6, 0x1f, 0x45, 0x71, 0xee, 0xe7, 0x41, 0x1c, + 0x65, 0x82, 0xc8, 0xfd, 0x16, 0x74, 0xef, 0xf3, 0x68, 0x9f, 0xf3, 0x91, 0xc7, 0x3f, 0x9e, 0xf2, + 0x2c, 0x67, 0xbf, 0x08, 0x6b, 0x3e, 0xff, 0x84, 0xf3, 0xd1, 0x20, 0xf1, 0xb3, 0x2c, 0x39, 0x4a, + 0xfd, 0x8c, 0xf7, 0x9c, 0xcb, 0xce, 0xd5, 0x8e, 0xb7, 0x2a, 0x2a, 0xf6, 0x34, 0xce, 0x5e, 0x83, + 0x4e, 0x86, 0xa4, 0x3c, 0xca, 0xd3, 0x38, 0x99, 0xf5, 0x1a, 0x44, 0xd7, 0x46, 0xec, 0xae, 0x80, + 0xdc, 0x10, 0x56, 0x74, 0x0b, 0x59, 0x12, 0x47, 0x19, 0x67, 0xd7, 0x61, 0x63, 0x18, 0x24, 0x47, + 0x3c, 0x1d, 0xd0, 0xc7, 0x93, 0x88, 0x4f, 0xe2, 0x28, 0x18, 0xf6, 0x9c, 0xcb, 0x73, 0x57, 0x5b, + 0x1e, 0x13, 0x75, 0xf8, 0xc5, 0x07, 0xb2, 0x86, 0x5d, 0x81, 0x15, 0x1e, 0x09, 0x9c, 0x8f, 0xe8, + 0x2b, 0xd9, 0x54, 0xb7, 0x80, 0xf1, 0x03, 0xf7, 0xcf, 0x1d, 0x58, 0x7b, 0x3f, 0x0a, 0xf2, 0x0f, + 0xfd, 0x30, 0xe4, 0xb9, 0x1a, 0xd3, 0x15, 0x58, 0x39, 0x21, 0x80, 0xc6, 0x74, 0x12, 0xa7, 0x23, + 0x39, 0xa2, 0xae, 0x80, 0xf7, 0x24, 0x7a, 0x6a, 0xcf, 0x1a, 0xa7, 0xf6, 0xac, 0x76, 0xba, 0xe6, + 0xea, 0xa7, 0xcb, 0xdd, 0x00, 0x66, 0x76, 0x4e, 0x4c, 0x87, 0xfb, 0x1e, 0xac, 0x3f, 0x8e, 0xc2, + 0x78, 0xf8, 0xe4, 0xa7, 0xeb, 0xb4, 0xbb, 0x09, 0x1b, 0xf6, 0xf7, 0x92, 0xef, 0x77, 0x1b, 0xd0, + 0x7e, 0x94, 0xfa, 0x51, 0xe6, 0x0f, 0x71, 0xc9, 0x59, 0x0f, 0x16, 0xf3, 0xa7, 0x83, 0x23, 0x3f, + 0x3b, 0x22, 0x46, 0x2d, 0x4f, 0x15, 0xd9, 0x26, 0x2c, 0xf8, 0x93, 0x78, 0x1a, 0xe5, 0x34, 0xab, + 0x73, 0x9e, 0x2c, 0xb1, 0x37, 0x61, 0x2d, 0x9a, 0x4e, 0x06, 0xc3, 0x38, 0x3a, 0x0c, 0xd2, 0x89, + 0x10, 0x1c, 0x1a, 0xdc, 0xbc, 0x57, 0xad, 0x60, 0x97, 0x00, 0x0e, 0xb0, 0x1b, 0xa2, 0x89, 0x26, + 0x35, 0x61, 0x20, 0xcc, 0x85, 0x8e, 0x2c, 0xf1, 0x60, 0x7c, 0x94, 0xf7, 0xe6, 0x89, 0x91, 0x85, + 0x21, 0x8f, 0x3c, 0x98, 0xf0, 0x41, 0x96, 0xfb, 0x93, 0xa4, 0xb7, 0x40, 0xbd, 0x31, 0x10, 0xaa, + 0x8f, 0x73, 0x3f, 0x1c, 0x1c, 0x72, 0x9e, 0xf5, 0x16, 0x65, 0xbd, 0x46, 0xd8, 0x1b, 0xd0, 0x1d, + 0xf1, 0x2c, 0x1f, 0xf8, 0xa3, 0x51, 0xca, 0xb3, 0x8c, 0x67, 0xbd, 0x25, 0x5a, 0xba, 0x12, 0xea, + 0xf6, 0x60, 0xf3, 0x3e, 0xcf, 0x8d, 0xd9, 0xc9, 0xe4, 0xb4, 0xbb, 0x0f, 0x80, 0x19, 0xf0, 0x1d, + 0x9e, 0xfb, 0x41, 0x98, 0xb1, 0xb7, 0xa1, 0x93, 0x1b, 0xc4, 0x24, 0xaa, 0xed, 0x1d, 0x76, 0x8d, + 0x74, 0xec, 0x9a, 0xf1, 0x81, 0x67, 0xd1, 0xb9, 0xff, 0xed, 0x40, 0x7b, 0x9f, 0x47, 0x5a, 0xbb, + 0x18, 0x34, 0xb1, 0x27, 0x72, 0x25, 0xe9, 0x37, 0x7b, 0x15, 0xda, 0xd4, 0xbb, 0x2c, 0x4f, 0x83, + 0x68, 0x4c, 0x4b, 0xd0, 0xf2, 0x00, 0xa1, 0x7d, 0x42, 0xd8, 0x2a, 0xcc, 0xf9, 0x93, 0x9c, 0x26, + 0x7e, 0xce, 0xc3, 0x9f, 0xa8, 0x77, 0x89, 0x3f, 0x9b, 0xf0, 0x28, 0x2f, 0x26, 0xbb, 0xe3, 0xb5, + 0x25, 0xb6, 0x8b, 0xb3, 0x7d, 0x0d, 0xd6, 0x4d, 0x12, 0xc5, 0x7d, 0x9e, 0xb8, 0xaf, 0x19, 0x94, + 0xb2, 0x91, 0x2b, 0xb0, 0xa2, 0xe8, 0x53, 0xd1, 0x59, 0x9a, 0xfe, 0x96, 0xd7, 0x95, 0xb0, 0x1a, + 0xc2, 0x55, 0x58, 0x3d, 0x0c, 0x22, 0x3f, 0x1c, 0x0c, 0xc3, 0xfc, 0x78, 0x30, 0xe2, 0x61, 0xee, + 0xd3, 0x42, 0xcc, 0x7b, 0x5d, 0xc2, 0x6f, 0x87, 0xf9, 0xf1, 0x1d, 0x44, 0xdd, 0x3f, 0x75, 0xa0, + 0x23, 0x06, 0x2f, 0x15, 0xff, 0x75, 0x58, 0x56, 0x6d, 0xf0, 0x34, 0x8d, 0x53, 0x29, 0x87, 0x36, + 0xc8, 0xb6, 0x60, 0x55, 0x01, 0x49, 0xca, 0x83, 0x89, 0x3f, 0xe6, 0x52, 0xdb, 0x2b, 0x38, 0xdb, + 0x29, 0x38, 0xa6, 0xf1, 0x34, 0x17, 0xaa, 0xd7, 0xde, 0xe9, 0xc8, 0x85, 0xf1, 0x10, 0xf3, 0x6c, + 0x12, 0xf7, 0x7b, 0x0e, 0x74, 0x6e, 0x1f, 0xf9, 0x51, 0xc4, 0xc3, 0xbd, 0x38, 0x88, 0x72, 0x76, + 0x1d, 0xd8, 0xe1, 0x34, 0x1a, 0x05, 0xd1, 0x78, 0x90, 0x3f, 0x0d, 0x46, 0x83, 0x83, 0x59, 0xce, + 0x33, 0xb1, 0x44, 0xbb, 0x67, 0xbc, 0x9a, 0x3a, 0xf6, 0x26, 0xac, 0x5a, 0x68, 0x96, 0xa7, 0x62, + 0xdd, 0x76, 0xcf, 0x78, 0x95, 0x1a, 0x14, 0xfc, 0x78, 0x9a, 0x27, 0xd3, 0x7c, 0x10, 0x44, 0x23, + 0xfe, 0x94, 0xfa, 0xb8, 0xec, 0x59, 0xd8, 0xad, 0x2e, 0x74, 0xcc, 0xef, 0xdc, 0xf7, 0x60, 0xf5, + 0x01, 0x6a, 0x44, 0x14, 0x44, 0xe3, 0x9b, 0x42, 0x6c, 0x51, 0x4d, 0x93, 0xe9, 0xc1, 0x13, 0x3e, + 0x93, 0xf3, 0x26, 0x4b, 0x28, 0x54, 0x47, 0x71, 0x96, 0x4b, 0xc9, 0xa1, 0xdf, 0xee, 0x3f, 0x3b, + 0xb0, 0x82, 0x73, 0xff, 0x81, 0x1f, 0xcd, 0xd4, 0xca, 0x3d, 0x80, 0x0e, 0xb2, 0x7a, 0x14, 0xdf, + 0x14, 0xca, 0x2e, 0x84, 0xf8, 0xaa, 0x9c, 0xab, 0x12, 0xf5, 0x35, 0x93, 0x14, 0x8d, 0xf9, 0xcc, + 0xb3, 0xbe, 0x46, 0xb1, 0xcd, 0xfd, 0x74, 0xcc, 0x73, 0x32, 0x03, 0xd2, 0x2c, 0x80, 0x80, 0x6e, + 0xc7, 0xd1, 0x21, 0xbb, 0x0c, 0x9d, 0xcc, 0xcf, 0x07, 0x09, 0x4f, 0x69, 0xd6, 0x48, 0xf4, 0xe6, + 0x3c, 0xc8, 0xfc, 0x7c, 0x8f, 0xa7, 0xb7, 0x66, 0x39, 0xef, 0x7f, 0x19, 0xd6, 0x2a, 0xad, 0xa0, + 0xb4, 0x17, 0x43, 0xc4, 0x9f, 0x6c, 0x03, 0xe6, 0x8f, 0xfd, 0x70, 0xca, 0xa5, 0x75, 0x12, 0x85, + 0x77, 0x1b, 0xef, 0x38, 0xee, 0x1b, 0xb0, 0x5a, 0x74, 0x5b, 0x0a, 0x19, 0x83, 0x26, 0xce, 0xa0, + 0x64, 0x40, 0xbf, 0xdd, 0xdf, 0x73, 0x04, 0xe1, 0xed, 0x38, 0xd0, 0x9a, 0x8e, 0x84, 0x68, 0x10, + 0x14, 0x21, 0xfe, 0x3e, 0xd5, 0x12, 0xfe, 0xec, 0x83, 0x75, 0xaf, 0xc0, 0x9a, 0xd1, 0x85, 0xe7, + 0x74, 0xf6, 0x3b, 0x0e, 0xac, 0x3d, 0xe4, 0x27, 0x72, 0xd5, 0x55, 0x6f, 0xdf, 0x81, 0x66, 0x3e, + 0x4b, 0xc4, 0x56, 0xdc, 0xdd, 0x79, 0x5d, 0x2e, 0x5a, 0x85, 0xee, 0x9a, 0x2c, 0x3e, 0x9a, 0x25, + 0xdc, 0xa3, 0x2f, 0xdc, 0xf7, 0xa0, 0x6d, 0x80, 0xec, 0x1c, 0xac, 0x7f, 0xf8, 0xfe, 0xa3, 0x87, + 0x77, 0xf7, 0xf7, 0x07, 0x7b, 0x8f, 0x6f, 0x7d, 0xf5, 0xee, 0x6f, 0x0c, 0x76, 0x6f, 0xee, 0xef, + 0xae, 0x9e, 0x61, 0x9b, 0xc0, 0x1e, 0xde, 0xdd, 0x7f, 0x74, 0xf7, 0x8e, 0x85, 0x3b, 0x6e, 0x1f, + 0x7a, 0x0f, 0xf9, 0xc9, 0x87, 0x41, 0x1e, 0xf1, 0x2c, 0xb3, 0x5b, 0x73, 0xaf, 0x01, 0x33, 0xbb, + 0x20, 0x47, 0xd5, 0x83, 0x45, 0x69, 0x6a, 0xd5, 0x4e, 0x23, 0x8b, 0xee, 0x1b, 0xc0, 0xf6, 0x83, + 0x71, 0xf4, 0x01, 0xcf, 0x32, 0x7f, 0xcc, 0xd5, 0xd8, 0x56, 0x61, 0x6e, 0x92, 0x8d, 0xa5, 0x51, + 0xc4, 0x9f, 0xee, 0xe7, 0x61, 0xdd, 0xa2, 0x93, 0x8c, 0x2f, 0x42, 0x2b, 0x0b, 0xc6, 0x91, 0x9f, + 0x4f, 0x53, 0x2e, 0x59, 0x17, 0x80, 0x7b, 0x0f, 0x36, 0xbe, 0xc1, 0xd3, 0xe0, 0x70, 0xf6, 0x22, + 0xf6, 0x36, 0x9f, 0x46, 0x99, 0xcf, 0x5d, 0x38, 0x5b, 0xe2, 0x23, 0x9b, 0x17, 0x82, 0x28, 0x97, + 0x6b, 0xc9, 0x13, 0x05, 0x43, 0x2d, 0x1b, 0xa6, 0x5a, 0xba, 0x8f, 0x81, 0xdd, 0x8e, 0xa3, 0x88, + 0x0f, 0xf3, 0x3d, 0xce, 0xd3, 0xc2, 0xbf, 0x2a, 0xa4, 0xae, 0xbd, 0x73, 0x4e, 0xae, 0x63, 0x59, + 0xd7, 0xa5, 0x38, 0x32, 0x68, 0x26, 0x3c, 0x9d, 0x10, 0xe3, 0x25, 0x8f, 0x7e, 0xbb, 0x67, 0x61, + 0xdd, 0x62, 0x2b, 0x77, 0xfb, 0xb7, 0xe0, 0xec, 0x9d, 0x20, 0x1b, 0x56, 0x1b, 0xec, 0xc1, 0x62, + 0x32, 0x3d, 0x18, 0x14, 0x3a, 0xa5, 0x8a, 0xb8, 0x09, 0x96, 0x3f, 0x91, 0xcc, 0xfe, 0xd0, 0x81, + 0xe6, 0xee, 0xa3, 0x07, 0xb7, 0x59, 0x1f, 0x96, 0x82, 0x68, 0x18, 0x4f, 0x70, 0xeb, 0x10, 0x83, + 0xd6, 0xe5, 0x53, 0x75, 0xe5, 0x22, 0xb4, 0x68, 0xc7, 0xc1, 0x7d, 0x5d, 0xba, 0x42, 0x05, 0x80, + 0x3e, 0x05, 0x7f, 0x9a, 0x04, 0x29, 0x39, 0x0d, 0xca, 0x15, 0x68, 0x92, 0x45, 0xac, 0x56, 0xb8, + 0xff, 0xd3, 0x84, 0x45, 0x69, 0xab, 0xa9, 0xbd, 0x61, 0x1e, 0x1c, 0x73, 0xd9, 0x13, 0x59, 0xc2, + 0x5d, 0x25, 0xe5, 0x93, 0x38, 0xe7, 0x03, 0x6b, 0x19, 0x6c, 0x10, 0xa9, 0x86, 0x82, 0xd1, 0x20, + 0x41, 0xab, 0x4f, 0x3d, 0x6b, 0x79, 0x36, 0x88, 0x93, 0x85, 0xc0, 0x20, 0x18, 0x51, 0x9f, 0x9a, + 0x9e, 0x2a, 0xe2, 0x4c, 0x0c, 0xfd, 0xc4, 0x1f, 0x06, 0xf9, 0x4c, 0x2a, 0xb7, 0x2e, 0x23, 0xef, + 0x30, 0x1e, 0xfa, 0xe1, 0xe0, 0xc0, 0x0f, 0xfd, 0x68, 0xc8, 0xa5, 0xe3, 0x62, 0x83, 0xe8, 0x9b, + 0xc8, 0x2e, 0x29, 0x32, 0xe1, 0xbf, 0x94, 0x50, 0xf4, 0x71, 0x86, 0xf1, 0x64, 0x12, 0xe4, 0xe8, + 0xd2, 0xf4, 0x96, 0x84, 0x21, 0x29, 0x10, 0x1a, 0x89, 0x28, 0x9d, 0x88, 0xd9, 0x6b, 0x89, 0xd6, + 0x2c, 0x10, 0xb9, 0x1c, 0x72, 0x4e, 0x06, 0xe9, 0xc9, 0x49, 0x0f, 0x04, 0x97, 0x02, 0xc1, 0x75, + 0x98, 0x46, 0x19, 0xcf, 0xf3, 0x90, 0x8f, 0x74, 0x87, 0xda, 0x44, 0x56, 0xad, 0x60, 0xd7, 0x61, + 0x5d, 0x78, 0x59, 0x99, 0x9f, 0xc7, 0xd9, 0x51, 0x90, 0x0d, 0x32, 0x1e, 0xe5, 0xbd, 0x0e, 0xd1, + 0xd7, 0x55, 0xb1, 0x77, 0xe0, 0x5c, 0x09, 0x4e, 0xf9, 0x90, 0x07, 0xc7, 0x7c, 0xd4, 0x5b, 0xa6, + 0xaf, 0x4e, 0xab, 0x66, 0x97, 0xa1, 0x8d, 0xce, 0xe5, 0x34, 0x19, 0xf9, 0xb8, 0x0f, 0x77, 0x69, + 0x1d, 0x4c, 0x88, 0xbd, 0x05, 0xcb, 0x09, 0x17, 0x9b, 0xe5, 0x51, 0x1e, 0x0e, 0xb3, 0xde, 0x0a, + 0xed, 0x64, 0x6d, 0xa9, 0x4c, 0x28, 0xb9, 0x9e, 0x4d, 0x81, 0x42, 0x39, 0xcc, 0xc8, 0x5d, 0xf1, + 0x67, 0xbd, 0x55, 0x12, 0xb7, 0x02, 0x20, 0x1d, 0x49, 0x83, 0x63, 0x3f, 0xe7, 0xbd, 0x35, 0x92, + 0x2d, 0x55, 0x74, 0xff, 0xd2, 0x81, 0xf5, 0x07, 0x41, 0x96, 0x4b, 0x21, 0xd4, 0xe6, 0xf8, 0x55, + 0x68, 0x0b, 0xf1, 0x1b, 0xc4, 0x51, 0x38, 0x93, 0x12, 0x09, 0x02, 0xfa, 0x5a, 0x14, 0xce, 0xd8, + 0xe7, 0x60, 0x39, 0x88, 0x4c, 0x12, 0xa1, 0xc3, 0x1d, 0x05, 0x12, 0xd1, 0xab, 0xd0, 0x4e, 0xa6, + 0x07, 0x61, 0x30, 0x14, 0x24, 0x73, 0x82, 0x8b, 0x80, 0x88, 0x00, 0x1d, 0x3d, 0xd1, 0x13, 0x41, + 0xd1, 0x24, 0x8a, 0xb6, 0xc4, 0x90, 0xc4, 0xbd, 0x05, 0x1b, 0x76, 0x07, 0xa5, 0xb1, 0xda, 0x82, + 0x25, 0x29, 0xdb, 0x59, 0xaf, 0x4d, 0xf3, 0xd3, 0x95, 0xf3, 0x23, 0x49, 0x3d, 0x5d, 0xef, 0xfe, + 0xbb, 0x03, 0x4d, 0x34, 0x00, 0xa7, 0x1b, 0x0b, 0xd3, 0xa6, 0xcf, 0x59, 0x36, 0x9d, 0xfc, 0x7e, + 0xf4, 0x8a, 0x84, 0x48, 0x08, 0xb5, 0x31, 0x90, 0xa2, 0x3e, 0xe5, 0xc3, 0x63, 0xd2, 0x1d, 0x5d, + 0x8f, 0x08, 0x6a, 0x16, 0x6e, 0x9d, 0xf4, 0xb5, 0x50, 0x1c, 0x5d, 0x56, 0x75, 0xf4, 0xe5, 0x62, + 0x51, 0x47, 0xdf, 0xf5, 0x60, 0x31, 0x88, 0x0e, 0xe2, 0x69, 0x34, 0x22, 0x25, 0x59, 0xf2, 0x54, + 0x11, 0x17, 0x3b, 0x21, 0x4f, 0x2a, 0x98, 0x70, 0xa9, 0x1d, 0x05, 0xe0, 0x32, 0x74, 0xad, 0x32, + 0x32, 0x78, 0x7a, 0x1f, 0x7b, 0x1b, 0xd6, 0x0c, 0x4c, 0xce, 0xe0, 0x6b, 0x30, 0x9f, 0x20, 0x20, + 0x1d, 0x25, 0x25, 0x5e, 0x64, 0x29, 0x45, 0x8d, 0xbb, 0x8a, 0xf1, 0x73, 0xfe, 0x7e, 0x74, 0x18, + 0x2b, 0x4e, 0x3f, 0x9a, 0xc3, 0x80, 0x57, 0x42, 0x92, 0xd1, 0x55, 0x58, 0x09, 0x46, 0x3c, 0xca, + 0x83, 0x7c, 0x36, 0xb0, 0x3c, 0xb8, 0x32, 0x8c, 0x3b, 0x8c, 0x1f, 0x06, 0x7e, 0x26, 0x6d, 0x98, + 0x28, 0xb0, 0x1d, 0xd8, 0x40, 0xf1, 0x57, 0x12, 0xad, 0x97, 0x55, 0x38, 0x92, 0xb5, 0x75, 0xa8, + 0xb1, 0x88, 0x4b, 0x09, 0xd4, 0x9f, 0x08, 0x4b, 0x5b, 0x57, 0x85, 0xb3, 0x26, 0x38, 0xe1, 0x90, + 0xe7, 0x85, 0x8a, 0x68, 0xa0, 0x12, 0xbd, 0x2d, 0x08, 0x27, 0xb6, 0x1c, 0xbd, 0x19, 0x11, 0xe0, + 0x52, 0x25, 0x02, 0xbc, 0x0a, 0x2b, 0xd9, 0x2c, 0x1a, 0xf2, 0xd1, 0x20, 0x8f, 0xb1, 0xdd, 0x20, + 0xa2, 0xd5, 0x59, 0xf2, 0xca, 0x30, 0xc5, 0xaa, 0x3c, 0xcb, 0x23, 0x9e, 0x93, 0xe9, 0x5a, 0xf2, + 0x54, 0x11, 0x77, 0x01, 0x22, 0x11, 0x42, 0xdd, 0xf2, 0x64, 0x09, 0xb7, 0xca, 0x69, 0x1a, 0x64, + 0xbd, 0x0e, 0xa1, 0xf4, 0x9b, 0x7d, 0x01, 0xce, 0x1e, 0x60, 0x64, 0x75, 0xc4, 0xfd, 0x11, 0x4f, + 0x69, 0xf5, 0x45, 0x60, 0x29, 0x2c, 0x50, 0x7d, 0x25, 0xb6, 0x7d, 0xcc, 0xd3, 0x2c, 0x88, 0x23, + 0xb2, 0x3d, 0x2d, 0x4f, 0x15, 0xdd, 0x4f, 0x68, 0x47, 0xd7, 0x21, 0xef, 0x63, 0x32, 0x47, 0xec, + 0x02, 0xb4, 0xc4, 0x18, 0xb3, 0x23, 0x5f, 0x3a, 0x19, 0x4b, 0x04, 0xec, 0x1f, 0xf9, 0xa8, 0xc0, + 0xd6, 0xb4, 0x35, 0xc8, 0x73, 0x6c, 0x13, 0xb6, 0x2b, 0x66, 0xed, 0x75, 0xe8, 0xaa, 0x60, 0x3a, + 0x1b, 0x84, 0xfc, 0x30, 0x57, 0x01, 0x42, 0x34, 0x9d, 0x60, 0x73, 0xd9, 0x03, 0x7e, 0x98, 0xbb, + 0x0f, 0x61, 0x4d, 0xea, 0xed, 0xd7, 0x12, 0xae, 0x9a, 0xfe, 0x52, 0x79, 0x53, 0x13, 0x5e, 0xc5, + 0xba, 0xad, 0xe8, 0x14, 0xe5, 0x94, 0x76, 0x3a, 0xd7, 0x03, 0x26, 0xab, 0x6f, 0x87, 0x71, 0xc6, + 0x25, 0x43, 0x17, 0x3a, 0xc3, 0x30, 0xce, 0x54, 0x18, 0x22, 0x87, 0x63, 0x61, 0x38, 0x3f, 0xd9, + 0x74, 0x38, 0x44, 0x4b, 0x20, 0x6c, 0x9a, 0x2a, 0xba, 0x7f, 0xe5, 0xc0, 0x3a, 0x71, 0x53, 0x16, + 0x46, 0xfb, 0xae, 0x2f, 0xdf, 0xcd, 0xce, 0xd0, 0x0c, 0xcd, 0x36, 0x60, 0xfe, 0x30, 0x4e, 0x87, + 0x5c, 0xb6, 0x24, 0x0a, 0x3f, 0xb9, 0x37, 0xde, 0xac, 0x78, 0xe3, 0x3f, 0x72, 0x60, 0x8d, 0xba, + 0xba, 0x9f, 0xfb, 0xf9, 0x34, 0x93, 0xc3, 0xff, 0x15, 0x58, 0xc6, 0xa1, 0x72, 0xa5, 0x4e, 0xb2, + 0xa3, 0x1b, 0x5a, 0xf3, 0x09, 0x15, 0xc4, 0xbb, 0x67, 0x3c, 0x9b, 0x98, 0x7d, 0x19, 0x3a, 0x66, + 0x46, 0x84, 0xfa, 0xdc, 0xde, 0x39, 0xaf, 0x46, 0x59, 0x91, 0x9c, 0xdd, 0x33, 0x9e, 0xf5, 0x01, + 0xbb, 0x01, 0x40, 0xee, 0x06, 0xb1, 0x95, 0xa1, 0xec, 0x79, 0x7b, 0x92, 0x8c, 0xc5, 0xda, 0x3d, + 0xe3, 0x19, 0xe4, 0xb7, 0x96, 0x60, 0x41, 0xec, 0x8f, 0xee, 0x7d, 0x58, 0xb6, 0x7a, 0x6a, 0x45, + 0x19, 0x1d, 0x11, 0x65, 0x54, 0x82, 0xd2, 0x46, 0x35, 0x28, 0x75, 0xff, 0xb5, 0x01, 0x0c, 0xa5, + 0xad, 0xb4, 0x9c, 0xb8, 0x41, 0xc7, 0x23, 0xcb, 0xdd, 0xea, 0x78, 0x26, 0xc4, 0xae, 0x01, 0x33, + 0x8a, 0x2a, 0xf7, 0x20, 0xf6, 0x8d, 0x9a, 0x1a, 0x34, 0x70, 0xc2, 0x57, 0x52, 0x31, 0xb0, 0x74, + 0x2c, 0xc5, 0xba, 0xd5, 0xd6, 0xe1, 0xd6, 0x90, 0x4c, 0xb3, 0x23, 0x74, 0x20, 0x94, 0x43, 0xa6, + 0xca, 0x65, 0x01, 0x59, 0x78, 0xa1, 0x80, 0x2c, 0x96, 0x05, 0xc4, 0x74, 0x09, 0x96, 0x2c, 0x97, + 0x00, 0xfd, 0xaf, 0x49, 0x10, 0x91, 0x5f, 0x31, 0x98, 0x60, 0xeb, 0xd2, 0xff, 0xb2, 0x40, 0xb6, + 0x05, 0xab, 0xd2, 0xaf, 0x2b, 0xfc, 0x0e, 0xa0, 0x39, 0xae, 0xe0, 0xee, 0x67, 0x0e, 0xac, 0xe2, + 0x3c, 0x5b, 0xb2, 0xf8, 0x2e, 0x90, 0x2a, 0xbc, 0xa4, 0x28, 0x5a, 0xb4, 0x3f, 0xbb, 0x24, 0xbe, + 0x03, 0x2d, 0x62, 0x18, 0x27, 0x3c, 0x92, 0x82, 0xd8, 0xb3, 0x05, 0xb1, 0xb0, 0x42, 0xbb, 0x67, + 0xbc, 0x82, 0xd8, 0x10, 0xc3, 0x7f, 0x70, 0xa0, 0x2d, 0xbb, 0xf9, 0x53, 0xc7, 0x12, 0x7d, 0x58, + 0x42, 0x89, 0x34, 0x1c, 0x76, 0x5d, 0xc6, 0xdd, 0x64, 0x82, 0x01, 0x1b, 0x6e, 0x9f, 0x56, 0x1c, + 0x51, 0x86, 0x71, 0x2f, 0x24, 0x83, 0x9b, 0x0d, 0xf2, 0x20, 0x1c, 0xa8, 0x5a, 0x99, 0x80, 0xac, + 0xab, 0x42, 0xbb, 0x93, 0xe5, 0xfe, 0x98, 0xcb, 0x6d, 0x4e, 0x14, 0x30, 0x60, 0x92, 0x03, 0x2a, + 0xb9, 0x83, 0xee, 0x0f, 0x01, 0xce, 0x55, 0xaa, 0x74, 0xba, 0x5b, 0x3a, 0xc8, 0x61, 0x30, 0x39, + 0x88, 0xb5, 0xaf, 0xed, 0x98, 0xbe, 0xb3, 0x55, 0xc5, 0xc6, 0x70, 0x56, 0xed, 0xe7, 0x38, 0xa7, + 0xc5, 0xee, 0xdd, 0x20, 0x47, 0xe4, 0x2d, 0x5b, 0x06, 0xca, 0x0d, 0x2a, 0xdc, 0xd4, 0xdc, 0x7a, + 0x7e, 0xec, 0x08, 0x7a, 0xda, 0x71, 0x90, 0x26, 0xde, 0x70, 0x2e, 0xb0, 0xad, 0x37, 0x5f, 0xd0, + 0x16, 0xd9, 0xa3, 0x91, 0x6a, 0xe6, 0x54, 0x6e, 0x6c, 0x06, 0x97, 0x54, 0x1d, 0xd9, 0xf0, 0x6a, + 0x7b, 0xcd, 0x97, 0x1a, 0xdb, 0x3d, 0xfc, 0xd8, 0x6e, 0xf4, 0x05, 0x8c, 0xfb, 0x3f, 0x74, 0xa0, + 0x6b, 0xb3, 0x43, 0xd1, 0x91, 0x4a, 0xa8, 0x8c, 0x91, 0x72, 0xc8, 0x4a, 0x70, 0x35, 0x6c, 0x6c, + 0xd4, 0x85, 0x8d, 0x66, 0x70, 0x38, 0xf7, 0xa2, 0xe0, 0xb0, 0xf9, 0x72, 0xc1, 0xe1, 0x7c, 0x5d, + 0x70, 0xd8, 0xff, 0x2f, 0x07, 0x58, 0x75, 0x7d, 0xd9, 0x7d, 0x11, 0xb7, 0x46, 0x3c, 0x94, 0x76, + 0xe2, 0x97, 0x5e, 0x4e, 0x46, 0xd4, 0x1c, 0xaa, 0xaf, 0x51, 0x58, 0x4d, 0x43, 0x60, 0xba, 0x2d, + 0xcb, 0x5e, 0x5d, 0x55, 0x29, 0x5c, 0x6d, 0xbe, 0x38, 0x5c, 0x9d, 0x7f, 0x71, 0xb8, 0xba, 0x50, + 0x0e, 0x57, 0xfb, 0xbf, 0x03, 0xcb, 0xd6, 0xaa, 0xff, 0xdf, 0x8d, 0xb8, 0xec, 0xf2, 0x88, 0x05, + 0xb6, 0xb0, 0xfe, 0x8f, 0x1b, 0xc0, 0xaa, 0x92, 0xf7, 0x73, 0xed, 0x03, 0xc9, 0x91, 0x65, 0x40, + 0xe6, 0xa4, 0x1c, 0x59, 0xa6, 0xe3, 0xff, 0xd3, 0x28, 0xbe, 0x09, 0x6b, 0x29, 0x1f, 0xc6, 0xc7, + 0x74, 0x08, 0x67, 0xa7, 0x3a, 0xaa, 0x15, 0xe8, 0xf4, 0xd9, 0x41, 0xfa, 0x92, 0x75, 0x66, 0x62, + 0xec, 0x0c, 0xa5, 0x58, 0xdd, 0xdd, 0x84, 0x0d, 0x71, 0x94, 0x75, 0x4b, 0xb0, 0x52, 0x46, 0xf6, + 0x2f, 0x1c, 0x38, 0x5b, 0xaa, 0x28, 0x0e, 0x16, 0x84, 0x1d, 0xb5, 0x8d, 0xab, 0x0d, 0x62, 0xff, + 0xa5, 0x00, 0x1b, 0xfd, 0x17, 0xfb, 0x4d, 0xb5, 0x02, 0xe7, 0x67, 0x1a, 0x55, 0xe9, 0xc5, 0xac, + 0xd7, 0x55, 0xb9, 0xe7, 0xe0, 0xac, 0x5c, 0xd9, 0x52, 0xc7, 0x0f, 0x61, 0xb3, 0x5c, 0x51, 0x64, + 0x4a, 0xed, 0x2e, 0xab, 0x22, 0xba, 0x44, 0x96, 0xcd, 0xb6, 0xfb, 0x5b, 0x5b, 0xe7, 0xfe, 0x36, + 0xb0, 0xaf, 0x4f, 0x79, 0x3a, 0xa3, 0x63, 0x0f, 0x9d, 0xaa, 0x38, 0x57, 0x8e, 0xe9, 0x17, 0x92, + 0xe9, 0xc1, 0x57, 0xf9, 0x4c, 0x9d, 0x2b, 0x35, 0x8a, 0x73, 0xa5, 0x57, 0x00, 0x30, 0x14, 0xa1, + 0x73, 0x12, 0x75, 0xd2, 0x87, 0x31, 0xa0, 0x60, 0xe8, 0xde, 0x80, 0x75, 0x8b, 0xbf, 0x9e, 0xfd, + 0x05, 0xf9, 0x85, 0x08, 0x94, 0xed, 0xd3, 0x17, 0x59, 0xe7, 0xfe, 0x87, 0x03, 0x73, 0xbb, 0x71, + 0x62, 0xa6, 0xd8, 0x1c, 0x3b, 0xc5, 0x26, 0x6d, 0xed, 0x40, 0x9b, 0xd2, 0x86, 0xb4, 0x14, 0x26, + 0xc8, 0xb6, 0xa0, 0xeb, 0x4f, 0x72, 0x0c, 0x15, 0x0f, 0xe3, 0xf4, 0xc4, 0x4f, 0x47, 0x62, 0x49, + 0x6e, 0x35, 0x7a, 0x8e, 0x57, 0xaa, 0x61, 0x1b, 0x30, 0xa7, 0x8d, 0x12, 0x11, 0x60, 0x11, 0x9d, + 0x0d, 0xca, 0x34, 0xce, 0x64, 0x94, 0x2b, 0x4b, 0xb8, 0xe2, 0xf6, 0xf7, 0xc2, 0xbd, 0x13, 0x12, + 0x5e, 0x57, 0x85, 0x76, 0x1f, 0x6d, 0x14, 0x91, 0xc9, 0xf4, 0x84, 0x2a, 0xbb, 0xff, 0xe6, 0xc0, + 0x3c, 0xcd, 0x00, 0xea, 0xa4, 0x10, 0x44, 0x3a, 0xc8, 0xa4, 0xb4, 0xa8, 0x23, 0x74, 0xb2, 0x04, + 0x33, 0xd7, 0x3a, 0xde, 0x6c, 0xe8, 0x6e, 0x9b, 0x47, 0x9c, 0x97, 0xa1, 0x25, 0x4a, 0xfa, 0x4c, + 0x90, 0x48, 0x0a, 0x90, 0x5d, 0x82, 0xe6, 0x51, 0x9c, 0xa8, 0x1d, 0x15, 0x54, 0x56, 0x2c, 0x4e, + 0x3c, 0xc2, 0x8b, 0xfe, 0x20, 0x3f, 0xd1, 0x79, 0x61, 0x93, 0xcb, 0x30, 0xee, 0x4a, 0x9a, 0xad, + 0x39, 0x19, 0x25, 0xd4, 0xdd, 0x82, 0x95, 0x87, 0xf1, 0x88, 0x1b, 0x79, 0x90, 0x53, 0xa5, 0xce, + 0xfd, 0x5d, 0x07, 0x96, 0x14, 0x31, 0xbb, 0x0a, 0x4d, 0xdc, 0x6a, 0x4b, 0xce, 0xad, 0xce, 0x86, + 0x23, 0x9d, 0x47, 0x14, 0x68, 0x22, 0x29, 0x4a, 0x2e, 0x5c, 0x21, 0x15, 0x23, 0x17, 0x4e, 0x86, + 0xee, 0x6e, 0x69, 0x33, 0x2e, 0xa1, 0xee, 0x5f, 0x3b, 0xb0, 0x6c, 0xb5, 0x81, 0x21, 0x4d, 0xe8, + 0x67, 0xb9, 0xcc, 0x30, 0xca, 0xe5, 0x31, 0x21, 0x33, 0x33, 0xd6, 0xb0, 0x33, 0x63, 0x3a, 0x67, + 0x33, 0x67, 0xe6, 0x6c, 0xae, 0x43, 0xab, 0x38, 0x84, 0x6e, 0x5a, 0xa6, 0x0f, 0x5b, 0x54, 0x79, + 0xfe, 0x82, 0x08, 0xf9, 0x0c, 0xe3, 0x30, 0x4e, 0xe5, 0x19, 0xad, 0x28, 0xb8, 0x37, 0xa0, 0x6d, + 0xd0, 0x63, 0x37, 0x22, 0x9e, 0x9f, 0xc4, 0xe9, 0x13, 0x95, 0xa0, 0x93, 0x45, 0x7d, 0x9c, 0xd5, + 0x28, 0x8e, 0xb3, 0xdc, 0xbf, 0x71, 0x60, 0x19, 0x65, 0x30, 0x88, 0xc6, 0x7b, 0x71, 0x18, 0x0c, + 0x67, 0xb4, 0xf6, 0x4a, 0xdc, 0xe4, 0xe1, 0xad, 0x92, 0x45, 0x1b, 0x46, 0xd9, 0x56, 0x11, 0x8d, + 0x54, 0x44, 0x5d, 0x46, 0x4d, 0x45, 0x39, 0x3f, 0xf0, 0x33, 0x29, 0xfc, 0x72, 0x2f, 0xb2, 0x40, + 0xd4, 0x27, 0x04, 0x52, 0x3f, 0xe7, 0x83, 0x49, 0x10, 0x86, 0x81, 0xa0, 0x15, 0x2e, 0x42, 0x5d, + 0x95, 0xfb, 0x83, 0x06, 0xb4, 0xa5, 0xa5, 0xbc, 0x3b, 0x1a, 0x8b, 0x54, 0xb8, 0x74, 0xb4, 0xb4, + 0xb9, 0x30, 0x10, 0x55, 0x6f, 0xb9, 0x66, 0x06, 0x52, 0x5e, 0xd6, 0xb9, 0xea, 0xb2, 0x5e, 0x84, + 0x16, 0x8a, 0xd7, 0x5b, 0xe4, 0x03, 0x8a, 0x3b, 0x0b, 0x05, 0xa0, 0x6a, 0x77, 0xa8, 0x76, 0xbe, + 0xa8, 0x25, 0xc0, 0xf2, 0xfa, 0x16, 0x4a, 0x5e, 0xdf, 0x3b, 0xd0, 0x91, 0x6c, 0x68, 0xde, 0xc9, + 0x3a, 0x14, 0x02, 0x6e, 0xad, 0x89, 0x67, 0x51, 0xaa, 0x2f, 0x77, 0xd4, 0x97, 0x4b, 0x2f, 0xfa, + 0x52, 0x51, 0xd2, 0xc9, 0x90, 0x98, 0x9b, 0xfb, 0xa9, 0x9f, 0x1c, 0xa9, 0xdd, 0x67, 0xa4, 0x8f, + 0xbb, 0x09, 0x66, 0x5b, 0x30, 0x8f, 0x9f, 0x29, 0x6b, 0x5d, 0xaf, 0x74, 0x82, 0x84, 0x5d, 0x85, + 0x79, 0x3e, 0x1a, 0x73, 0x15, 0x79, 0x30, 0x3b, 0x06, 0xc4, 0x35, 0xf2, 0x04, 0x01, 0x9a, 0x00, + 0x44, 0x4b, 0x26, 0xc0, 0xb6, 0xf4, 0x0b, 0x58, 0x7c, 0x7f, 0xe4, 0x6e, 0x00, 0x7b, 0x28, 0xa4, + 0xd6, 0xcc, 0x9c, 0xfe, 0xc1, 0x1c, 0xb4, 0x0d, 0x18, 0xb5, 0x79, 0x8c, 0x1d, 0x1e, 0x8c, 0x02, + 0x7f, 0xc2, 0x73, 0x9e, 0x4a, 0x49, 0x2d, 0xa1, 0x48, 0xe7, 0x1f, 0x8f, 0x07, 0xf1, 0x34, 0x1f, + 0x8c, 0xf8, 0x38, 0xe5, 0x62, 0x8f, 0xc4, 0xcd, 0xc0, 0x42, 0x91, 0x6e, 0xe2, 0x3f, 0x35, 0xe9, + 0x84, 0x3c, 0x94, 0x50, 0x95, 0x07, 0x15, 0x73, 0xd4, 0x2c, 0xf2, 0xa0, 0x62, 0x46, 0xca, 0x76, + 0x68, 0xbe, 0xc6, 0x0e, 0xbd, 0x0d, 0x9b, 0xc2, 0xe2, 0x48, 0xdd, 0x1c, 0x94, 0xc4, 0xe4, 0x94, + 0x5a, 0xb6, 0x05, 0xab, 0xd8, 0x67, 0x25, 0xe0, 0x59, 0xf0, 0x89, 0xc8, 0x4c, 0x38, 0x5e, 0x05, + 0x47, 0x5a, 0x54, 0x47, 0x8b, 0x56, 0x9c, 0x15, 0x55, 0x70, 0xa2, 0xf5, 0x9f, 0xda, 0xb4, 0x2d, + 0x49, 0x5b, 0xc2, 0xdd, 0x65, 0x68, 0xef, 0xe7, 0x71, 0xa2, 0x16, 0xa5, 0x0b, 0x1d, 0x51, 0x94, + 0x27, 0x83, 0x17, 0xe0, 0x3c, 0x49, 0xd1, 0xa3, 0x38, 0x89, 0xc3, 0x78, 0x3c, 0xdb, 0x9f, 0x1e, + 0x64, 0xc3, 0x34, 0x48, 0x30, 0x22, 0x70, 0xff, 0xde, 0x81, 0x75, 0xab, 0x56, 0xa6, 0x32, 0xbe, + 0x20, 0x44, 0x5a, 0x1f, 0xe9, 0x08, 0xc1, 0x5b, 0x33, 0xcc, 0xa1, 0x20, 0x14, 0x49, 0xa4, 0xc7, + 0xf2, 0x94, 0xe7, 0x26, 0xac, 0xa8, 0x9e, 0xa9, 0x0f, 0x85, 0x14, 0xf6, 0xaa, 0x52, 0x28, 0xbf, + 0xef, 0xca, 0x0f, 0x14, 0x8b, 0x5f, 0x15, 0x7e, 0x35, 0x1f, 0xd1, 0x18, 0x55, 0x4c, 0xdb, 0x57, + 0xdf, 0x9b, 0xce, 0xbc, 0xea, 0xc1, 0x50, 0x83, 0x99, 0xfb, 0x47, 0x0e, 0x40, 0xd1, 0x3b, 0x14, + 0x8c, 0xc2, 0xa4, 0x8b, 0xcb, 0x6a, 0x86, 0xf9, 0x7e, 0x0d, 0x3a, 0x3a, 0x9b, 0x5f, 0xec, 0x12, + 0x6d, 0x85, 0xa1, 0xc3, 0x75, 0x05, 0x56, 0xc6, 0x61, 0x7c, 0x40, 0x5b, 0x2c, 0x1d, 0x35, 0x67, + 0xf2, 0x7c, 0xb4, 0x2b, 0xe0, 0x7b, 0x12, 0x2d, 0xb6, 0x94, 0xa6, 0xb1, 0xa5, 0xb8, 0xdf, 0x69, + 0xe8, 0x1c, 0x70, 0x31, 0xe6, 0x53, 0xb5, 0x8c, 0xed, 0x54, 0x8c, 0xe3, 0x29, 0x29, 0x57, 0xca, + 0xde, 0xec, 0xbd, 0x30, 0x90, 0xbd, 0x01, 0xdd, 0x54, 0x58, 0x1f, 0x65, 0x9a, 0x9a, 0xcf, 0x31, + 0x4d, 0xcb, 0xa9, 0xb5, 0xef, 0xfc, 0x02, 0xac, 0xfa, 0xa3, 0x63, 0x9e, 0xe6, 0x01, 0x45, 0x34, + 0xb4, 0xe9, 0x0b, 0x83, 0xba, 0x62, 0xe0, 0xb4, 0x17, 0x5f, 0x81, 0x15, 0x79, 0x26, 0xad, 0x29, + 0xe5, 0x4d, 0xa4, 0x02, 0x46, 0x42, 0xf7, 0xfb, 0x2a, 0xdd, 0x6c, 0xaf, 0xe1, 0xe9, 0x33, 0x62, + 0x8e, 0xae, 0x51, 0x1a, 0xdd, 0xe7, 0x64, 0xea, 0x77, 0xa4, 0xc2, 0x26, 0x99, 0x84, 0x17, 0xa0, + 0x4c, 0xd5, 0xdb, 0x53, 0xda, 0x7c, 0x99, 0x29, 0x75, 0x3f, 0x73, 0x60, 0x71, 0x37, 0x4e, 0x76, + 0xe5, 0xf1, 0x32, 0x29, 0x82, 0xbe, 0xf1, 0xa1, 0x8a, 0xa6, 0x57, 0xdc, 0xa8, 0x78, 0xc5, 0xd5, + 0xbd, 0x76, 0xb9, 0xbc, 0xd7, 0xfe, 0x1a, 0x5c, 0xa0, 0x68, 0x39, 0x8d, 0x93, 0x38, 0x45, 0x65, + 0xf4, 0x43, 0xb1, 0xb1, 0xc6, 0x51, 0x7e, 0xa4, 0xcc, 0xd8, 0xf3, 0x48, 0x28, 0x3a, 0x0a, 0xf3, + 0xe3, 0x81, 0x70, 0x86, 0xa5, 0x6f, 0x20, 0xac, 0x5b, 0xb5, 0xc2, 0xfd, 0x12, 0xb4, 0xc8, 0xb9, + 0xa5, 0x61, 0xbd, 0x09, 0xad, 0xa3, 0x38, 0x19, 0x1c, 0x05, 0x51, 0xae, 0x94, 0xbb, 0x5b, 0x78, + 0x9d, 0xbb, 0x34, 0x21, 0x9a, 0xc0, 0xfd, 0xf1, 0x1c, 0x2c, 0xbe, 0x1f, 0x1d, 0xc7, 0xc1, 0x90, + 0x32, 0xd3, 0x13, 0x3e, 0x89, 0xd5, 0xfd, 0x17, 0xfc, 0x8d, 0x53, 0x41, 0x67, 0xc1, 0x49, 0x2e, + 0x53, 0xcb, 0xaa, 0x88, 0xdb, 0x7d, 0x5a, 0xdc, 0x09, 0x13, 0xaa, 0x63, 0x20, 0xe8, 0xd8, 0xa7, + 0xe6, 0x85, 0x38, 0x59, 0x2a, 0x2e, 0x10, 0xcd, 0x1b, 0x17, 0x88, 0xe8, 0x1c, 0x43, 0x1c, 0x73, + 0x93, 0x7c, 0x2d, 0x79, 0xaa, 0x48, 0x81, 0x48, 0xca, 0x45, 0x96, 0x83, 0x1c, 0x87, 0x45, 0x19, + 0x88, 0x98, 0x20, 0x3a, 0x17, 0xe2, 0x03, 0x41, 0x23, 0x8c, 0xaf, 0x09, 0xa1, 0xb3, 0x55, 0xbe, + 0x53, 0xd7, 0x12, 0x32, 0x5f, 0x82, 0xd1, 0x42, 0x8f, 0xb8, 0x36, 0xa4, 0x62, 0x0c, 0x20, 0xee, + 0xbc, 0x95, 0x71, 0x23, 0x7c, 0x11, 0xc7, 0xf5, 0x2a, 0x7c, 0x41, 0x41, 0xf1, 0xc3, 0xf0, 0xc0, + 0x1f, 0x3e, 0xa1, 0x9b, 0x8e, 0x74, 0x3a, 0xdf, 0xf2, 0x6c, 0x10, 0x7b, 0x6d, 0xac, 0x26, 0x9d, + 0x84, 0x35, 0x3d, 0x13, 0x62, 0x3b, 0xd0, 0xa6, 0x90, 0x4d, 0xae, 0x67, 0x97, 0xd6, 0x73, 0xd5, + 0x8c, 0xe9, 0x68, 0x45, 0x4d, 0x22, 0x33, 0x5b, 0xbe, 0x62, 0x1f, 0xa0, 0x7f, 0x03, 0xd8, 0xcd, + 0xd1, 0x48, 0xae, 0xb7, 0x0e, 0x19, 0x8b, 0x95, 0x72, 0xac, 0x95, 0xaa, 0x99, 0xb1, 0x46, 0xed, + 0x8c, 0xb9, 0x77, 0xa1, 0xbd, 0x67, 0x5c, 0x77, 0x24, 0xd1, 0x50, 0x17, 0x1d, 0xa5, 0x38, 0x19, + 0x88, 0xd1, 0x60, 0xc3, 0x6c, 0xd0, 0xfd, 0x65, 0x60, 0x0f, 0x82, 0x2c, 0xd7, 0xfd, 0x13, 0xcb, + 0xf1, 0x1a, 0x74, 0x74, 0x80, 0x5d, 0x1c, 0xef, 0xb7, 0x25, 0x46, 0xc7, 0xee, 0x37, 0xc5, 0xbd, + 0x80, 0xf2, 0xc0, 0xb6, 0x60, 0x29, 0x10, 0x50, 0x59, 0x13, 0x14, 0xa5, 0xae, 0x47, 0x7f, 0x4d, + 0x82, 0xd6, 0x2e, 0xfa, 0x03, 0x07, 0x16, 0xe5, 0xd0, 0xd0, 0xdb, 0xb0, 0x2e, 0x7a, 0x8a, 0x81, + 0x59, 0x58, 0xfd, 0xf5, 0xb8, 0xaa, 0x0c, 0xcf, 0xd5, 0xc9, 0x30, 0x83, 0x66, 0xe2, 0xe7, 0x47, + 0x14, 0xa0, 0xb4, 0x3c, 0xfa, 0xcd, 0x56, 0x45, 0xd0, 0x2c, 0x74, 0x85, 0x02, 0xe6, 0xba, 0x1b, + 0x99, 0xc2, 0x24, 0x57, 0x70, 0x1c, 0x14, 0x9d, 0xa4, 0x0b, 0x5c, 0x27, 0xc8, 0xe5, 0x2d, 0x85, + 0x02, 0x2e, 0xe6, 0x4b, 0xb2, 0x28, 0xcf, 0x97, 0x24, 0xf5, 0x74, 0xbd, 0xdb, 0x87, 0xde, 0x1d, + 0x1e, 0xf2, 0x9c, 0xdf, 0x0c, 0xc3, 0x32, 0xff, 0x0b, 0x70, 0xbe, 0xa6, 0x4e, 0x3a, 0x2d, 0xf7, + 0x60, 0xed, 0x0e, 0x3f, 0x98, 0x8e, 0x1f, 0xf0, 0xe3, 0xe2, 0x14, 0x8b, 0x41, 0x33, 0x3b, 0x8a, + 0x4f, 0xe4, 0xda, 0xd2, 0x6f, 0xf6, 0x0a, 0x40, 0x88, 0x34, 0x83, 0x2c, 0xe1, 0x43, 0x75, 0x31, + 0x8c, 0x90, 0xfd, 0x84, 0x0f, 0xdd, 0xb7, 0x81, 0x99, 0x7c, 0xe4, 0x10, 0xd0, 0x0e, 0x4c, 0x0f, + 0x06, 0xd9, 0x2c, 0xcb, 0xf9, 0x44, 0xdd, 0x78, 0x33, 0x21, 0xf7, 0x0a, 0x74, 0xf6, 0xfc, 0x99, + 0xc7, 0x3f, 0x96, 0x77, 0x6d, 0x31, 0x36, 0xf6, 0x67, 0x28, 0xca, 0x3a, 0x36, 0xa6, 0x6a, 0xf7, + 0x3f, 0x1b, 0xb0, 0x20, 0x28, 0x91, 0xeb, 0x88, 0x67, 0x79, 0x10, 0x89, 0x13, 0x1c, 0xc9, 0xd5, + 0x80, 0x2a, 0xb2, 0xd1, 0xa8, 0x91, 0x0d, 0xe9, 0xad, 0xaa, 0x4b, 0x36, 0x52, 0x08, 0x2c, 0x0c, + 0xdd, 0x9a, 0xe2, 0x64, 0x5c, 0x04, 0x67, 0x05, 0x50, 0x4a, 0x96, 0x14, 0xd6, 0x46, 0xf4, 0x4f, + 0x09, 0xad, 0x14, 0x07, 0x13, 0xaa, 0xb5, 0x69, 0x8b, 0x42, 0x6a, 0x2a, 0x36, 0xad, 0x62, 0xbb, + 0x96, 0x5e, 0xc2, 0x76, 0x09, 0x17, 0xf6, 0x79, 0xb6, 0x0b, 0x5e, 0xc2, 0x76, 0xb9, 0x0c, 0x56, + 0xef, 0x71, 0xee, 0x71, 0xdc, 0x15, 0x95, 0x38, 0x7d, 0xd7, 0x81, 0x55, 0xb9, 0xa1, 0xeb, 0x3a, + 0xf6, 0x9a, 0xb5, 0xfb, 0x3b, 0x75, 0x07, 0x01, 0xaf, 0xc3, 0x32, 0xed, 0xc9, 0x3a, 0x2b, 0x24, + 0x53, 0x58, 0x16, 0x88, 0xe3, 0x50, 0xa9, 0xed, 0x49, 0x10, 0xca, 0x45, 0x31, 0x21, 0x95, 0x58, + 0xc2, 0xf8, 0x98, 0x96, 0xc4, 0xf1, 0x74, 0xd9, 0xfd, 0x3b, 0x07, 0xd6, 0x8c, 0x0e, 0x4b, 0x29, + 0xbc, 0x01, 0xea, 0xe4, 0x5c, 0x24, 0x8f, 0x84, 0x32, 0x9d, 0xb3, 0x9d, 0x93, 0xe2, 0x33, 0x8b, + 0x98, 0x16, 0xd3, 0x9f, 0x51, 0x07, 0xb3, 0xe9, 0x44, 0x7a, 0x20, 0x26, 0x84, 0x82, 0x74, 0xc2, + 0xf9, 0x13, 0x4d, 0x32, 0x47, 0x24, 0x16, 0x46, 0x07, 0xa3, 0xe8, 0x4b, 0x68, 0x22, 0x71, 0x17, + 0xc8, 0x06, 0xdd, 0x7f, 0x74, 0x60, 0x5d, 0x38, 0x85, 0xd2, 0xe5, 0xd6, 0xf7, 0x14, 0x17, 0x84, + 0x17, 0x2c, 0x34, 0x72, 0xf7, 0x8c, 0x27, 0xcb, 0xec, 0x8b, 0x2f, 0xe9, 0xc8, 0xea, 0x03, 0xf1, + 0x53, 0xd6, 0x62, 0xae, 0x6e, 0x2d, 0x9e, 0x33, 0xd3, 0x75, 0xc9, 0x92, 0xf9, 0xda, 0x64, 0xc9, + 0xad, 0x45, 0x98, 0xcf, 0x86, 0x71, 0xc2, 0xdd, 0x4d, 0xd8, 0xb0, 0x07, 0x27, 0x4d, 0xd0, 0xf7, + 0x1c, 0xe8, 0xdd, 0x13, 0xa9, 0xc3, 0x20, 0x1a, 0xef, 0x06, 0x59, 0x1e, 0xa7, 0xfa, 0x62, 0xf6, + 0x25, 0x80, 0x2c, 0xf7, 0xd3, 0x5c, 0x5c, 0x58, 0x92, 0x69, 0x8e, 0x02, 0xc1, 0x3e, 0xf2, 0x68, + 0x24, 0x6a, 0xc5, 0xda, 0xe8, 0x32, 0x2e, 0x0c, 0x1d, 0xd6, 0x0f, 0xe2, 0xc3, 0xc3, 0x8c, 0x6b, + 0xb7, 0xd5, 0xc4, 0x30, 0xf2, 0x45, 0x8d, 0xc7, 0x58, 0x8f, 0x1f, 0x93, 0xa9, 0x15, 0xfe, 0x60, + 0x09, 0x75, 0xff, 0xd6, 0x81, 0x95, 0xa2, 0x93, 0x77, 0x11, 0xb4, 0xad, 0x83, 0xe8, 0x9a, 0x61, + 0x1d, 0x54, 0x02, 0x26, 0x18, 0x0d, 0x82, 0x48, 0xf6, 0xcd, 0x40, 0x48, 0x63, 0x65, 0x29, 0x9e, + 0xaa, 0xcb, 0x61, 0x26, 0x24, 0x4e, 0x7e, 0x73, 0xfc, 0x5a, 0xdc, 0x0c, 0x93, 0x25, 0xba, 0x6f, + 0x36, 0xc9, 0xe9, 0xab, 0x05, 0xe1, 0x10, 0xcb, 0xa2, 0xda, 0x9f, 0x16, 0x09, 0xc5, 0x9f, 0xee, + 0x1f, 0x3b, 0x70, 0xbe, 0x66, 0x72, 0xa5, 0x66, 0xdc, 0x81, 0xb5, 0x43, 0x5d, 0xa9, 0x26, 0x40, + 0xa8, 0xc7, 0xa6, 0x94, 0xa2, 0xd2, 0xa0, 0xbd, 0xea, 0x07, 0xe8, 0x1e, 0x53, 0xde, 0x48, 0x4c, + 0xa9, 0x75, 0x69, 0xa2, 0x5a, 0xb1, 0xf3, 0xfd, 0x06, 0x74, 0xc5, 0x51, 0x85, 0x78, 0x9a, 0xc3, + 0x53, 0xf6, 0x01, 0x2c, 0xca, 0x87, 0x50, 0xec, 0xac, 0x6c, 0xd6, 0x7e, 0x7a, 0xd5, 0xdf, 0x2c, + 0xc3, 0x52, 0x76, 0xd6, 0x7f, 0xff, 0xb3, 0x7f, 0xf9, 0x93, 0xc6, 0x32, 0x6b, 0x6f, 0x1f, 0xbf, + 0xb5, 0x3d, 0xe6, 0x51, 0x86, 0x3c, 0x7e, 0x13, 0xa0, 0x78, 0x4b, 0xc4, 0x7a, 0xda, 0xc9, 0x28, + 0xbd, 0x7d, 0xea, 0x9f, 0xaf, 0xa9, 0x91, 0x7c, 0xcf, 0x13, 0xdf, 0x75, 0xb7, 0x8b, 0x7c, 0x83, + 0x28, 0xc8, 0xc5, 0xc3, 0xa2, 0x77, 0x9d, 0x2d, 0x36, 0x82, 0x8e, 0xf9, 0xa6, 0x88, 0xa9, 0x90, + 0xb9, 0xe6, 0xa1, 0x52, 0xff, 0x42, 0x6d, 0x9d, 0xca, 0x17, 0x50, 0x1b, 0x67, 0xdd, 0x55, 0x6c, + 0x63, 0x4a, 0x14, 0xba, 0x95, 0x9d, 0x7f, 0xba, 0x00, 0x2d, 0x9d, 0x76, 0x62, 0xdf, 0x86, 0x65, + 0xeb, 0x74, 0x87, 0x29, 0xc6, 0x75, 0x87, 0x41, 0xfd, 0x8b, 0xf5, 0x95, 0xb2, 0xd9, 0x4b, 0xd4, + 0x6c, 0x8f, 0x6d, 0x62, 0xb3, 0xf2, 0x78, 0x64, 0x9b, 0xce, 0xb4, 0xc4, 0xfd, 0xb2, 0x27, 0xd0, + 0xb5, 0x4f, 0x64, 0xd8, 0x45, 0xdb, 0xa0, 0x94, 0x5a, 0x7b, 0xe5, 0x94, 0x5a, 0xd9, 0xdc, 0x45, + 0x6a, 0x6e, 0x93, 0x6d, 0x98, 0xcd, 0xe9, 0x74, 0x10, 0xa7, 0x1b, 0x81, 0xe6, 0x63, 0x23, 0xf6, + 0x8a, 0x5e, 0xea, 0xba, 0x47, 0x48, 0x7a, 0xd1, 0xaa, 0x2f, 0x91, 0xdc, 0x1e, 0x35, 0xc5, 0x18, + 0x4d, 0xa8, 0xf9, 0xd6, 0x88, 0x7d, 0x04, 0x2d, 0xfd, 0xc0, 0x80, 0x9d, 0x33, 0x5e, 0x75, 0x98, + 0xaf, 0x1e, 0xfa, 0xbd, 0x6a, 0x45, 0xdd, 0x52, 0x99, 0x9c, 0x51, 0x20, 0x1e, 0xc0, 0x59, 0xe9, + 0xa4, 0x1e, 0xf0, 0x9f, 0x64, 0x24, 0x35, 0x4f, 0xa4, 0xae, 0x3b, 0xec, 0x06, 0x2c, 0xa9, 0x77, + 0x1b, 0x6c, 0xb3, 0xfe, 0xfd, 0x49, 0xff, 0x5c, 0x05, 0x97, 0xfa, 0x7c, 0x13, 0xa0, 0x78, 0x73, + 0xa0, 0x25, 0xbf, 0xf2, 0x12, 0x42, 0x4f, 0x62, 0xcd, 0x03, 0x85, 0x31, 0xbd, 0xb0, 0xb0, 0x9f, + 0x34, 0xb0, 0x57, 0x0b, 0xfa, 0xda, 0xc7, 0x0e, 0xcf, 0x61, 0xe8, 0x6e, 0xd2, 0xdc, 0xad, 0x32, + 0x52, 0xa5, 0x88, 0x9f, 0xa8, 0xbb, 0xb1, 0x77, 0xa0, 0x6d, 0xbc, 0x63, 0x60, 0x8a, 0x43, 0xf5, + 0x0d, 0x44, 0xbf, 0x5f, 0x57, 0x25, 0xbb, 0xfb, 0x15, 0x58, 0xb6, 0x1e, 0x24, 0x68, 0xcd, 0xa8, + 0x7b, 0xee, 0xa0, 0x35, 0xa3, 0xfe, 0x0d, 0xc3, 0x37, 0xa1, 0x6d, 0x3c, 0x1f, 0x60, 0xc6, 0x9d, + 0xa0, 0xd2, 0xc3, 0x01, 0xdd, 0xa3, 0xba, 0xd7, 0x06, 0x1b, 0x34, 0xde, 0xae, 0xdb, 0xc2, 0xf1, + 0xd2, 0x05, 0x51, 0x14, 0x92, 0x6f, 0x43, 0xd7, 0x7e, 0x50, 0xa0, 0xb5, 0xaa, 0xf6, 0x69, 0x82, + 0xd6, 0xaa, 0x53, 0x5e, 0x21, 0x48, 0x81, 0xdc, 0x5a, 0xd7, 0x8d, 0x6c, 0x7f, 0x2a, 0x0f, 0x5d, + 0x9e, 0xb1, 0xaf, 0xa3, 0xe9, 0x90, 0x37, 0x76, 0x59, 0xf1, 0x8c, 0xc2, 0xbe, 0xd7, 0xab, 0xa5, + 0xbd, 0x72, 0xb9, 0xd7, 0x5d, 0x23, 0xe6, 0x6d, 0x56, 0x8c, 0x40, 0x58, 0x68, 0xba, 0xb9, 0x6b, + 0x58, 0x68, 0xf3, 0x72, 0xaf, 0x61, 0xa1, 0xad, 0x0b, 0xbe, 0x65, 0x0b, 0x9d, 0x07, 0xc8, 0x23, + 0x82, 0x95, 0xd2, 0x3d, 0x00, 0xad, 0x2c, 0xf5, 0xb7, 0x88, 0xfa, 0x97, 0x9e, 0x7f, 0x7d, 0xc0, + 0x36, 0x33, 0xca, 0xbc, 0x6c, 0xab, 0x4b, 0x5f, 0xbf, 0x05, 0x1d, 0xf3, 0x22, 0xb8, 0xb6, 0xd9, + 0x35, 0xd7, 0xd7, 0xb5, 0xcd, 0xae, 0xbb, 0x39, 0xae, 0x16, 0x97, 0x75, 0xcc, 0x66, 0xd8, 0x37, + 0x61, 0xc5, 0xb8, 0x71, 0xb2, 0x3f, 0x8b, 0x86, 0x5a, 0x78, 0xaa, 0x77, 0x04, 0xfb, 0x75, 0xfe, + 0x99, 0x7b, 0x8e, 0x18, 0xaf, 0xb9, 0x16, 0x63, 0x14, 0x9c, 0xdb, 0xd0, 0x36, 0x6f, 0xb3, 0x3c, + 0x87, 0xef, 0x39, 0xa3, 0xca, 0xbc, 0x2e, 0x77, 0xdd, 0x61, 0x7f, 0xe6, 0x40, 0xc7, 0xbc, 0x7d, + 0xca, 0xac, 0x3c, 0x6f, 0x89, 0x4f, 0xcf, 0xac, 0x33, 0x19, 0xb9, 0x1e, 0x75, 0xf2, 0xc1, 0xd6, + 0x57, 0xac, 0x49, 0xfe, 0xd4, 0xf2, 0xf3, 0xaf, 0x95, 0xdf, 0xf8, 0x3d, 0x2b, 0x13, 0x98, 0xf7, + 0x28, 0x9f, 0x5d, 0x77, 0xd8, 0xbb, 0xe2, 0x1d, 0xa8, 0x8a, 0xeb, 0x99, 0x61, 0xdc, 0xca, 0x53, + 0x66, 0x3e, 0x99, 0xbc, 0xea, 0x5c, 0x77, 0xd8, 0xb7, 0xc4, 0x53, 0x3e, 0xf9, 0x2d, 0xcd, 0xfc, + 0xcb, 0x7e, 0xef, 0xbe, 0x4e, 0xa3, 0xb9, 0xe4, 0x9e, 0xb7, 0x46, 0x53, 0xb6, 0xee, 0x7b, 0x00, + 0x45, 0x92, 0x86, 0x95, 0x32, 0x16, 0xda, 0xee, 0x55, 0xf3, 0x38, 0xf6, 0x8a, 0xaa, 0xc4, 0x06, + 0x72, 0xfc, 0x48, 0x08, 0xa3, 0xa4, 0xcf, 0xf4, 0x92, 0x56, 0x93, 0x2d, 0xfd, 0x7e, 0x5d, 0x55, + 0x9d, 0x28, 0x2a, 0xfe, 0xec, 0x31, 0x2c, 0x3f, 0x88, 0xe3, 0x27, 0xd3, 0x44, 0xa7, 0x11, 0xed, + 0x9c, 0xc1, 0xae, 0x9f, 0x1d, 0xf5, 0x4b, 0xa3, 0x70, 0x2f, 0x13, 0xab, 0x3e, 0xeb, 0x19, 0xac, + 0xb6, 0x3f, 0x2d, 0x52, 0x44, 0xcf, 0x98, 0x0f, 0x6b, 0x7a, 0x8f, 0xd3, 0x1d, 0xef, 0xdb, 0x6c, + 0xcc, 0x4c, 0x4d, 0xa5, 0x09, 0xcb, 0xeb, 0x50, 0xbd, 0xdd, 0xce, 0x14, 0xcf, 0xeb, 0x0e, 0xdb, + 0x83, 0xce, 0x1d, 0x3e, 0x8c, 0x47, 0x5c, 0x46, 0xf9, 0xeb, 0x45, 0xc7, 0x75, 0x7a, 0xa0, 0xbf, + 0x6c, 0x81, 0xb6, 0xd6, 0x27, 0xfe, 0x2c, 0xe5, 0x1f, 0x6f, 0x7f, 0x2a, 0xf3, 0x07, 0xcf, 0x94, + 0xd6, 0xab, 0x9c, 0x87, 0xa5, 0xf5, 0xa5, 0x24, 0x89, 0xa5, 0xf5, 0x95, 0x24, 0x89, 0x35, 0xd5, + 0x2a, 0xe7, 0xc2, 0x42, 0x58, 0xab, 0xe4, 0x55, 0xf4, 0x4e, 0x79, 0x5a, 0x36, 0xa6, 0x7f, 0xf9, + 0x74, 0x02, 0xbb, 0xb5, 0x2d, 0xbb, 0xb5, 0x7d, 0x58, 0xbe, 0xc3, 0xc5, 0x64, 0x89, 0xb3, 0xca, + 0xbe, 0x6d, 0x46, 0xcc, 0x73, 0xcd, 0xb2, 0x89, 0xa1, 0x3a, 0xdb, 0xac, 0xd3, 0x41, 0x21, 0xfb, + 0x08, 0xda, 0xf7, 0x79, 0xae, 0x0e, 0x27, 0xb5, 0xbf, 0x51, 0x3a, 0xad, 0xec, 0xd7, 0x9c, 0x6d, + 0xda, 0x32, 0x43, 0xdc, 0xb6, 0xf9, 0x68, 0xcc, 0x85, 0xb2, 0x0f, 0x82, 0xd1, 0x33, 0xf6, 0xeb, + 0xc4, 0x5c, 0xdf, 0x67, 0xd8, 0x34, 0xce, 0xb4, 0x4c, 0xe6, 0x2b, 0x25, 0xbc, 0x8e, 0x73, 0x14, + 0x8f, 0xb8, 0xb1, 0xc1, 0x45, 0xd0, 0x36, 0x2e, 0xdb, 0x68, 0x05, 0xaa, 0x5e, 0xf0, 0xd1, 0x0a, + 0x54, 0x73, 0x37, 0xc7, 0xbd, 0x4a, 0xed, 0xb8, 0xec, 0x72, 0xd1, 0x8e, 0xb8, 0x8f, 0x53, 0xb4, + 0xb4, 0xfd, 0xa9, 0x3f, 0xc9, 0x9f, 0xb1, 0x0f, 0xe9, 0x29, 0x8b, 0x79, 0x00, 0x5b, 0xf8, 0x3b, + 0xe5, 0xb3, 0x5a, 0x3d, 0x59, 0x46, 0x95, 0xed, 0x03, 0x89, 0xa6, 0x68, 0x1f, 0xfc, 0x22, 0xc0, + 0x7e, 0x1e, 0x27, 0x77, 0x7c, 0x3e, 0x89, 0xa3, 0xc2, 0x72, 0x15, 0x87, 0x8c, 0x85, 0xe5, 0x32, + 0x4e, 0x1a, 0xd9, 0x87, 0x86, 0xc7, 0x69, 0x9d, 0x5f, 0x2b, 0xe1, 0x3a, 0xf5, 0x1c, 0x52, 0x4f, + 0x48, 0xcd, 0x59, 0xe4, 0x75, 0x07, 0xfd, 0xc7, 0x22, 0x8b, 0xa7, 0xfd, 0xc7, 0x4a, 0x82, 0x50, + 0x9b, 0xbd, 0x9a, 0x94, 0xdf, 0x1e, 0xb4, 0x8a, 0xb4, 0x90, 0xda, 0x92, 0xca, 0x49, 0x24, 0xbd, + 0xc7, 0x54, 0x92, 0x35, 0xee, 0x2a, 0x4d, 0x15, 0xb0, 0x25, 0x9c, 0x2a, 0xca, 0xc0, 0x04, 0xb0, + 0x2e, 0x3a, 0xa8, 0x37, 0x4c, 0x3a, 0x36, 0x53, 0x23, 0xa9, 0x49, 0x98, 0x68, 0x6d, 0xae, 0xcd, + 0x37, 0x58, 0xb1, 0x1d, 0x4a, 0xab, 0x38, 0xb2, 0x43, 0xd3, 0x3c, 0x81, 0xb5, 0x4a, 0xb0, 0xac, + 0x55, 0xfa, 0xb4, 0x1c, 0x85, 0x56, 0xe9, 0x53, 0xe3, 0x6c, 0xf7, 0x2c, 0x35, 0xb9, 0xe2, 0x02, + 0x36, 0x99, 0x9d, 0x04, 0xf9, 0xf0, 0xe8, 0x5d, 0x67, 0xeb, 0x60, 0x81, 0xfe, 0x69, 0xe4, 0xf3, + 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x0b, 0xc7, 0xfe, 0x7f, 0x9b, 0x44, 0x00, 0x00, } diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index 5113369a..8680b326 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -1458,6 +1458,9 @@ message Invoice { invoice's destination. */ repeated RouteHint route_hints = 14 [json_name = "route_hints"]; + + /// Whether this invoice should include routing hints for private channels. + bool private = 15 [json_name = "private"]; } message AddInvoiceResponse { bytes r_hash = 1 [json_name = "r_hash"]; diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index b598ad04..70bf8ab8 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -1632,6 +1632,11 @@ "$ref": "#/definitions/lnrpcRouteHint" }, "description": "*\nRoute hints that can each be individually used to assist in reaching the\ninvoice's destination." + }, + "private": { + "type": "boolean", + "format": "boolean", + "description": "/ Whether this invoice should include routing hints for private channels." } } }, From ff2be77c0085e30787989e02c1eae5ebc478fd48 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 28 Mar 2018 00:50:03 -0400 Subject: [PATCH 10/14] cmd/lncli: add `private` flag to addinvoice command --- cmd/lncli/commands.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 91fa0ccd..33c4884b 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -1713,6 +1713,12 @@ var addInvoiceCommand = cli.Command{ "specified an expiry of 3600 seconds (1 hour) " + "is implied.", }, + cli.BoolTFlag{ + Name: "private", + Usage: "encode routing hints in the invoice with " + + "private channels in order to assist the " + + "payer in reaching you", + }, }, Action: actionDecorator(addInvoice), } @@ -1771,6 +1777,7 @@ func addInvoice(ctx *cli.Context) error { DescriptionHash: descHash, FallbackAddr: ctx.String("fallback_addr"), Expiry: ctx.Int64("expiry"), + Private: ctx.Bool("private"), } resp, err := client.AddInvoice(context.Background(), invoice) From d1a717ba88e494e7b2cb0ac279a2f3ef62cb6c1a Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 28 Mar 2018 00:51:04 -0400 Subject: [PATCH 11/14] rpcserver: add ability to populate routing hints when creating an invoice --- rpcserver.go | 103 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 792f8607..b4d831d2 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "crypto/rand" "crypto/sha256" "encoding/hex" @@ -2202,13 +2203,107 @@ func (r *rpcServer) AddInvoice(ctx context.Context, options = append(options, zpay32.CLTVExpiry(uint64(defaultDelta))) } + // If we were requested to include routing hints in the invoice, then + // we'll fetch all of our available private channels and create routing + // hints for them. + if invoice.Private { + openChannels, err := r.server.chanDB.FetchAllChannels() + if err != nil { + return nil, fmt.Errorf("could not fetch all channels") + } + + graph := r.server.chanDB.ChannelGraph() + + numHints := 0 + for _, channel := range openChannels { + // We'll restrict the number of individual route hints + // to 20 to avoid creating overly large invoices. + if numHints > 20 { + break + } + + // Since we're only interested in our private channels, + // we'll skip public ones. + isPublic := channel.ChannelFlags&lnwire.FFAnnounceChannel != 0 + if isPublic { + continue + } + + // Make sure the counterparty has enough balance in the + // channel for our amount. We do this in order to reduce + // payment errors when attempting to use this channel + // as a hint. + chanPoint := lnwire.NewChanIDFromOutPoint( + &channel.FundingOutpoint, + ) + if amtMSat >= channel.LocalCommitment.RemoteBalance { + rpcsLog.Debugf("Skipping channel %v due to "+ + "not having enough remote balance", + chanPoint) + continue + } + + // Make sure the channel is active. + link, err := r.server.htlcSwitch.GetLink(chanPoint) + if err != nil { + rpcsLog.Errorf("Unable to get link for "+ + "channel %v: %v", chanPoint, err) + } + + if !link.EligibleToForward() { + rpcsLog.Debugf("Skipping link %v due to not "+ + "being eligible to forward payments", + chanPoint) + continue + } + + // Fetch the policies for each end of the channel. + chanID := channel.ShortChanID.ToUint64() + _, p1, p2, err := graph.FetchChannelEdgesByID(chanID) + if err != nil { + rpcsLog.Errorf("Unable to fetch the routing "+ + "policies for the edges of the channel "+ + "%v: %v", chanPoint, err) + continue + } + + // Now, we'll need to determine which is the correct + // policy for HTLCs being sent from the remote node. + var remotePolicy *channeldb.ChannelEdgePolicy + + remotePub := channel.IdentityPub.SerializeCompressed() + if bytes.Equal(remotePub, p1.Node.PubKeyBytes[:]) { + remotePolicy = p1 + } else { + remotePolicy = p2 + } + + // Finally, create the routing hint for this channel and + // add it to our list of route hints. + hint := routing.HopHint{ + NodeID: channel.IdentityPub, + ChannelID: chanID, + FeeBaseMSat: uint32(remotePolicy.FeeBaseMSat), + FeeProportionalMillionths: uint32( + remotePolicy.FeeProportionalMillionths, + ), + CLTVExpiryDelta: remotePolicy.TimeLockDelta, + } + + // Include the route hint in our set of options that + // will be used when creating the invoice. + routeHint := []routing.HopHint{hint} + options = append(options, zpay32.RouteHint(routeHint)) + + numHints++ + } + + } + // Create and encode the payment request as a bech32 (zpay32) string. creationDate := time.Now() payReq, err := zpay32.NewInvoice( - activeNetParams.Params, - rHash, - creationDate, - options..., + activeNetParams.Params, rHash, creationDate, options..., ) if err != nil { return nil, err From 4e90691bf34206fff000b243e78d77d7ae42dfd8 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 28 Mar 2018 00:53:00 -0400 Subject: [PATCH 12/14] rpcserver: include routing hints when sending payments --- rpcserver.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index b4d831d2..fd4dc93b 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1704,12 +1704,13 @@ func validatePayReqExpiry(payReq *zpay32.Invoice) error { // Lightning Network with a single persistent connection. func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer) error { // For each payment we need to know the msat amount, the destination - // public key, and the payment hash. + // public key, the payment hash, and the optional route hints. type payment struct { - msat lnwire.MilliSatoshi - dest []byte - pHash []byte - cltvDelta uint16 + msat lnwire.MilliSatoshi + dest []byte + pHash []byte + cltvDelta uint16 + routeHints [][]routing.HopHint } payChan := make(chan *payment) errChan := make(chan error, 1) @@ -1821,6 +1822,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer) p.pHash = payReq.PaymentHash[:] p.cltvDelta = uint16(payReq.MinFinalCLTVExpiry()) + p.routeHints = payReq.RouteHints } else { // If the payment request field was not // specified, construct the payment from @@ -1904,6 +1906,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer) Target: destNode, Amount: p.msat, PaymentHash: rHash, + RouteHints: p.routeHints, } if p.cltvDelta != 0 { payment.FinalCLTVDelta = &p.cltvDelta @@ -1961,10 +1964,11 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context, } var ( - destPub *btcec.PublicKey - amtMSat lnwire.MilliSatoshi - rHash [32]byte - cltvDelta uint16 + destPub *btcec.PublicKey + amtMSat lnwire.MilliSatoshi + rHash [32]byte + cltvDelta uint16 + routeHints [][]routing.HopHint ) // If the proto request has an encoded payment request, then we we'll @@ -1997,6 +2001,7 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context, rHash = *payReq.PaymentHash cltvDelta = uint16(payReq.MinFinalCLTVExpiry()) + routeHints = payReq.RouteHints // Otherwise, the payment conditions have been manually // specified in the proto. @@ -2047,6 +2052,7 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context, Target: destPub, Amount: amtMSat, PaymentHash: rHash, + RouteHints: routeHints, } if cltvDelta != 0 { payment.FinalCLTVDelta = &cltvDelta From 8469fddb336ea3cdbbd1ad5de4effeddfd109116 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 15 Mar 2018 13:02:40 -0400 Subject: [PATCH 13/14] lnd_test: modify openChannelAndAssert to open private or public channels --- lnd_test.go | 227 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 135 insertions(+), 92 deletions(-) diff --git a/lnd_test.go b/lnd_test.go index 14c28318..130b1262 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -144,19 +144,20 @@ func mineBlocks(t *harnessTest, net *lntest.NetworkHarness, num uint32) []*wire. // channel. func openChannelAndAssert(ctx context.Context, t *harnessTest, net *lntest.NetworkHarness, alice, bob *lntest.HarnessNode, - fundingAmt btcutil.Amount, pushAmt btcutil.Amount) *lnrpc.ChannelPoint { + fundingAmt btcutil.Amount, pushAmt btcutil.Amount, + private bool) *lnrpc.ChannelPoint { - chanOpenUpdate, err := net.OpenChannel(ctx, alice, bob, fundingAmt, - pushAmt, false) + chanOpenUpdate, err := net.OpenChannel( + ctx, alice, bob, fundingAmt, pushAmt, private, + ) if err != nil { t.Fatalf("unable to open channel: %v", err) } // Mine 6 blocks, then wait for Alice's node to notify us that the // channel has been opened. The funding transaction should be found - // within the first newly mined block. We mine 6 blocks to make sure - // the channel is public, as it will not be announced to the network - // before the funding transaction is 6 blocks deep. + // within the first newly mined block. We mine 6 blocks so that in the + // case that the channel is public, it is announced to the network. block := mineBlocks(t, net, 6)[0] fundingChanPoint, err := net.WaitForChannelOpen(ctx, chanOpenUpdate) @@ -458,8 +459,9 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { // assertions will be executed to ensure the funding process completed // successfully. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, pushAmt) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false, + ) ctxt, _ = context.WithTimeout(ctxb, time.Second*15) err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint) @@ -517,8 +519,9 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { // Create a channel Alice->Bob. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, pushAmt) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false, + ) ctxt, _ = context.WithTimeout(ctxb, time.Second*15) err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint) @@ -543,8 +546,9 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPoint2 := openChannelAndAssert(ctxt, t, net, net.Bob, carol, - chanAmt, pushAmt) + chanPoint2 := openChannelAndAssert( + ctxt, t, net, net.Bob, carol, chanAmt, pushAmt, false, + ) ctxt, _ = context.WithTimeout(ctxb, time.Second*15) err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint2) @@ -756,7 +760,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { } ctxt, _ = context.WithTimeout(ctxb, timeout) chanPoint3 := openChannelAndAssert( - ctxt, t, net, net.Alice, carol, chanAmt, pushAmt, + ctxt, t, net, net.Alice, carol, chanAmt, pushAmt, false, ) ctxt, _ = context.WithTimeout(ctxb, time.Second*15) @@ -1297,8 +1301,9 @@ func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to connect alice and bob: %v", err) } - chanPoint := openChannelAndAssert(ctx, t, net, net.Alice, net.Bob, - amount, 0) + chanPoint := openChannelAndAssert( + ctx, t, net, net.Alice, net.Bob, amount, 0, false, + ) // Wait for both Alice and Bob to recognize this new channel. ctxt, _ := context.WithTimeout(context.Background(), timeout) @@ -1467,8 +1472,9 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) { carolStartingBalance := carolBalResp.ConfirmedBalance ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, carol, - chanAmt, pushAmt) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, carol, chanAmt, pushAmt, false, + ) // Wait for Alice and Carol to receive the channel edge from the // funding manager. @@ -2054,8 +2060,9 @@ func testSphinxReplayPersistence(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, 0, false, + ) assertAmountSent := func(amt btcutil.Amount) { // Both channels should also have properly accounted from the @@ -2201,8 +2208,9 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) { // the sole funder of the channel. ctxt, _ := context.WithTimeout(ctxb, timeout) chanAmt := btcutil.Amount(100000) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) assertAmountSent := func(amt btcutil.Amount) { // Both channels should also have properly accounted from the @@ -2356,8 +2364,9 @@ func testListPayments(net *lntest.NetworkHarness, t *harnessTest) { // being the sole funder of the channel. chanAmt := btcutil.Amount(100000) ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) // Now that the channel is open, create an invoice for Bob which // expects a payment of 1000 satoshis from Alice paid via a particular @@ -2537,8 +2546,9 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) { // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, - net.Bob, chanAmt, 0) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointAlice) txidHash, err := getChanPointFundingTxid(chanPointAlice) @@ -2573,8 +2583,9 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to dave: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointDave := openChannelAndAssert(ctxt, t, net, dave, - net.Alice, chanAmt, 0) + chanPointDave := openChannelAndAssert( + ctxt, t, net, dave, net.Alice, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointDave) txidHash, err = getChanPointFundingTxid(chanPointDave) if err != nil { @@ -2603,8 +2614,9 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointCarol := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, 0) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointCarol) txidHash, err = getChanPointFundingTxid(chanPointCarol) @@ -2800,8 +2812,9 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { // Open a channel with 200k satoshis between Alice and Bob. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, - net.Bob, chanAmt*2, 0) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt*2, 0, false, + ) networkChans = append(networkChans, chanPointAlice) txidHash, err := getChanPointFundingTxid(chanPointAlice) @@ -2830,8 +2843,9 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to dave: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointDave := openChannelAndAssert(ctxt, t, net, dave, - net.Alice, chanAmt, 0) + chanPointDave := openChannelAndAssert( + ctxt, t, net, dave, net.Alice, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointDave) txidHash, err = getChanPointFundingTxid(chanPointDave) if err != nil { @@ -2860,8 +2874,9 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointCarol := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, 0) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointCarol) txidHash, err = getChanPointFundingTxid(chanPointCarol) @@ -3124,8 +3139,9 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) { // Open a channel with 500k satoshis between Alice and Bob with Alice // being the sole funder of the channel. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) // Next create a new invoice for Bob requesting 1k satoshis. // TODO(roasbeef): make global list of invoices for each node to re-use @@ -3233,8 +3249,9 @@ func testBasicChannelCreation(net *lntest.NetworkHarness, t *harnessTest) { chanPoints := make([]*lnrpc.ChannelPoint, numChannels) for i := 0; i < numChannels; i++ { ctx, _ := context.WithTimeout(context.Background(), timeout) - chanPoints[i] = openChannelAndAssert(ctx, t, net, net.Alice, - net.Bob, amount, 0) + chanPoints[i] = openChannelAndAssert( + ctx, t, net, net.Alice, net.Bob, amount, 0, false, + ) } // Close the channel between Alice and Bob, asserting that the @@ -3460,8 +3477,9 @@ func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) { // closure by Bob, we'll first open up a channel between them with a // 0.5 BTC value. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) // With the channel open, we'll create a few invoices for Bob that // Alice will pay to in order to advance the state of the channel. @@ -3709,8 +3727,9 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness // closure by Carol, we'll first open up a channel between them with a // 0.5 BTC value. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, carol, - chanAmt, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, carol, chanAmt, 0, false, + ) // With the channel open, we'll create a few invoices for Carol that // Alice will pay to in order to advance the state of the channel. @@ -3945,7 +3964,7 @@ func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness, // maxFundingAmount (2^24) satoshis value. ctxt, _ := context.WithTimeout(ctxb, timeout) chanPoint := openChannelAndAssert( - ctxt, t, net, dave, carol, chanAmt, pushAmt, + ctxt, t, net, dave, carol, chanAmt, pushAmt, false, ) // With the channel open, we'll create a few invoices for Carol that @@ -4268,8 +4287,9 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) { // First establish a channel with a capacity of 0.5 BTC between Alice // and Bob. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, 0) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) ctxt, _ = context.WithTimeout(ctxb, timeout) if err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPointAlice); err != nil { t.Fatalf("channel not seen by alice before timeout: %v", err) @@ -4312,8 +4332,9 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) { } ctxt, _ = context.WithTimeout(ctxb, timeout) const bobChanAmt = maxFundingAmount - chanPointBob := openChannelAndAssert(ctxt, t, net, net.Bob, carol, - chanAmt, 0) + chanPointBob := openChannelAndAssert( + ctxt, t, net, net.Bob, carol, chanAmt, 0, false, + ) // Ensure that Alice has Carol in her routing table before proceeding. nodeInfoReq := &lnrpc.NodeInfoRequest{ @@ -4600,8 +4621,9 @@ func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest) // Open a new channel between Alice and Bob. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) // The channel opening above should have triggered a few notifications // sent to the notification client. We'll expect two channel updates, @@ -4714,8 +4736,9 @@ func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest) t.Fatalf("unable to connect bob to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPoint = openChannelAndAssert(ctxt, t, net, net.Bob, carol, - chanAmt, 0) + chanPoint = openChannelAndAssert( + ctxt, t, net, net.Bob, carol, chanAmt, 0, false, + ) // Reconnect Alice and Bob. This should result in the nodes syncing up // their respective graph state, with the new addition being the @@ -4811,8 +4834,9 @@ func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) { timeout := time.Duration(time.Second * 5) ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Bob, dave, - 1000000, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Bob, dave, 1000000, 0, false, + ) // When Alice now connects with Dave, Alice will get his node announcement. if err := net.ConnectNodes(ctxb, net.Alice, dave); err != nil { @@ -4869,8 +4893,9 @@ func testNodeSignVerify(net *lntest.NetworkHarness, t *harnessTest) { // Create a channel between alice and bob. ctxt, _ := context.WithTimeout(ctxb, timeout) - aliceBobCh := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - chanAmt, pushAmt) + aliceBobCh := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false, + ) aliceMsg := []byte("alice msg") @@ -4968,8 +4993,9 @@ func testAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) { // Alice should send all money from her side to Bob. ctxt, _ := context.WithTimeout(ctxb, timeout) channelCapacity := btcutil.Amount(paymentAmt * 2000) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - channelCapacity, 0) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, channelCapacity, 0, false, + ) info, err := getChanInfo(net.Alice) if err != nil { @@ -5150,8 +5176,10 @@ func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) // amount of payments, between Alice and Bob, at the end of the test // Alice should send all money from her side to Bob. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, net.Bob, - paymentAmt*2000, paymentAmt*1000) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, paymentAmt*2000, + paymentAmt*1000, false, + ) info, err := getChanInfo(net.Alice) if err != nil { @@ -5466,7 +5494,7 @@ func createThreeHopHodlNetwork(t *harnessTest, timeout := time.Duration(time.Second * 15) ctxt, _ := context.WithTimeout(ctxb, timeout) aliceChanPoint := openChannelAndAssert( - ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, ) ctxt, _ = context.WithTimeout(ctxb, time.Second*15) @@ -5496,7 +5524,7 @@ func createThreeHopHodlNetwork(t *harnessTest, // open, our topology looks like: A -> B -> C. ctxt, _ = context.WithTimeout(ctxb, timeout) bobChanPoint := openChannelAndAssert( - ctxt, t, net, net.Bob, carol, chanAmt, 0, + ctxt, t, net, net.Bob, carol, chanAmt, 0, false, ) ctxt, _ = context.WithTimeout(ctxb, time.Second*15) err = net.Bob.WaitForNetworkChannelOpen(ctxt, bobChanPoint) @@ -6763,8 +6791,9 @@ func testSwitchCircuitPersistence(net *lntest.NetworkHarness, t *harnessTest) { // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, - net.Bob, chanAmt, pushAmt) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointAlice) txidHash, err := getChanPointFundingTxid(chanPointAlice) @@ -6799,8 +6828,9 @@ func testSwitchCircuitPersistence(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to dave: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointDave := openChannelAndAssert(ctxt, t, net, dave, - net.Alice, chanAmt, pushAmt) + chanPointDave := openChannelAndAssert( + ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointDave) txidHash, err = getChanPointFundingTxid(chanPointDave) if err != nil { @@ -6830,8 +6860,9 @@ func testSwitchCircuitPersistence(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointCarol := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, pushAmt) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointCarol) txidHash, err = getChanPointFundingTxid(chanPointCarol) @@ -7081,8 +7112,9 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) { // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, - net.Bob, chanAmt, pushAmt) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointAlice) txidHash, err := getChanPointFundingTxid(chanPointAlice) @@ -7117,8 +7149,9 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to dave: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointDave := openChannelAndAssert(ctxt, t, net, dave, - net.Alice, chanAmt, pushAmt) + chanPointDave := openChannelAndAssert( + ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointDave) txidHash, err = getChanPointFundingTxid(chanPointDave) if err != nil { @@ -7148,8 +7181,9 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointCarol := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, pushAmt) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointCarol) txidHash, err = getChanPointFundingTxid(chanPointCarol) @@ -7404,8 +7438,9 @@ func testSwitchOfflineDeliveryPersistence(net *lntest.NetworkHarness, t *harness // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, - net.Bob, chanAmt, pushAmt) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointAlice) txidHash, err := getChanPointFundingTxid(chanPointAlice) @@ -7440,8 +7475,9 @@ func testSwitchOfflineDeliveryPersistence(net *lntest.NetworkHarness, t *harness t.Fatalf("unable to send coins to dave: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointDave := openChannelAndAssert(ctxt, t, net, dave, - net.Alice, chanAmt, pushAmt) + chanPointDave := openChannelAndAssert( + ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointDave) txidHash, err = getChanPointFundingTxid(chanPointDave) if err != nil { @@ -7471,8 +7507,9 @@ func testSwitchOfflineDeliveryPersistence(net *lntest.NetworkHarness, t *harness t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointCarol := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, pushAmt) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointCarol) txidHash, err = getChanPointFundingTxid(chanPointCarol) @@ -7728,8 +7765,9 @@ func testSwitchOfflineDeliveryOutgoingOffline( // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, - net.Bob, chanAmt, pushAmt) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointAlice) txidHash, err := getChanPointFundingTxid(chanPointAlice) @@ -7764,8 +7802,9 @@ func testSwitchOfflineDeliveryOutgoingOffline( t.Fatalf("unable to send coins to dave: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointDave := openChannelAndAssert(ctxt, t, net, dave, - net.Alice, chanAmt, pushAmt) + chanPointDave := openChannelAndAssert( + ctxt, t, net, dave, net.Alice, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointDave) txidHash, err = getChanPointFundingTxid(chanPointDave) if err != nil { @@ -7795,8 +7834,9 @@ func testSwitchOfflineDeliveryOutgoingOffline( t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointCarol := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, pushAmt) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, pushAmt, false, + ) networkChans = append(networkChans, chanPointCarol) txidHash, err = getChanPointFundingTxid(chanPointCarol) @@ -8000,8 +8040,9 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) { // Open a channel between Alice and Bob. ctxt, _ := context.WithTimeout(ctxb, timeout) - chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, - net.Bob, chanAmt, 0) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointAlice) // Create Carol and establish a channel from Bob. @@ -8017,8 +8058,9 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to bob: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointBob := openChannelAndAssert(ctxt, t, net, net.Bob, - carol, chanAmt, 0) + chanPointBob := openChannelAndAssert( + ctxt, t, net, net.Bob, carol, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointBob) // Create Dave and establish a channel from Carol. @@ -8034,8 +8076,9 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to send coins to carol: %v", err) } ctxt, _ = context.WithTimeout(ctxb, timeout) - chanPointCarol := openChannelAndAssert(ctxt, t, net, carol, - dave, chanAmt, 0) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, 0, false, + ) networkChans = append(networkChans, chanPointCarol) // Wait for all nodes to have seen all channels. From cb8bdc2d21f2676ba5571fc0a3a6d290ba041d52 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 15 Mar 2018 13:02:52 -0400 Subject: [PATCH 14/14] lnd_test: add test for multi-hop payments over private channels --- lnd_test.go | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/lnd_test.go b/lnd_test.go index 130b1262..efc126b5 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -3131,6 +3131,223 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { } } +// testMultiHopOverPrivateChannels tests that private channels can be used as +// intermediate hops in a route for payments. +func testMultiHopOverPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { + // We'll test that multi-hop payments over private channels work as + // intended. To do so, we'll create the following topology: + // private public private + // Alice <--100k--> Bob <--100k--> Carol <--100k--> Dave + + ctxb := context.Background() + timeout := time.Duration(15 * time.Second) + const chanAmt = btcutil.Amount(100000) + + // First, we'll open a private channel between Alice and Bob with Alice + // being the funder. + ctxt, _ := context.WithTimeout(ctxb, timeout) + chanPointAlice := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, true, + ) + + ctxt, _ = context.WithTimeout(ctxb, timeout) + err := net.Alice.WaitForNetworkChannelOpen(ctxb, chanPointAlice) + if err != nil { + t.Fatalf("alice didn't see the channel alice <-> bob before "+ + "timeout: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = net.Bob.WaitForNetworkChannelOpen(ctxb, chanPointAlice) + if err != nil { + t.Fatalf("bob didn't see the channel alice <-> bob before "+ + "timeout: %v", err) + } + + // Retrieve Alice's funding outpoint. + txidHash, err := getChanPointFundingTxid(chanPointAlice) + if err != nil { + t.Fatalf("unable to get txid: %v", err) + } + aliceChanTXID, err := chainhash.NewHash(txidHash) + if err != nil { + t.Fatalf("unable to create sha hash: %v", err) + } + aliceFundPoint := wire.OutPoint{ + Hash: *aliceChanTXID, + Index: chanPointAlice.OutputIndex, + } + + // Next, we'll create Carol's node and open a public channel between + // her and Bob with Bob being the funder. + carol, err := net.NewNode(nil) + if err != nil { + t.Fatalf("unable to create carol's node: %v", err) + } + if err := net.ConnectNodes(ctxb, net.Bob, carol); err != nil { + t.Fatalf("unable to connect bob to carol: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + chanPointBob := openChannelAndAssert( + ctxt, t, net, net.Bob, carol, chanAmt, 0, false, + ) + + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = net.Bob.WaitForNetworkChannelOpen(ctxb, chanPointBob) + if err != nil { + t.Fatalf("bob didn't see the channel bob <-> carol before "+ + "timeout: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = carol.WaitForNetworkChannelOpen(ctxb, chanPointBob) + if err != nil { + t.Fatalf("carol didn't see the channel bob <-> carol before "+ + "timeout: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = net.Alice.WaitForNetworkChannelOpen(ctxb, chanPointBob) + if err != nil { + t.Fatalf("alice didn't see the channel bob <-> carol before "+ + "timeout: %v", err) + } + + // Retrieve Bob's funding outpoint. + txidHash, err = getChanPointFundingTxid(chanPointBob) + if err != nil { + t.Fatalf("unable to get txid: %v", err) + } + bobChanTXID, err := chainhash.NewHash(txidHash) + if err != nil { + t.Fatalf("unable to create sha hash: %v", err) + } + bobFundPoint := wire.OutPoint{ + Hash: *bobChanTXID, + Index: chanPointBob.OutputIndex, + } + + // Next, we'll create Dave's node and open a private channel between him + // and Carol with Carol being the funder. + dave, err := net.NewNode(nil) + if err != nil { + t.Fatalf("unable to create dave's node: %v", err) + } + if err := net.ConnectNodes(ctxb, carol, dave); err != nil { + t.Fatalf("unable to connect carol to dave: %v", err) + } + err = net.SendCoins(ctxb, btcutil.SatoshiPerBitcoin, carol) + if err != nil { + t.Fatalf("unable to send coins to carol: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, 0, true, + ) + + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = carol.WaitForNetworkChannelOpen(ctxb, chanPointCarol) + if err != nil { + t.Fatalf("carol didn't see the channel carol <-> dave before "+ + "timeout: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = dave.WaitForNetworkChannelOpen(ctxb, chanPointCarol) + if err != nil { + t.Fatalf("dave didn't see the channel carol <-> dave before "+ + "timeout: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = dave.WaitForNetworkChannelOpen(ctxb, chanPointBob) + if err != nil { + t.Fatalf("dave didn't see the channel bob <-> carol before "+ + "timeout: %v", err) + } + + // Retrieve Carol's funding point. + txidHash, err = getChanPointFundingTxid(chanPointCarol) + if err != nil { + t.Fatalf("unable to get txid: %v", err) + } + carolChanTXID, err := chainhash.NewHash(txidHash) + if err != nil { + t.Fatalf("unable to create sha hash: %v", err) + } + carolFundPoint := wire.OutPoint{ + Hash: *carolChanTXID, + Index: chanPointCarol.OutputIndex, + } + + // Now that all the channels are set up according to the topology from + // above, we can proceed to test payments. We'll create an invoice for + // Dave of 20k satoshis and pay it with Alice. Since there is no public + // route from Alice to Dave, we'll need to use the private channel + // between Carol and Dave as a routing hint encoded in the invoice. + const paymentAmt = 20000 + + // Create the invoice for Dave. + invoice := &lnrpc.Invoice{ + Memo: "two hopz!", + Value: paymentAmt, + Private: true, + } + + resp, err := dave.AddInvoice(ctxb, invoice) + if err != nil { + t.Fatalf("unable to add invoice for dave: %v", err) + } + + // Let Alice pay the invoice. + payReqs := []string{resp.PaymentRequest} + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = completePaymentRequests(ctxt, net.Alice, payReqs, true) + if err != nil { + t.Fatalf("unable to send payments from alice to dave: %v", err) + } + + // When asserting the amount of satoshis moved, we'll factor in the + // default base fee, as we didn't modify the fee structure when opening + // the channels. + const baseFee = 1 + + // Dave should have received 20k satoshis from Carol. + assertAmountPaid(t, ctxb, "Carol(local) [private=>] Dave(remote)", + dave, carolFundPoint, 0, paymentAmt) + + // Carol should have sent 20k satoshis to Dave. + assertAmountPaid(t, ctxb, "Carol(local) [private=>] Dave(remote)", + carol, carolFundPoint, paymentAmt, 0) + + // Carol should have received 20k satoshis + fee for one hop from Bob. + assertAmountPaid(t, ctxb, "Bob(local) => Carol(remote)", + carol, bobFundPoint, 0, paymentAmt+baseFee) + + // Bob should have sent 20k satoshis + fee for one hop to Carol. + assertAmountPaid(t, ctxb, "Bob(local) => Carol(remote)", + net.Bob, bobFundPoint, paymentAmt+baseFee, 0) + + // Bob should have received 20k satoshis + fee for two hops from Alice. + assertAmountPaid(t, ctxb, "Alice(local) [private=>] Bob(remote)", net.Bob, + aliceFundPoint, 0, paymentAmt+baseFee*2) + + // Alice should have sent 20k satoshis + fee for two hops to Bob. + assertAmountPaid(t, ctxb, "Alice(local) [private=>] Bob(remote)", net.Alice, + aliceFundPoint, paymentAmt+baseFee*2, 0) + + // At this point, the payment was successful. We can now close all the + // channels and shutdown the nodes created throughout this test. + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAlice, false) + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, net.Bob, chanPointBob, false) + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, carol, chanPointCarol, false) + + if err := net.ShutdownNode(carol); err != nil { + t.Fatalf("unable to shutdown carol's node: %v", err) + } + if err := net.ShutdownNode(dave); err != nil { + t.Fatalf("unable to shutdown dave's node: %v", err) + } +} + func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) { const chanAmt = btcutil.Amount(500000) ctxb := context.Background() @@ -8280,6 +8497,10 @@ var testsCases = []*testCase{ name: "private channels", test: testPrivateChannels, }, + { + name: "multi-hop payments over private channels", + test: testMultiHopOverPrivateChannels, + }, { name: "multiple channel creation", test: testBasicChannelCreation,