Merge branch 'master' into regnaio/location

git merge master
This commit is contained in:
regnaio 2022-05-01 03:24:13 -04:00
commit b548bf3723
24 changed files with 688 additions and 317 deletions

View File

@ -21,6 +21,7 @@ import (
"github.com/cloudflare/cloudflared/logger" "github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/metrics" "github.com/cloudflare/cloudflared/metrics"
"github.com/cloudflare/cloudflared/overwatch" "github.com/cloudflare/cloudflared/overwatch"
"github.com/cloudflare/cloudflared/tracing"
"github.com/cloudflare/cloudflared/watcher" "github.com/cloudflare/cloudflared/watcher"
) )
@ -86,6 +87,7 @@ func main() {
tunnel.Init(bInfo, graceShutdownC) // we need this to support the tunnel sub command... tunnel.Init(bInfo, graceShutdownC) // we need this to support the tunnel sub command...
access.Init(graceShutdownC) access.Init(graceShutdownC)
updater.Init(Version) updater.Init(Version)
tracing.Init(Version)
runApp(app, graceShutdownC) runApp(app, graceShutdownC)
} }

View File

@ -41,7 +41,8 @@ var (
LogFieldHostname = "hostname" LogFieldHostname = "hostname"
secretFlags = [2]*altsrc.StringFlag{credentialsContentsFlag, tunnelTokenFlag} secretFlags = [2]*altsrc.StringFlag{credentialsContentsFlag, tunnelTokenFlag}
defaultFeatures = []string{supervisor.FeatureAllowRemoteConfig, supervisor.FeatureSerializedHeaders}
) )
// returns the first path that contains a cert.pem file. If none of the DefaultConfigSearchDirectories // returns the first path that contains a cert.pem file. If none of the DefaultConfigSearchDirectories
@ -225,7 +226,7 @@ func prepareTunnelConfig(
return nil, nil, errors.Wrap(err, "can't generate connector UUID") return nil, nil, errors.Wrap(err, "can't generate connector UUID")
} }
log.Info().Msgf("Generated Connector ID: %s", clientUUID) log.Info().Msgf("Generated Connector ID: %s", clientUUID)
features := append(c.StringSlice("features"), supervisor.FeatureSerializedHeaders) features := append(c.StringSlice("features"), defaultFeatures...)
if c.IsSet(TunnelTokenFlag) { if c.IsSet(TunnelTokenFlag) {
if transportProtocol == connection.AutoSelectFlag { if transportProtocol == connection.AutoSelectFlag {
protocolFetcher = func() (edgediscovery.ProtocolPercents, error) { protocolFetcher = func() (edgediscovery.ProtocolPercents, error) {
@ -243,7 +244,6 @@ func prepareTunnelConfig(
return preferQuic, nil return preferQuic, nil
} }
} }
features = append(features, supervisor.FeatureAllowRemoteConfig)
log.Info().Msg("Will be fetching remotely managed configuration from Cloudflare API. Defaulting to protocol: quic") log.Info().Msg("Will be fetching remotely managed configuration from Cloudflare API. Defaulting to protocol: quic")
} }
namedTunnel.Client = tunnelpogs.ClientInfo{ namedTunnel.Client = tunnelpogs.ClientInfo{

View File

@ -15,7 +15,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v3"
"github.com/cloudflare/cloudflared/validation" "github.com/cloudflare/cloudflared/validation"
) )
@ -393,7 +393,7 @@ func ReadConfigFile(c *cli.Context, log *zerolog.Logger) (settings *configFileSe
// Parse it again, with strict mode, to find warnings. // Parse it again, with strict mode, to find warnings.
if file, err := os.Open(configFile); err == nil { if file, err := os.Open(configFile); err == nil {
decoder := yaml.NewDecoder(file) decoder := yaml.NewDecoder(file)
decoder.SetStrict(true) decoder.KnownFields(true)
var unusedConfig configFileSettings var unusedConfig configFileSettings
if err := decoder.Decode(&unusedConfig); err != nil { if err := decoder.Decode(&unusedConfig); err != nil {
warnings = err.Error() warnings = err.Error()

View File

@ -231,6 +231,12 @@ func (rp *http2RespWriter) WriteRespHeaders(status int, header http.Header) erro
dest[name] = values dest[name] = values
} }
if h2name == tracing.IntCloudflaredTracingHeader {
// Add cf-int-cloudflared-tracing header outside of serialized userHeaders
rp.w.Header()[tracing.CanonicalCloudflaredTracingHeader] = values
continue
}
if !IsControlResponseHeader(h2name) || IsWebsocketClientHeader(h2name) { if !IsControlResponseHeader(h2name) || IsWebsocketClientHeader(h2name) {
// User headers, on the other hand, must all be serialized so that // User headers, on the other hand, must all be serialized so that
// HTTP/2 header validation won't be applied to HTTP/1 header values // HTTP/2 header validation won't be applied to HTTP/1 header values

View File

@ -2,6 +2,7 @@ package datagramsession
import ( import (
"context" "context"
"fmt"
"io" "io"
"time" "time"
@ -16,6 +17,10 @@ const (
defaultReqTimeout = time.Second * 5 defaultReqTimeout = time.Second * 5
) )
var (
errSessionManagerClosed = fmt.Errorf("session manager closed")
)
// Manager defines the APIs to manage sessions from the same transport. // Manager defines the APIs to manage sessions from the same transport.
type Manager interface { type Manager interface {
// Serve starts the event loop // Serve starts the event loop
@ -30,6 +35,7 @@ type manager struct {
registrationChan chan *registerSessionEvent registrationChan chan *registerSessionEvent
unregistrationChan chan *unregisterSessionEvent unregistrationChan chan *unregisterSessionEvent
datagramChan chan *newDatagram datagramChan chan *newDatagram
closedChan chan struct{}
transport transport transport transport
sessions map[uuid.UUID]*Session sessions map[uuid.UUID]*Session
log *zerolog.Logger log *zerolog.Logger
@ -43,6 +49,7 @@ func NewManager(transport transport, log *zerolog.Logger) *manager {
unregistrationChan: make(chan *unregisterSessionEvent), unregistrationChan: make(chan *unregisterSessionEvent),
// datagramChan is buffered, so it can read more datagrams from transport while the event loop is processing other events // datagramChan is buffered, so it can read more datagrams from transport while the event loop is processing other events
datagramChan: make(chan *newDatagram, requestChanCapacity), datagramChan: make(chan *newDatagram, requestChanCapacity),
closedChan: make(chan struct{}),
transport: transport, transport: transport,
sessions: make(map[uuid.UUID]*Session), sessions: make(map[uuid.UUID]*Session),
log: log, log: log,
@ -90,7 +97,24 @@ func (m *manager) Serve(ctx context.Context) error {
} }
} }
}) })
return errGroup.Wait() err := errGroup.Wait()
close(m.closedChan)
m.shutdownSessions(err)
return err
}
func (m *manager) shutdownSessions(err error) {
if err == nil {
err = errSessionManagerClosed
}
closeSessionErr := &errClosedSession{
message: err.Error(),
// Usually connection with remote has been closed, so set this to true to skip unregistering from remote
byRemote: true,
}
for _, s := range m.sessions {
s.close(closeSessionErr)
}
} }
func (m *manager) RegisterSession(ctx context.Context, sessionID uuid.UUID, originProxy io.ReadWriteCloser) (*Session, error) { func (m *manager) RegisterSession(ctx context.Context, sessionID uuid.UUID, originProxy io.ReadWriteCloser) (*Session, error) {
@ -104,15 +128,33 @@ func (m *manager) RegisterSession(ctx context.Context, sessionID uuid.UUID, orig
case m.registrationChan <- event: case m.registrationChan <- event:
session := <-event.resultChan session := <-event.resultChan
return session, nil return session, nil
// Once closedChan is closed, manager won't accept more registration because nothing is
// reading from registrationChan and it's an unbuffered channel
case <-m.closedChan:
return nil, errSessionManagerClosed
} }
} }
func (m *manager) registerSession(ctx context.Context, registration *registerSessionEvent) { func (m *manager) registerSession(ctx context.Context, registration *registerSessionEvent) {
session := newSession(registration.sessionID, m.transport, registration.originProxy, m.log) session := m.newSession(registration.sessionID, registration.originProxy)
m.sessions[registration.sessionID] = session m.sessions[registration.sessionID] = session
registration.resultChan <- session registration.resultChan <- session
} }
func (m *manager) newSession(id uuid.UUID, dstConn io.ReadWriteCloser) *Session {
return &Session{
ID: id,
transport: m.transport,
dstConn: dstConn,
// activeAtChan has low capacity. It can be full when there are many concurrent read/write. markActive() will
// drop instead of blocking because last active time only needs to be an approximation
activeAtChan: make(chan time.Time, 2),
// capacity is 2 because close() and dstToTransport routine in Serve() can write to this channel
closeChan: make(chan error, 2),
log: m.log,
}
}
func (m *manager) UnregisterSession(ctx context.Context, sessionID uuid.UUID, message string, byRemote bool) error { func (m *manager) UnregisterSession(ctx context.Context, sessionID uuid.UUID, message string, byRemote bool) error {
ctx, cancel := context.WithTimeout(ctx, m.timeout) ctx, cancel := context.WithTimeout(ctx, m.timeout)
defer cancel() defer cancel()
@ -129,6 +171,8 @@ func (m *manager) UnregisterSession(ctx context.Context, sessionID uuid.UUID, me
return ctx.Err() return ctx.Err()
case m.unregistrationChan <- event: case m.unregistrationChan <- event:
return nil return nil
case <-m.closedChan:
return errSessionManagerClosed
} }
} }

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"sync"
"testing" "testing"
"time" "time"
@ -21,12 +22,8 @@ func TestManagerServe(t *testing.T) {
msgs = 50 msgs = 50
remoteUnregisterMsg = "eyeball closed connection" remoteUnregisterMsg = "eyeball closed connection"
) )
log := zerolog.Nop()
transport := &mockQUICTransport{ mg, transport := newTestManager(1)
reqChan: newDatagramChannel(1),
respChan: newDatagramChannel(1),
}
mg := NewManager(transport, &log)
eyeballTracker := make(map[uuid.UUID]*datagramChannel) eyeballTracker := make(map[uuid.UUID]*datagramChannel)
for i := 0; i < sessions; i++ { for i := 0; i < sessions; i++ {
@ -124,12 +121,8 @@ func TestTimeout(t *testing.T) {
const ( const (
testTimeout = time.Millisecond * 50 testTimeout = time.Millisecond * 50
) )
log := zerolog.Nop()
transport := &mockQUICTransport{ mg, _ := newTestManager(1)
reqChan: newDatagramChannel(1),
respChan: newDatagramChannel(1),
}
mg := NewManager(transport, &log)
mg.timeout = testTimeout mg.timeout = testTimeout
ctx := context.Background() ctx := context.Background()
sessionID := uuid.New() sessionID := uuid.New()
@ -142,6 +135,47 @@ func TestTimeout(t *testing.T) {
require.ErrorIs(t, err, context.DeadlineExceeded) require.ErrorIs(t, err, context.DeadlineExceeded)
} }
func TestCloseTransportCloseSessions(t *testing.T) {
mg, transport := newTestManager(1)
ctx := context.Background()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := mg.Serve(ctx)
require.Error(t, err)
}()
cfdConn, eyeballConn := net.Pipe()
session, err := mg.RegisterSession(ctx, uuid.New(), cfdConn)
require.NoError(t, err)
require.NotNil(t, session)
wg.Add(1)
go func() {
defer wg.Done()
_, err := eyeballConn.Write([]byte(t.Name()))
require.NoError(t, err)
transport.close()
}()
closedByRemote, err := session.Serve(ctx, time.Minute)
require.True(t, closedByRemote)
require.Error(t, err)
wg.Wait()
}
func newTestManager(capacity uint) (*manager, *mockQUICTransport) {
log := zerolog.Nop()
transport := &mockQUICTransport{
reqChan: newDatagramChannel(capacity),
respChan: newDatagramChannel(capacity),
}
return NewManager(transport, &log), transport
}
type mockOrigin struct { type mockOrigin struct {
expectMsgCount int expectMsgCount int
expectedMsg []byte expectedMsg []byte

View File

@ -39,20 +39,6 @@ type Session struct {
log *zerolog.Logger log *zerolog.Logger
} }
func newSession(id uuid.UUID, transport transport, dstConn io.ReadWriteCloser, log *zerolog.Logger) *Session {
return &Session{
ID: id,
transport: transport,
dstConn: dstConn,
// activeAtChan has low capacity. It can be full when there are many concurrent read/write. markActive() will
// drop instead of blocking because last active time only needs to be an approximation
activeAtChan: make(chan time.Time, 2),
// capacity is 2 because close() and dstToTransport routine in Serve() can write to this channel
closeChan: make(chan error, 2),
log: log,
}
}
func (s *Session) Serve(ctx context.Context, closeAfterIdle time.Duration) (closedByRemote bool, err error) { func (s *Session) Serve(ctx context.Context, closeAfterIdle time.Duration) (closedByRemote bool, err error) {
go func() { go func() {
// QUIC implementation copies data to another buffer before returning https://github.com/lucas-clemente/quic-go/blob/v0.24.0/session.go#L1967-L1975 // QUIC implementation copies data to another buffer before returning https://github.com/lucas-clemente/quic-go/blob/v0.24.0/session.go#L1967-L1975

View File

@ -11,7 +11,6 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
@ -41,12 +40,9 @@ func testSessionReturns(t *testing.T, closeBy closeMethod, closeAfterIdle time.D
sessionID := uuid.New() sessionID := uuid.New()
cfdConn, originConn := net.Pipe() cfdConn, originConn := net.Pipe()
payload := testPayload(sessionID) payload := testPayload(sessionID)
transport := &mockQUICTransport{
reqChan: newDatagramChannel(1), mg, _ := newTestManager(1)
respChan: newDatagramChannel(1), session := mg.newSession(sessionID, cfdConn)
}
log := zerolog.Nop()
session := newSession(sessionID, transport, cfdConn, &log)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
sessionDone := make(chan struct{}) sessionDone := make(chan struct{})
@ -117,12 +113,9 @@ func testActiveSessionNotClosed(t *testing.T, readFromDst bool, writeToDst bool)
sessionID := uuid.New() sessionID := uuid.New()
cfdConn, originConn := net.Pipe() cfdConn, originConn := net.Pipe()
payload := testPayload(sessionID) payload := testPayload(sessionID)
transport := &mockQUICTransport{
reqChan: newDatagramChannel(100), mg, _ := newTestManager(100)
respChan: newDatagramChannel(100), session := mg.newSession(sessionID, cfdConn)
}
log := zerolog.Nop()
session := newSession(sessionID, transport, cfdConn, &log)
startTime := time.Now() startTime := time.Now()
activeUntil := startTime.Add(activeTime) activeUntil := startTime.Add(activeTime)
@ -184,7 +177,8 @@ func testActiveSessionNotClosed(t *testing.T, readFromDst bool, writeToDst bool)
func TestMarkActiveNotBlocking(t *testing.T) { func TestMarkActiveNotBlocking(t *testing.T) {
const concurrentCalls = 50 const concurrentCalls = 50
session := newSession(uuid.New(), nil, nil, nil) mg, _ := newTestManager(1)
session := mg.newSession(uuid.New(), nil)
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(concurrentCalls) wg.Add(concurrentCalls)
for i := 0; i < concurrentCalls; i++ { for i := 0; i < concurrentCalls; i++ {
@ -199,12 +193,9 @@ func TestMarkActiveNotBlocking(t *testing.T) {
func TestZeroBytePayload(t *testing.T) { func TestZeroBytePayload(t *testing.T) {
sessionID := uuid.New() sessionID := uuid.New()
cfdConn, originConn := net.Pipe() cfdConn, originConn := net.Pipe()
transport := &mockQUICTransport{
reqChan: newDatagramChannel(1), mg, transport := newTestManager(1)
respChan: newDatagramChannel(1), session := mg.newSession(sessionID, cfdConn)
}
log := zerolog.Nop()
session := newSession(sessionID, transport, cfdConn, &log)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
errGroup, ctx := errgroup.WithContext(ctx) errGroup, ctx := errgroup.WithContext(ctx)

2
go.mod
View File

@ -45,6 +45,7 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
zombiezen.com/go/capnproto2 v2.18.0+incompatible zombiezen.com/go/capnproto2 v2.18.0+incompatible
) )
@ -101,7 +102,6 @@ require (
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb // indirect google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb // indirect
google.golang.org/grpc v1.45.0 // indirect google.golang.org/grpc v1.45.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
) )
replace github.com/urfave/cli/v2 => github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d replace github.com/urfave/cli/v2 => github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d

3
go.sum
View File

@ -104,6 +104,7 @@ github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 h1:JLaf/iINcLyjwbtTsCJjc6rtlASgHeIJPrB6QmwURnA= github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 h1:JLaf/iINcLyjwbtTsCJjc6rtlASgHeIJPrB6QmwURnA=
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
@ -343,6 +344,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
@ -522,6 +524,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs= github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=

View File

@ -13,6 +13,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"github.com/cloudflare/cloudflared/carrier" "github.com/cloudflare/cloudflared/carrier"
"github.com/cloudflare/cloudflared/cfio" "github.com/cloudflare/cloudflared/cfio"
@ -74,7 +76,8 @@ func (p *Proxy) ProxyHTTP(
lbProbe := connection.IsLBProbeRequest(req) lbProbe := connection.IsLBProbeRequest(req)
p.appendTagHeaders(req) p.appendTagHeaders(req)
_, ruleSpan := tr.Tracer().Start(req.Context(), "ingress_match") _, ruleSpan := tr.Tracer().Start(req.Context(), "ingress_match",
trace.WithAttributes(attribute.String("req-host", req.Host)))
rule, ruleNum := p.ingressRules.FindMatchingRule(req.Host, req.URL.Path) rule, ruleNum := p.ingressRules.FindMatchingRule(req.Host, req.URL.Path)
logFields := logFields{ logFields := logFields{
cfRay: cfRay, cfRay: cfRay,
@ -103,7 +106,7 @@ func (p *Proxy) ProxyHTTP(
case ingress.HTTPOriginProxy: case ingress.HTTPOriginProxy:
if err := p.proxyHTTPRequest( if err := p.proxyHTTPRequest(
w, w,
req, tr,
originProxy, originProxy,
isWebsocket, isWebsocket,
rule.Config.DisableChunkedEncoding, rule.Config.DisableChunkedEncoding,
@ -175,15 +178,15 @@ func ruleField(ing ingress.Ingress, ruleNum int) (ruleID string, srv string) {
// ProxyHTTPRequest proxies requests of underlying type http and websocket to the origin service. // ProxyHTTPRequest proxies requests of underlying type http and websocket to the origin service.
func (p *Proxy) proxyHTTPRequest( func (p *Proxy) proxyHTTPRequest(
w connection.ResponseWriter, w connection.ResponseWriter,
req *http.Request, tr *tracing.TracedRequest,
httpService ingress.HTTPOriginProxy, httpService ingress.HTTPOriginProxy,
isWebsocket bool, isWebsocket bool,
disableChunkedEncoding bool, disableChunkedEncoding bool,
fields logFields, fields logFields,
) error { ) error {
roundTripReq := req roundTripReq := tr.Request
if isWebsocket { if isWebsocket {
roundTripReq = req.Clone(req.Context()) roundTripReq = tr.Clone(tr.Request.Context())
roundTripReq.Header.Set("Connection", "Upgrade") roundTripReq.Header.Set("Connection", "Upgrade")
roundTripReq.Header.Set("Upgrade", "websocket") roundTripReq.Header.Set("Upgrade", "websocket")
roundTripReq.Header.Set("Sec-Websocket-Version", "13") roundTripReq.Header.Set("Sec-Websocket-Version", "13")
@ -193,7 +196,7 @@ func (p *Proxy) proxyHTTPRequest(
// Support for WSGI Servers by switching transfer encoding from chunked to gzip/deflate // Support for WSGI Servers by switching transfer encoding from chunked to gzip/deflate
if disableChunkedEncoding { if disableChunkedEncoding {
roundTripReq.TransferEncoding = []string{"gzip", "deflate"} roundTripReq.TransferEncoding = []string{"gzip", "deflate"}
cLength, err := strconv.Atoi(req.Header.Get("Content-Length")) cLength, err := strconv.Atoi(tr.Request.Header.Get("Content-Length"))
if err == nil { if err == nil {
roundTripReq.ContentLength = int64(cLength) roundTripReq.ContentLength = int64(cLength)
} }
@ -207,12 +210,18 @@ func (p *Proxy) proxyHTTPRequest(
roundTripReq.Header.Set("User-Agent", "") roundTripReq.Header.Set("User-Agent", "")
} }
_, ttfbSpan := tr.Tracer().Start(tr.Context(), "ttfb_origin")
resp, err := httpService.RoundTrip(roundTripReq) resp, err := httpService.RoundTrip(roundTripReq)
if err != nil { if err != nil {
tracing.EndWithStatus(ttfbSpan, codes.Error, "")
return errors.Wrap(err, "Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared") return errors.Wrap(err, "Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared")
} }
tracing.EndWithStatus(ttfbSpan, codes.Ok, resp.Status)
defer resp.Body.Close() defer resp.Body.Close()
// Add spans to response header (if available)
tr.AddSpans(resp.Header, p.log)
err = w.WriteRespHeaders(resp.StatusCode, resp.Header) err = w.WriteRespHeaders(resp.StatusCode, resp.Header)
if err != nil { if err != nil {
return errors.Wrap(err, "Error writing response header") return errors.Wrap(err, "Error writing response header")
@ -227,7 +236,7 @@ func (p *Proxy) proxyHTTPRequest(
eyeballStream := &bidirectionalStream{ eyeballStream := &bidirectionalStream{
writer: w, writer: w,
reader: req.Body, reader: tr.Request.Body,
} }
websocket.Stream(eyeballStream, rwc, p.log) websocket.Stream(eyeballStream, rwc, p.log)

View File

@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/lucas-clemente/quic-go"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/cloudflare/cloudflared/connection" "github.com/cloudflare/cloudflared/connection"
@ -264,9 +265,9 @@ func (s *Supervisor) startFirstTunnel(
switch err.(type) { switch err.(type) {
case nil: case nil:
return return
// try the next address if it was a dialError(network problem) or // try the next address if it was a quic.IdleTimeoutError, dialError(network problem) or
// dupConnRegisterTunnelError // dupConnRegisterTunnelError
case edgediscovery.DialError, connection.DupConnRegisterTunnelError: case *quic.IdleTimeoutError, edgediscovery.DialError, connection.DupConnRegisterTunnelError:
edgeErrors++ edgeErrors++
default: default:
return return

View File

@ -12,11 +12,12 @@ import (
) )
const ( const (
maxTraceAmount = 20 MaxTraceAmount = 20
) )
var ( var (
errNoTraces = errors.New("no traces recorded to be exported") errNoTraces = errors.New("no traces recorded to be exported")
errNoopTracer = errors.New("noop tracer has no traces")
) )
type InMemoryClient interface { type InMemoryClient interface {
@ -45,7 +46,7 @@ func (mc *InMemoryOtlpClient) UploadTraces(_ context.Context, protoSpans []*trac
defer mc.mu.Unlock() defer mc.mu.Unlock()
// Catch to make sure too many traces aren't being added to response header. // Catch to make sure too many traces aren't being added to response header.
// Returning nil makes sure we don't fail to send the traces we already recorded. // Returning nil makes sure we don't fail to send the traces we already recorded.
if len(mc.spans)+len(protoSpans) > maxTraceAmount { if len(mc.spans)+len(protoSpans) > MaxTraceAmount {
return nil return nil
} }
mc.spans = append(mc.spans, protoSpans...) mc.spans = append(mc.spans, protoSpans...)
@ -86,5 +87,5 @@ func (mc *NoopOtlpClient) UploadTraces(_ context.Context, _ []*tracepb.ResourceS
// Spans always returns no traces error // Spans always returns no traces error
func (mc *NoopOtlpClient) Spans() (string, error) { func (mc *NoopOtlpClient) Spans() (string, error) {
return "", errNoTraces return "", errNoopTracer
} }

View File

@ -108,12 +108,12 @@ func TestSpansNil(t *testing.T) {
func TestSpansTooManySpans(t *testing.T) { func TestSpansTooManySpans(t *testing.T) {
client := &InMemoryOtlpClient{} client := &InMemoryOtlpClient{}
for i := 0; i < maxTraceAmount+1; i++ { for i := 0; i < MaxTraceAmount+1; i++ {
spans := createResourceSpans([]*tracepb.Span{createOtlpSpan(traceId)}) spans := createResourceSpans([]*tracepb.Span{createOtlpSpan(traceId)})
err := client.UploadTraces(context.Background(), spans) err := client.UploadTraces(context.Background(), spans)
assert.NoError(t, err) assert.NoError(t, err)
} }
assert.Len(t, client.spans, maxTraceAmount) assert.Len(t, client.spans, MaxTraceAmount)
_, err := client.Spans() _, err := client.Spans()
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@ -3,9 +3,13 @@ package tracing
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"net/http" "net/http"
"os"
"runtime"
otelContrib "go.opentelemetry.io/contrib/propagators/Jaeger" "github.com/rs/zerolog"
otelContrib "go.opentelemetry.io/contrib/propagators/jaeger"
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
@ -21,16 +25,26 @@ const (
service = "cloudflared" service = "cloudflared"
tracerInstrumentName = "origin" tracerInstrumentName = "origin"
tracerContextName = "cf-trace-id" TracerContextName = "cf-trace-id"
tracerContextNameOverride = "uber-trace-id" TracerContextNameOverride = "uber-trace-id"
IntCloudflaredTracingHeader = "cf-int-cloudflared-tracing"
) )
var ( var (
Http2TransportAttribute = trace.WithAttributes(TransportAttributeKey.String("http2")) CanonicalCloudflaredTracingHeader = http.CanonicalHeaderKey(IntCloudflaredTracingHeader)
QuicTransportAttribute = trace.WithAttributes(TransportAttributeKey.String("quic")) Http2TransportAttribute = trace.WithAttributes(transportAttributeKey.String("http2"))
QuicTransportAttribute = trace.WithAttributes(transportAttributeKey.String("quic"))
HostOSAttribute = semconv.HostTypeKey.String(runtime.GOOS)
HostArchAttribute = semconv.HostArchKey.String(runtime.GOARCH)
TransportAttributeKey = attribute.Key("transport") otelVersionAttribute attribute.KeyValue
TrafficAttributeKey = attribute.Key("traffic") hostnameAttribute attribute.KeyValue
cloudflaredVersionAttribute attribute.KeyValue
serviceAttribute = semconv.ServiceNameKey.String(service)
transportAttributeKey = attribute.Key("transport")
otelVersionAttributeKey = attribute.Key("jaeger.version")
errNoopTracerProvider = errors.New("noop tracer provider records no spans") errNoopTracerProvider = errors.New("noop tracer provider records no spans")
) )
@ -38,6 +52,14 @@ var (
func init() { func init() {
// Register the jaeger propagator globally. // Register the jaeger propagator globally.
otel.SetTextMapPropagator(otelContrib.Jaeger{}) otel.SetTextMapPropagator(otelContrib.Jaeger{})
otelVersionAttribute = otelVersionAttributeKey.String(fmt.Sprintf("go-otel-%s", otel.Version()))
if hostname, err := os.Hostname(); err == nil {
hostnameAttribute = attribute.String("hostname", hostname)
}
}
func Init(version string) {
cloudflaredVersionAttribute = semconv.ProcessRuntimeVersionKey.String(version)
} }
type TracedRequest struct { type TracedRequest struct {
@ -63,7 +85,12 @@ func NewTracedRequest(req *http.Request) *TracedRequest {
// Record information about this application in a Resource. // Record information about this application in a Resource.
tracesdk.WithResource(resource.NewWithAttributes( tracesdk.WithResource(resource.NewWithAttributes(
semconv.SchemaURL, semconv.SchemaURL,
semconv.ServiceNameKey.String(service), serviceAttribute,
otelVersionAttribute,
hostnameAttribute,
cloudflaredVersionAttribute,
HostOSAttribute,
HostArchAttribute,
)), )),
) )
@ -75,8 +102,26 @@ func (cft *TracedRequest) Tracer() trace.Tracer {
} }
// Spans returns the spans as base64 encoded protobuf otlp traces. // Spans returns the spans as base64 encoded protobuf otlp traces.
func (cft *TracedRequest) Spans() (string, error) { func (cft *TracedRequest) AddSpans(headers http.Header, log *zerolog.Logger) {
return cft.exporter.Spans() enc, err := cft.exporter.Spans()
switch err {
case nil:
break
case errNoTraces:
log.Error().Err(err).Msgf("expected traces to be available")
return
case errNoopTracer:
return // noop tracer has no traces
default:
log.Error().Err(err)
return
}
// No need to add header if no traces
if enc == "" {
log.Error().Msgf("no traces provided and no error from exporter")
return
}
headers[CanonicalCloudflaredTracingHeader] = []string{enc}
} }
// EndWithStatus will set a status for the span and then end it. // EndWithStatus will set a status for the span and then end it.
@ -88,27 +133,28 @@ func EndWithStatus(span trace.Span, code codes.Code, status string) {
span.End() span.End()
} }
// extractTrace attempts to check for a cf-trace-id from a request header. // extractTrace attempts to check for a cf-trace-id from a request and return the
// trace context with the provided http.Request.
func extractTrace(req *http.Request) (context.Context, bool) { func extractTrace(req *http.Request) (context.Context, bool) {
// Only add tracing for requests with appropriately tagged headers // Only add tracing for requests with appropriately tagged headers
remoteTraces := req.Header.Values(tracerContextName) remoteTraces := req.Header.Values(TracerContextName)
if len(remoteTraces) <= 0 { if len(remoteTraces) <= 0 {
// Strip the cf-trace-id header // Strip the cf-trace-id header
req.Header.Del(tracerContextName) req.Header.Del(TracerContextName)
return nil, false return nil, false
} }
traceHeader := make(map[string]string, 1) traceHeader := map[string]string{}
for _, t := range remoteTraces { for _, t := range remoteTraces {
// Override the 'cf-trace-id' as 'uber-trace-id' so the jaeger propagator can extract it. // Override the 'cf-trace-id' as 'uber-trace-id' so the jaeger propagator can extract it.
// Last entry wins if multiple provided // Last entry wins if multiple provided
traceHeader[tracerContextNameOverride] = t traceHeader[TracerContextNameOverride] = t
} }
// Strip the cf-trace-id header // Strip the cf-trace-id header
req.Header.Del(tracerContextName) req.Header.Del(TracerContextName)
if traceHeader[tracerContextNameOverride] == "" { if traceHeader[TracerContextNameOverride] == "" {
return nil, false return nil, false
} }
remoteCtx := otel.GetTextMapPropagator().Extract(req.Context(), propagation.MapCarrier(traceHeader)) remoteCtx := otel.GetTextMapPropagator().Extract(req.Context(), propagation.MapCarrier(traceHeader))

View File

@ -12,7 +12,7 @@ import (
func TestNewCfTracer(t *testing.T) { func TestNewCfTracer(t *testing.T) {
req := httptest.NewRequest("GET", "http://localhost", nil) req := httptest.NewRequest("GET", "http://localhost", nil)
req.Header.Add(tracerContextName, "14cb070dde8e51fc5ae8514e69ba42ca:b38f1bf5eae406f3:0:1") req.Header.Add(TracerContextName, "14cb070dde8e51fc5ae8514e69ba42ca:b38f1bf5eae406f3:0:1")
tr := NewTracedRequest(req) tr := NewTracedRequest(req)
assert.NotNil(t, tr) assert.NotNil(t, tr)
assert.IsType(t, tracesdk.NewTracerProvider(), tr.TracerProvider) assert.IsType(t, tracesdk.NewTracerProvider(), tr.TracerProvider)
@ -21,8 +21,8 @@ func TestNewCfTracer(t *testing.T) {
func TestNewCfTracerMultiple(t *testing.T) { func TestNewCfTracerMultiple(t *testing.T) {
req := httptest.NewRequest("GET", "http://localhost", nil) req := httptest.NewRequest("GET", "http://localhost", nil)
req.Header.Add(tracerContextName, "1241ce3ecdefc68854e8514e69ba42ca:b38f1bf5eae406f3:0:1") req.Header.Add(TracerContextName, "1241ce3ecdefc68854e8514e69ba42ca:b38f1bf5eae406f3:0:1")
req.Header.Add(tracerContextName, "14cb070dde8e51fc5ae8514e69ba42ca:b38f1bf5eae406f3:0:1") req.Header.Add(TracerContextName, "14cb070dde8e51fc5ae8514e69ba42ca:b38f1bf5eae406f3:0:1")
tr := NewTracedRequest(req) tr := NewTracedRequest(req)
assert.NotNil(t, tr) assert.NotNil(t, tr)
assert.IsType(t, tracesdk.NewTracerProvider(), tr.TracerProvider) assert.IsType(t, tracesdk.NewTracerProvider(), tr.TracerProvider)
@ -31,7 +31,7 @@ func TestNewCfTracerMultiple(t *testing.T) {
func TestNewCfTracerNilHeader(t *testing.T) { func TestNewCfTracerNilHeader(t *testing.T) {
req := httptest.NewRequest("GET", "http://localhost", nil) req := httptest.NewRequest("GET", "http://localhost", nil)
req.Header[http.CanonicalHeaderKey(tracerContextName)] = nil req.Header[http.CanonicalHeaderKey(TracerContextName)] = nil
tr := NewTracedRequest(req) tr := NewTracedRequest(req)
assert.NotNil(t, tr) assert.NotNil(t, tr)
assert.IsType(t, trace.NewNoopTracerProvider(), tr.TracerProvider) assert.IsType(t, trace.NewNoopTracerProvider(), tr.TracerProvider)
@ -41,7 +41,7 @@ func TestNewCfTracerNilHeader(t *testing.T) {
func TestNewCfTracerInvalidHeaders(t *testing.T) { func TestNewCfTracerInvalidHeaders(t *testing.T) {
req := httptest.NewRequest("GET", "http://localhost", nil) req := httptest.NewRequest("GET", "http://localhost", nil)
for _, test := range [][]string{nil, {""}} { for _, test := range [][]string{nil, {""}} {
req.Header[http.CanonicalHeaderKey(tracerContextName)] = test req.Header[http.CanonicalHeaderKey(TracerContextName)] = test
tr := NewTracedRequest(req) tr := NewTracedRequest(req)
assert.NotNil(t, tr) assert.NotNil(t, tr)
assert.IsType(t, trace.NewNoopTracerProvider(), tr.TracerProvider) assert.IsType(t, trace.NewNoopTracerProvider(), tr.TracerProvider)

View File

@ -18,6 +18,7 @@ import (
type RegistrationServer interface { type RegistrationServer interface {
RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error)
UnregisterConnection(ctx context.Context) UnregisterConnection(ctx context.Context)
UpdateLocalConfiguration(ctx context.Context, config []byte) error
} }
type RegistrationServer_PogsImpl struct { type RegistrationServer_PogsImpl struct {
@ -88,6 +89,17 @@ func (i RegistrationServer_PogsImpl) UnregisterConnection(p tunnelrpc.Registrati
return nil return nil
} }
func (i RegistrationServer_PogsImpl) UpdateLocalConfiguration(c tunnelrpc.RegistrationServer_updateLocalConfiguration) error {
server.Ack(c.Options)
configBytes, err := c.Params.Config()
if err != nil {
return err
}
return i.impl.UpdateLocalConfiguration(c.Ctx, configBytes)
}
type RegistrationServer_PogsClient struct { type RegistrationServer_PogsClient struct {
Client capnp.Client Client capnp.Client
Conn *rpc.Conn Conn *rpc.Conn
@ -212,8 +224,9 @@ func (a *TunnelAuth) UnmarshalCapnproto(s tunnelrpc.TunnelAuth) error {
} }
type ConnectionDetails struct { type ConnectionDetails struct {
UUID uuid.UUID UUID uuid.UUID
Location string Location string
TunnelIsRemotelyManaged bool
} }
func (details *ConnectionDetails) MarshalCapnproto(s tunnelrpc.ConnectionDetails) error { func (details *ConnectionDetails) MarshalCapnproto(s tunnelrpc.ConnectionDetails) error {
@ -223,6 +236,7 @@ func (details *ConnectionDetails) MarshalCapnproto(s tunnelrpc.ConnectionDetails
if err := s.SetLocationName(details.Location); err != nil { if err := s.SetLocationName(details.Location); err != nil {
return err return err
} }
s.SetTunnelIsRemotelyManaged(details.TunnelIsRemotelyManaged)
return nil return nil
} }
@ -240,6 +254,7 @@ func (details *ConnectionDetails) UnmarshalCapnproto(s tunnelrpc.ConnectionDetai
if err != nil { if err != nil {
return err return err
} }
details.TunnelIsRemotelyManaged = s.TunnelIsRemotelyManaged()
return err return err
} }

View File

@ -129,6 +129,11 @@ type testConnectionRegistrationServer struct {
err error err error
} }
func (t *testConnectionRegistrationServer) UpdateLocalConfiguration(ctx context.Context, config []byte) error {
// do nothing at this point
return nil
}
func (t *testConnectionRegistrationServer) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) { func (t *testConnectionRegistrationServer) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) {
if auth.AccountTag != testAccountTag { if auth.AccountTag != testAccountTag {
panic("bad account tag: " + auth.AccountTag) panic("bad account tag: " + auth.AccountTag)

View File

@ -121,6 +121,8 @@ struct ConnectionDetails {
uuid @0 :Data; uuid @0 :Data;
# airport code of the colo where this connection landed # airport code of the colo where this connection landed
locationName @1 :Text; locationName @1 :Text;
# tells if the tunnel is remotely managed
tunnelIsRemotelyManaged @2: Bool;
} }
struct TunnelAuth { struct TunnelAuth {
@ -131,6 +133,7 @@ struct TunnelAuth {
interface RegistrationServer { interface RegistrationServer {
registerConnection @0 (auth :TunnelAuth, tunnelId :Data, connIndex :UInt8, options :ConnectionOptions) -> (result :ConnectionResponse); registerConnection @0 (auth :TunnelAuth, tunnelId :Data, connIndex :UInt8, options :ConnectionOptions) -> (result :ConnectionResponse);
unregisterConnection @1 () -> (); unregisterConnection @1 () -> ();
updateLocalConfiguration @2 (config :Data) -> ();
} }
interface TunnelServer extends (RegistrationServer) { interface TunnelServer extends (RegistrationServer) {

View File

@ -1410,12 +1410,12 @@ type ConnectionDetails struct{ capnp.Struct }
const ConnectionDetails_TypeID = 0xb5f39f082b9ac18a const ConnectionDetails_TypeID = 0xb5f39f082b9ac18a
func NewConnectionDetails(s *capnp.Segment) (ConnectionDetails, error) { func NewConnectionDetails(s *capnp.Segment) (ConnectionDetails, error) {
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}) st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 2})
return ConnectionDetails{st}, err return ConnectionDetails{st}, err
} }
func NewRootConnectionDetails(s *capnp.Segment) (ConnectionDetails, error) { func NewRootConnectionDetails(s *capnp.Segment) (ConnectionDetails, error) {
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}) st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 2})
return ConnectionDetails{st}, err return ConnectionDetails{st}, err
} }
@ -1462,12 +1462,20 @@ func (s ConnectionDetails) SetLocationName(v string) error {
return s.Struct.SetText(1, v) return s.Struct.SetText(1, v)
} }
func (s ConnectionDetails) TunnelIsRemotelyManaged() bool {
return s.Struct.Bit(0)
}
func (s ConnectionDetails) SetTunnelIsRemotelyManaged(v bool) {
s.Struct.SetBit(0, v)
}
// ConnectionDetails_List is a list of ConnectionDetails. // ConnectionDetails_List is a list of ConnectionDetails.
type ConnectionDetails_List struct{ capnp.List } type ConnectionDetails_List struct{ capnp.List }
// NewConnectionDetails creates a new list of ConnectionDetails. // NewConnectionDetails creates a new list of ConnectionDetails.
func NewConnectionDetails_List(s *capnp.Segment, sz int32) (ConnectionDetails_List, error) { func NewConnectionDetails_List(s *capnp.Segment, sz int32) (ConnectionDetails_List, error) {
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}, sz) l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 8, PointerCount: 2}, sz)
return ConnectionDetails_List{l}, err return ConnectionDetails_List{l}, err
} }
@ -1621,11 +1629,35 @@ func (c RegistrationServer) UnregisterConnection(ctx context.Context, params fun
} }
return RegistrationServer_unregisterConnection_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))} return RegistrationServer_unregisterConnection_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))}
} }
func (c RegistrationServer) UpdateLocalConfiguration(ctx context.Context, params func(RegistrationServer_updateLocalConfiguration_Params) error, opts ...capnp.CallOption) RegistrationServer_updateLocalConfiguration_Results_Promise {
if c.Client == nil {
return RegistrationServer_updateLocalConfiguration_Results_Promise{Pipeline: capnp.NewPipeline(capnp.ErrorAnswer(capnp.ErrNullClient))}
}
call := &capnp.Call{
Ctx: ctx,
Method: capnp.Method{
InterfaceID: 0xf71695ec7fe85497,
MethodID: 2,
InterfaceName: "tunnelrpc/tunnelrpc.capnp:RegistrationServer",
MethodName: "updateLocalConfiguration",
},
Options: capnp.NewCallOptions(opts),
}
if params != nil {
call.ParamsSize = capnp.ObjectSize{DataSize: 0, PointerCount: 1}
call.ParamsFunc = func(s capnp.Struct) error {
return params(RegistrationServer_updateLocalConfiguration_Params{Struct: s})
}
}
return RegistrationServer_updateLocalConfiguration_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))}
}
type RegistrationServer_Server interface { type RegistrationServer_Server interface {
RegisterConnection(RegistrationServer_registerConnection) error RegisterConnection(RegistrationServer_registerConnection) error
UnregisterConnection(RegistrationServer_unregisterConnection) error UnregisterConnection(RegistrationServer_unregisterConnection) error
UpdateLocalConfiguration(RegistrationServer_updateLocalConfiguration) error
} }
func RegistrationServer_ServerToClient(s RegistrationServer_Server) RegistrationServer { func RegistrationServer_ServerToClient(s RegistrationServer_Server) RegistrationServer {
@ -1635,7 +1667,7 @@ func RegistrationServer_ServerToClient(s RegistrationServer_Server) Registration
func RegistrationServer_Methods(methods []server.Method, s RegistrationServer_Server) []server.Method { func RegistrationServer_Methods(methods []server.Method, s RegistrationServer_Server) []server.Method {
if cap(methods) == 0 { if cap(methods) == 0 {
methods = make([]server.Method, 0, 2) methods = make([]server.Method, 0, 3)
} }
methods = append(methods, server.Method{ methods = append(methods, server.Method{
@ -1666,6 +1698,20 @@ func RegistrationServer_Methods(methods []server.Method, s RegistrationServer_Se
ResultsSize: capnp.ObjectSize{DataSize: 0, PointerCount: 0}, ResultsSize: capnp.ObjectSize{DataSize: 0, PointerCount: 0},
}) })
methods = append(methods, server.Method{
Method: capnp.Method{
InterfaceID: 0xf71695ec7fe85497,
MethodID: 2,
InterfaceName: "tunnelrpc/tunnelrpc.capnp:RegistrationServer",
MethodName: "updateLocalConfiguration",
},
Impl: func(c context.Context, opts capnp.CallOptions, p, r capnp.Struct) error {
call := RegistrationServer_updateLocalConfiguration{c, opts, RegistrationServer_updateLocalConfiguration_Params{Struct: p}, RegistrationServer_updateLocalConfiguration_Results{Struct: r}}
return s.UpdateLocalConfiguration(call)
},
ResultsSize: capnp.ObjectSize{DataSize: 0, PointerCount: 0},
})
return methods return methods
} }
@ -1685,6 +1731,14 @@ type RegistrationServer_unregisterConnection struct {
Results RegistrationServer_unregisterConnection_Results Results RegistrationServer_unregisterConnection_Results
} }
// RegistrationServer_updateLocalConfiguration holds the arguments for a server call to RegistrationServer.updateLocalConfiguration.
type RegistrationServer_updateLocalConfiguration struct {
Ctx context.Context
Options capnp.CallOptions
Params RegistrationServer_updateLocalConfiguration_Params
Results RegistrationServer_updateLocalConfiguration_Results
}
type RegistrationServer_registerConnection_Params struct{ capnp.Struct } type RegistrationServer_registerConnection_Params struct{ capnp.Struct }
// RegistrationServer_registerConnection_Params_TypeID is the unique identifier for the type RegistrationServer_registerConnection_Params. // RegistrationServer_registerConnection_Params_TypeID is the unique identifier for the type RegistrationServer_registerConnection_Params.
@ -2014,6 +2068,130 @@ func (p RegistrationServer_unregisterConnection_Results_Promise) Struct() (Regis
return RegistrationServer_unregisterConnection_Results{s}, err return RegistrationServer_unregisterConnection_Results{s}, err
} }
type RegistrationServer_updateLocalConfiguration_Params struct{ capnp.Struct }
// RegistrationServer_updateLocalConfiguration_Params_TypeID is the unique identifier for the type RegistrationServer_updateLocalConfiguration_Params.
const RegistrationServer_updateLocalConfiguration_Params_TypeID = 0xc5d6e311876a3604
func NewRegistrationServer_updateLocalConfiguration_Params(s *capnp.Segment) (RegistrationServer_updateLocalConfiguration_Params, error) {
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
return RegistrationServer_updateLocalConfiguration_Params{st}, err
}
func NewRootRegistrationServer_updateLocalConfiguration_Params(s *capnp.Segment) (RegistrationServer_updateLocalConfiguration_Params, error) {
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
return RegistrationServer_updateLocalConfiguration_Params{st}, err
}
func ReadRootRegistrationServer_updateLocalConfiguration_Params(msg *capnp.Message) (RegistrationServer_updateLocalConfiguration_Params, error) {
root, err := msg.RootPtr()
return RegistrationServer_updateLocalConfiguration_Params{root.Struct()}, err
}
func (s RegistrationServer_updateLocalConfiguration_Params) String() string {
str, _ := text.Marshal(0xc5d6e311876a3604, s.Struct)
return str
}
func (s RegistrationServer_updateLocalConfiguration_Params) Config() ([]byte, error) {
p, err := s.Struct.Ptr(0)
return []byte(p.Data()), err
}
func (s RegistrationServer_updateLocalConfiguration_Params) HasConfig() bool {
p, err := s.Struct.Ptr(0)
return p.IsValid() || err != nil
}
func (s RegistrationServer_updateLocalConfiguration_Params) SetConfig(v []byte) error {
return s.Struct.SetData(0, v)
}
// RegistrationServer_updateLocalConfiguration_Params_List is a list of RegistrationServer_updateLocalConfiguration_Params.
type RegistrationServer_updateLocalConfiguration_Params_List struct{ capnp.List }
// NewRegistrationServer_updateLocalConfiguration_Params creates a new list of RegistrationServer_updateLocalConfiguration_Params.
func NewRegistrationServer_updateLocalConfiguration_Params_List(s *capnp.Segment, sz int32) (RegistrationServer_updateLocalConfiguration_Params_List, error) {
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz)
return RegistrationServer_updateLocalConfiguration_Params_List{l}, err
}
func (s RegistrationServer_updateLocalConfiguration_Params_List) At(i int) RegistrationServer_updateLocalConfiguration_Params {
return RegistrationServer_updateLocalConfiguration_Params{s.List.Struct(i)}
}
func (s RegistrationServer_updateLocalConfiguration_Params_List) Set(i int, v RegistrationServer_updateLocalConfiguration_Params) error {
return s.List.SetStruct(i, v.Struct)
}
func (s RegistrationServer_updateLocalConfiguration_Params_List) String() string {
str, _ := text.MarshalList(0xc5d6e311876a3604, s.List)
return str
}
// RegistrationServer_updateLocalConfiguration_Params_Promise is a wrapper for a RegistrationServer_updateLocalConfiguration_Params promised by a client call.
type RegistrationServer_updateLocalConfiguration_Params_Promise struct{ *capnp.Pipeline }
func (p RegistrationServer_updateLocalConfiguration_Params_Promise) Struct() (RegistrationServer_updateLocalConfiguration_Params, error) {
s, err := p.Pipeline.Struct()
return RegistrationServer_updateLocalConfiguration_Params{s}, err
}
type RegistrationServer_updateLocalConfiguration_Results struct{ capnp.Struct }
// RegistrationServer_updateLocalConfiguration_Results_TypeID is the unique identifier for the type RegistrationServer_updateLocalConfiguration_Results.
const RegistrationServer_updateLocalConfiguration_Results_TypeID = 0xe5ceae5d6897d7be
func NewRegistrationServer_updateLocalConfiguration_Results(s *capnp.Segment) (RegistrationServer_updateLocalConfiguration_Results, error) {
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
return RegistrationServer_updateLocalConfiguration_Results{st}, err
}
func NewRootRegistrationServer_updateLocalConfiguration_Results(s *capnp.Segment) (RegistrationServer_updateLocalConfiguration_Results, error) {
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
return RegistrationServer_updateLocalConfiguration_Results{st}, err
}
func ReadRootRegistrationServer_updateLocalConfiguration_Results(msg *capnp.Message) (RegistrationServer_updateLocalConfiguration_Results, error) {
root, err := msg.RootPtr()
return RegistrationServer_updateLocalConfiguration_Results{root.Struct()}, err
}
func (s RegistrationServer_updateLocalConfiguration_Results) String() string {
str, _ := text.Marshal(0xe5ceae5d6897d7be, s.Struct)
return str
}
// RegistrationServer_updateLocalConfiguration_Results_List is a list of RegistrationServer_updateLocalConfiguration_Results.
type RegistrationServer_updateLocalConfiguration_Results_List struct{ capnp.List }
// NewRegistrationServer_updateLocalConfiguration_Results creates a new list of RegistrationServer_updateLocalConfiguration_Results.
func NewRegistrationServer_updateLocalConfiguration_Results_List(s *capnp.Segment, sz int32) (RegistrationServer_updateLocalConfiguration_Results_List, error) {
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0}, sz)
return RegistrationServer_updateLocalConfiguration_Results_List{l}, err
}
func (s RegistrationServer_updateLocalConfiguration_Results_List) At(i int) RegistrationServer_updateLocalConfiguration_Results {
return RegistrationServer_updateLocalConfiguration_Results{s.List.Struct(i)}
}
func (s RegistrationServer_updateLocalConfiguration_Results_List) Set(i int, v RegistrationServer_updateLocalConfiguration_Results) error {
return s.List.SetStruct(i, v.Struct)
}
func (s RegistrationServer_updateLocalConfiguration_Results_List) String() string {
str, _ := text.MarshalList(0xe5ceae5d6897d7be, s.List)
return str
}
// RegistrationServer_updateLocalConfiguration_Results_Promise is a wrapper for a RegistrationServer_updateLocalConfiguration_Results promised by a client call.
type RegistrationServer_updateLocalConfiguration_Results_Promise struct{ *capnp.Pipeline }
func (p RegistrationServer_updateLocalConfiguration_Results_Promise) Struct() (RegistrationServer_updateLocalConfiguration_Results, error) {
s, err := p.Pipeline.Struct()
return RegistrationServer_updateLocalConfiguration_Results{s}, err
}
type TunnelServer struct{ Client capnp.Client } type TunnelServer struct{ Client capnp.Client }
// TunnelServer_TypeID is the unique identifier for the type TunnelServer. // TunnelServer_TypeID is the unique identifier for the type TunnelServer.
@ -2181,6 +2359,28 @@ func (c TunnelServer) UnregisterConnection(ctx context.Context, params func(Regi
} }
return RegistrationServer_unregisterConnection_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))} return RegistrationServer_unregisterConnection_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))}
} }
func (c TunnelServer) UpdateLocalConfiguration(ctx context.Context, params func(RegistrationServer_updateLocalConfiguration_Params) error, opts ...capnp.CallOption) RegistrationServer_updateLocalConfiguration_Results_Promise {
if c.Client == nil {
return RegistrationServer_updateLocalConfiguration_Results_Promise{Pipeline: capnp.NewPipeline(capnp.ErrorAnswer(capnp.ErrNullClient))}
}
call := &capnp.Call{
Ctx: ctx,
Method: capnp.Method{
InterfaceID: 0xf71695ec7fe85497,
MethodID: 2,
InterfaceName: "tunnelrpc/tunnelrpc.capnp:RegistrationServer",
MethodName: "updateLocalConfiguration",
},
Options: capnp.NewCallOptions(opts),
}
if params != nil {
call.ParamsSize = capnp.ObjectSize{DataSize: 0, PointerCount: 1}
call.ParamsFunc = func(s capnp.Struct) error {
return params(RegistrationServer_updateLocalConfiguration_Params{Struct: s})
}
}
return RegistrationServer_updateLocalConfiguration_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))}
}
type TunnelServer_Server interface { type TunnelServer_Server interface {
RegisterTunnel(TunnelServer_registerTunnel) error RegisterTunnel(TunnelServer_registerTunnel) error
@ -2198,6 +2398,8 @@ type TunnelServer_Server interface {
RegisterConnection(RegistrationServer_registerConnection) error RegisterConnection(RegistrationServer_registerConnection) error
UnregisterConnection(RegistrationServer_unregisterConnection) error UnregisterConnection(RegistrationServer_unregisterConnection) error
UpdateLocalConfiguration(RegistrationServer_updateLocalConfiguration) error
} }
func TunnelServer_ServerToClient(s TunnelServer_Server) TunnelServer { func TunnelServer_ServerToClient(s TunnelServer_Server) TunnelServer {
@ -2207,7 +2409,7 @@ func TunnelServer_ServerToClient(s TunnelServer_Server) TunnelServer {
func TunnelServer_Methods(methods []server.Method, s TunnelServer_Server) []server.Method { func TunnelServer_Methods(methods []server.Method, s TunnelServer_Server) []server.Method {
if cap(methods) == 0 { if cap(methods) == 0 {
methods = make([]server.Method, 0, 8) methods = make([]server.Method, 0, 9)
} }
methods = append(methods, server.Method{ methods = append(methods, server.Method{
@ -2322,6 +2524,20 @@ func TunnelServer_Methods(methods []server.Method, s TunnelServer_Server) []serv
ResultsSize: capnp.ObjectSize{DataSize: 0, PointerCount: 0}, ResultsSize: capnp.ObjectSize{DataSize: 0, PointerCount: 0},
}) })
methods = append(methods, server.Method{
Method: capnp.Method{
InterfaceID: 0xf71695ec7fe85497,
MethodID: 2,
InterfaceName: "tunnelrpc/tunnelrpc.capnp:RegistrationServer",
MethodName: "updateLocalConfiguration",
},
Impl: func(c context.Context, opts capnp.CallOptions, p, r capnp.Struct) error {
call := RegistrationServer_updateLocalConfiguration{c, opts, RegistrationServer_updateLocalConfiguration_Params{Struct: p}, RegistrationServer_updateLocalConfiguration_Results{Struct: r}}
return s.UpdateLocalConfiguration(call)
},
ResultsSize: capnp.ObjectSize{DataSize: 0, PointerCount: 0},
})
return methods return methods
} }
@ -4317,224 +4533,231 @@ func CloudflaredServer_Methods(methods []server.Method, s CloudflaredServer_Serv
return methods return methods
} }
const schema_db8274f9144abc7e = "x\xda\xccZ{t\x14\xe7u\xbfwfW#\x81V" + const schema_db8274f9144abc7e = "x\xda\xccZ}t\x1c\xd5u\xbfwfW#\x19\xad" +
"\xab\xf1\xac\xd1\x03T\xb5:P\x179\xd8\x06Jk\xab" + "G\xc3,\x96\xb5\xc7B\x8d\x8e]j'\x06d\xd7)" +
"9\xd1\xc3\x12\xb1d\x03\x9a]\x94\xe3cC\x8eG\xbb" + "u\xd3H2\xb2\x83\x84?4\xbbV\x0e1&\x87\xd1" +
"\x9f\xa4Qwg\x96\x99Y\x19\x11\x130\x01c\xfb\xb8" + "\xee\x934\xea\xee\xcc23+l\x07\xe2\x0fl\x0c\x1c" +
"\x8eq\xc0\xb1Ih0.\xed\x01\xdb\xad\x89\xdd\xa6\xee" + "B0\xb1\xf9pBc\x9b\xd2\x9e\x98$\x85`\x9a\xba" +
"1\xa7\xa6\xcd\xabq\xc0&\x87\xf4\x90@\x9a&\x84>" + "\x07Z\x9c\x86\x10Cpp\x0e\xa4&\x86\xa6\x89\xe3\xb6" +
"8\xb8\xae14\x876\xf1\xf4\xdc\x99\x9d\x87v\x17\x09" + "\xf8\x98R\x0cn\x8e\xdb\x98\xe9\xb93;\x1f\xda]$" +
"\x8c\xff\xc8\x7f\xab;\xdf\xe3\xde\xdf\xf7\xbb\x8f\xef~\xba" + "+\xce\x1f\xf9ou\xe7\xbe\xf7\xee\xfb\xbd\xdf\xfdx\xf7" +
"\xed\xe6\x9a.nq\xf4\xed:\x00\xf9\xa5h\x95\xcd\xda" + "\xe9\xea;\x1a\xba\xb8\x8e\xf8F\x11@9\x10\xafs\xd8" +
"\x7f\xb0a\xef\x82\x7f\xdc\x02r3\xa2\xfd\xf97\x06\x12" + "\xbc\x9fl\xd83\xe7\x9f\xb7\x80\x92Bt\xbe\xf8l_" +
"\x97\xad-\xa7 \xca\x0b\x00KW\x08\x1bPR\x04\x01" + "\xf2\x9c\xbd\xe58\xc4y\x01`\xe1\xe3\xc2\x06\x94\x0f\x0a" +
"@Z+\xfc;\xa0\xfd\xc8\x9cW\xbe\xb6\xbfo\xe7\x17" + "\x02\x80\xfc\x8c\xf0\x1f\x80\xce\x9d3\x9e\xfc\xfa\xe3Kw" +
"@l\xe6\x83\xc1\x80K\xbb\xab\x07P\x1a\xaa\xa6\x91r" + "\xde\x01R\x8a\x0f\x95\x01\x17>R\xdf\x87\xf2\xb7\xeaI" +
"\xf5v\xe9\x10\xfd\xb2\xef\x16o\xbd?\xf1\xce1\x1a\x1d" + "\xf3\x1b\xf5\xdb\xe5\x86\x06\x01\xc0\xb9^\xba\xea\xc6\xe4\xab" +
"^:BK?W\xdd\x8e\xd2\x01g\xc2\xfejZ\xfa" + "GH;:u\x8c\xa6~\xaf~\x1e\xcaHj\xf2\xf9" +
"\x93\xb9\xb7\xf7\xfd\xc1\xae\xb7\xb6\x82\xd8\xccMYzG" + "z\x9a\xfaS\x85\x1f\xef\xfb\xe4\xae\x97\xb7\x82\x94\xe2\xc6" +
"\xcd\x06\x94\xf6\xd7\xd0\xc8\xe7kV\x01\xda\x1f\xecl|" + "M\xfdv\xc3\x06\x94\xcf\xbb\x9a\xe7\x1aV\x01:\xef\xef" +
"\xf1\xf9c\xdf\xdd\x06\xe2M\x08EM_\xaf\xf91\x02" + "\x9c\xf9\xc4\xde#?\xdc\x06\xd2\x15\x08eK\xa5i?" +
"JGk\xfe\x0a\xd0>z\xe9\xfe\x8b\xaf}{\xd9#" + "C@y\xce\xb4\xbf\x05t^9{\xe3\x07\x07~\xb0" +
" .\xa4\x01H\x03r\xb3\xda8@i\xdb\xacN@" + "\xe8N\x90\xe6\x92\x02\x92\xc2\x0b\xd3\xda9@\xf9\xadi" +
"\xfb\xdc\xf9\xff\xdb\xfe\xb9\x85+\x9f\x02y!r\x00Q" + "\x9d\x80\xce\xa9\xd3\xff\xb7\xfd\x0bsW\xde\x0f\xca\\\xe4" +
"\x8eF\xec\x9f\xd5L#\x0e\xcf\"m:\x97\x1f}\xbd" + "\x00\xe2\x1ci\x9c\x9f\x96\"\x8d\xcb.!k:\x97\xbd" +
"y\xe93;KTw\x06\xee\x99\xdd\x8e\xd2\xcb\xb3I" + "r0\xb5\xf0\xc1\x9d\x15\xa6\xbb\x8ag/\x99\x87r\xbc" +
"\xa1\x03\xb3\x1f\x04\xb4?\xf5\x87\xaf>\xd9\xfb\xcc\xe6]" + "\x91\x0c\xc2\xc6[\x01\x9dO\xff\xc9\xd3\xf7\xf5<\xb8i" +
" \xde\xea\xef\x17\xab\xbd\x8fV[XK\xfb\xfdO\xdd" + "\x17HW\x05\xeb\xb1\xc654\xdb\xe6FZ\xef\x7f\xa6" +
"W\x8e\x15\xee\xfc\xc63E\x85\x9cU\xfak\xdbi\x80" + "\x7f\xf5H\xe9\xda\xef>X6\xc8\x9deo\xe3<R" +
"RK+\xb4M,x\xe0\x1f\xbe\xf5\xea\x97A^\x84" + "8\xe8\xce\xd0>6\xe7\xe6\xef\xbd\xf0\xf4C\xa0\xccG" +
"h\x9f\x1e\xbe\xf9\x87\xfc\x9e\x83\xa7`\x08\x05\xd2o\xe9" + "t\xde\x1c\xfc\xf8\xeb\xfc\xa3\xfb\x8f\xc3\x00\x0ad\xdf\xc2" +
"\x91\xda}d\xddqg\xec\xdb\x9fx\xe3\xef\x9ezu" + "\x96\xc4>\xda\xdd\xdc\x04\xe9\xfe\xf8\x13\xcf\xfe\xc3\xfdO" +
"\xfbW@\xbe\x09\x11\xc0AsY\xec\x7fi@\x7f\x8c" + "o\xff*(W \x02\xb8h~)\xf1\xbf\xa4\xb07" +
"v\xdby\xf2\xf0\xca\xdc\x8e\xdd\xfb\\|\x9c\xef\xebb" + "A\xab\xed<\xf6\xdc\xca\xc2\x8e\xdd\xfb<|\xdc\xef\x87" +
"\x1c\x07\x11{k\xff/sC/\xa4^(\"\x17\xa5" + "\x13\x1c\x071gk\xef\xaf\x0b\x03\x8fe\x1e+#\x17" +
"O,v\x01\x01\x97N\xc6Z\x11\xd0^\xf6\xe3\xb3\xab" + "\xa7O\xcf%\xce \xe0\xc2\xa3\x896\x04t\x16\xfd\xec" +
"V|}\xe4/Bsw\xd5m\xa0\xb9\xdbG.\x1c" + "\xe4\xaa\x15\xdf\x19\xfa\x9b\xc8\xd8w\xa6o\xa0\xb1\xdb\x87" +
"\xa9O\xe6^,A\xc41vG\xddA\x94\x0e\xd49" + "\xce\x1cjJ\x17\x9e\xa8@\xc4\xdd\xec\xdb\xd3\xf7\xa3\x8c" +
"\x87YG*\xbc\xfc[w\xd7\xac?\xbb\xfc\x15\x10\x17" + "\xa2{\x98\xd3\xc9\x84o]~}\xc3\xba\x93\xcb\x9e\x04" +
"y\xcb|\xab.I\xcbL|\xef\x85\xdf]\xf0\xbd\x07" + "i\xbe?M\xab\x98\xa6i\xc6^z\xec\x0f\xe7\xbct" +
"\x0f\x81|+\xfa`\x1d\xa1o(\xfd\xa4\x8e\xec\x8b\x9c" + "\xebS\xa0\\\x85\x01X-\xf4\x0d\xe5E\"\xed/v" +
"Zp\xf0\xf0O\x9f|\xad\x8ccw\xc47\xa0\xb4\"" + "|\xce\xfe\xe7~~\xdf\x81*\x8e\xed\x107\xa0\xfc\xb8" +
"N\xbb\xf4\xc7?-M\xd2/;\xb2\x96\xffPy\xf6" + "\xbb\xca^\xf13\xf2Q\xfa\xe5\xc4n\xe2?T\x1f\xfe" +
"\xef_+\xe5\xaf\x83\xb1\x12\x1fF\xa9\x10w\x10\x88;" + "\xa7\x03\x95\xfcu1>(\x0e\xa2\xfc\x8a\xe8\" \xba" +
"\xf6=~d\xf7\xcd\xd5_\xfb\xe0\xaf+\x9d\xebs\xf5" + "\xfb\xbb\xe7\xd0\xee\x8f\xd7\x7f\xfd\xfdgj\xaa\xbf\xd74" +
"\xc3(\xbd\\\xef\x9ck=irc?\x9e~sq" + "\x88r\\r\x0fV\"\"]\xd6\x8bo>\xdf\x11\xfb" +
"\xe4\x1ba\xa2\xd5\x88\xe7\x08\xe9\x16\x91\x88\xd6\xf2nO" + "n\x94i\x8fK\xa7\x08\xea\x83\xaeB\xeb;K\x12\xfa" +
"L{o\xcb\x9b%\xab9\x03\x0f\x8b\x03(\x1d\x17i" + "\xbb[\x9e\xaf\x00\xc5U\xfc\xdc\xa5}(\x17.\xa5\xd9" +
"\xb5\xa3\xce\xe0\x81\xfb\xbf\xf4t\xf4\xec\x97\xbeC\x9a\x86" + "\xb4KI9\xf6\xc9\xd1\xed\xd2\x89\x9f\xbe\xe0\x81\xe2\xed" +
"\x18\x1e%\x1fX\xaa\xde`\xa0\xb4\xf1\x06\xfa9yC" + "<.\x8f\xd2\xce?&\x13j}7~\xe5\x81\xf8\xc9" +
"\x03\x0fh7\xbf\xf2G\x7f\xd9\x93\xf9\xd1[\x154\x95" + "\xaf\xbcH\xc6E| Nn\xb5\xb0[6Q\x1e\x90" +
".\xdfxA\x8a\xce\xa1_8\x87\x14=\xb3\xe8\xd0\xe7" + "\xe9\xa7\"7\xf3\x80N\xea\xc9?\xfb\xf6\x92\xdc\x1b/" +
"\xfe\xf3O\x8e\x9f(*\xea`\xbav\x8eC\x89us" + "\xd7\xe0\xa8|t\xc6\x19\xf9\xad\x19\xf4\xeb\x8d\x19\x04\xea" +
"\xe8<.\xaf\xd9{\xb7j\xdf{\xaa\x14%\xf7\xf4\xe6" + "\x89\xf9O}\xe1\xed/\x1d}\xad\xbc\x13w\xedE\xcd" +
"|\x1d\xa5\x03\xcer\xfb\x9d\xe5|\xfeU\x1a]\xd30" + ".iz\x9bi\xedsk\xf7\\\xaf97\x1c\xaf\x04" +
"\x8eRK\x03\x8dnj\xa0\xb5\xb9\xb3J\xd3\xe6\x7f\xfe" + "\xc6\xd5\xd4\x9a\xbf\x83\xf2\xe6f\x9a\xee\xf6f\x9a.`" +
"\xd4\xe9\x10eZ\x1a~\x8e\x10\xb1W~\xe6\xfe\xf1\x9a" + "h-\xed_4\x8f\xa2|\xd6\xd5~\xcf\x9d\x9b;\xa9" +
"\x8dg\xce\x84\xd5\x12\x1b\x1c\xfc\x168S\xff\xeb\xcf\xcf" + "\xb6l\xfa\xe9\xa7\xdf\x8c\x90\xeal\xf3/\x11b\xce\xca" +
"}\xf1|.\xf3o\x0e\xed=\x84\xfb\x1a:\x88\x0ck" + "\xcf\xde8\xdap\xfb\x89\x13Q\xb3\xdenv\x01>\xef" +
"\x1b\xc8\x0f\x1bZc}m'\x07\xcf\xb9Dr\x97\xb8" + "\x0e\xfd\xc7\x7fyh\xe4\xa6o\x1f9\x19%\xd2L\x93" +
"\xa3\xb1\x87\x06\xc8\x8d\xb4\xc4\xb2\x07\xba\xd9\x9a\xdb\xef=" + "\x88\xf4_\x7f}\xea\xcb\xa7\x0b\xb9\x7fw]\xc6?\x9c" +
"W\xc6\x96u\x8d\x1d(=\xdcH\x1366nGi" + "\x96\x99\x8b\x09\xce\x8e\x99\xe4\xc3\xcdm\x89\xa5\xed\xc7\xfa" +
"WS\x03\x80=\xf17;\xee}\xf1\x9b+/\xb8\x9e" + "OE\xf1N\xb4,!\x859-4\xf9\xa2\x9b\xbb\xd9" +
"\xe8(\xbb\xadi\x09\x11\xf3\xc9\xcf\xf7\xae\xba\xa3\xed\xc8" + "\xdakn8U\xc5\xb4\xa5-\x8bQ\x1ehq\xb1n" +
"\x85\xb0\xb2\x1b\x9b\xc87\xa4\x1dM\xb4\xd3\xc8\xed\xe7?" + "\xd9\x8e\xb2\x96j\x06p\xc6\xfen\xc7\x0dO|\x7f\xe5" +
"\xbd\xe0\xc9o_\xa8\xe4\x00\x87\x9a\xdaQ:\xd2D\xa0" + "\x19\xcf\x8b][>\x97Z@\xb6\xdc\xf7\xc5\x9eU\x7f" +
"\x1c\xa6\xc1\xef-\xff\xd3\x13\xcd\xf1\xe6\x8b%\x00V\xd1" + "\xda~\xe8Lt\x1bJ\x8a\xfcJf)Zi\xe8\x9a" +
"\xd8\x9f5\x8d\xa3t\x89\xc6.}\xbf\xe9;D\xca\xe7" + "\xd3\x9f\x99s\xdf\x0f\xce\xd4r\x9em\xa9y(\xefJ" +
"\xffl\xdf\xbf\\>v\xd7\xa52\x1b\xce\xce\x1dF\xe9" + "\x11\\;H\xf9\xdde\x7f\xf9ZJL}P\x01m" +
"\xf2\\Z\xf6\xd2\\A\xba4\xf7&\x00\xfb\x91S\x9f" + "\x1d\xe9>\x93\x1aE\xf9p\xca\x0dh\xa9\x17\x89\xd0{" +
"]\xff\x83/|p\xa9\x94G\x8e\"\xef\xceM\xa2\x84" + "\xffj\xdf\xbf\x9e;r\xdd\xd9\xaa=\x1c\x9cE\xdc\x9f" +
"\xf3h\xc6\xaf\xe7\x12\xeb\xbe\xbc\xfa?6\x9d\xdf5\xe7" + "E\xd3\x1e\x9e%\xc8\x87g]\x01\xe0\xdcy\xfc\xf3\xeb" +
"\x97ek\xef\x997\x8e\xd2!g\xe4\xcb\xf3\xb6K\xb1" + "~r\xc7\xfbg+\x19\xe6\x1arhV\x1a\xe5\xd7\xdd" +
"\x16\xf2\xa6w\x84\x17\x16\xf7nz\xebr\xc8o/\xcd" + "\x11Gg\x11a\x1fZ\xfd\x9f\x1bO\xef\x9a\xf1\xeb\xaa" +
"\x1b x\x9e\x11\xbezf\xf3O?\xfb\xab0<\xef" + "\xb9oi\x1dEy[+inn}Q\xbe\xecr" +
"\xcf\xfb9\xc1\x13m!x\x1ez\xef\xb9\xbb\xbe\xb8\xe6" + "\xf2\xc4W\x85\xc7:z6\xbe|.rT\xe7[\xfb" +
"\xa5\x0fC4X\xd0\xb2\x85\xa6Z\x05McY#\x1f" + "\x08\x9e\x07\x85\xaf\x9d\xd8\xf4\xf3\xcf\xff&\x0a\xcf\xb9\xd6" +
"I\xdf\xea\xfdL\xdf\x92V\xf2Z\xbe\xa3\xbb`\x8d1" + "_\x12<\x89\xcb\x09\x9e\xdb\xde}\xe4\xba/\xaf\xfd\xe6" +
"\xcdR\xd3\x8a\xc5\x92\xac\xd3\xcc\xeb\x9a\xc9\x06\x11\xe5z" + "\x87\x11\x82\xcc\xbf|\x0b\x0d\xb5K\xba\xce\xf2f1\x96" +
">\x02\x10A\x00Q\x19\x07\x90\x1f\xe0Q\xcer(\"" + "\xbd\xca\xff\x99\xbd2\xab\x16\xf5\xe2\xe2\xee\x92=\xc2t" +
"&\x88(\xa2J\xc21\x1ee\x8bC\x91\xe3\x12\x14%" + "[\xcb\xaa6K\xb3N\xabh\xe8\x16\xebGT\x9a\xf8" +
"\xc5um\x00r\x96Gy=\x87\xc8'\x90\x07\x10\x0b" + "\x18@\x0c\x01$u\x14@\xb9\x99G%\xcf\xa1\x84\x98" +
"O\x03\xc8\xeby\x94\xb7rh\xe7\x99\x91S4\xa6A" + "$\xa2H\x1a\x09GxTl\x0e%\x8eKR\x84\x95" +
"\xdc\xea3\x0c\xac\x05\x0ek\x01m\x83Y\xc6\xa42\x9c" + "ni\x07P\xf2<*\xeb8D>\x89<\x80Tz" +
"\x858\x0b\x89\x85\xf1\x07-\x8c\x01\x871@{L/" + "\x00@Y\xc7\xa3\xb2\x95C\xa7\xc8\xcc\x82\xaa3\x1dD" +
"\x18\xe6\x90f\xa1\x9aM\xb2\x11\x83\x998\x86U\xc0a" + "{\xa9ib#p\xd8\x08\xe8\x98\xcc6\xd7\xab\x83y" +
"\x15\xe0t\xe6\xa5\x98i\xaa\xba\xb6B\xd1\x94Qf\x00" + "\x10YD,\x8c\xdejc\x028L\x00:#F\xc9" +
"\x90e\xd5|\x14\xc0\xcf@\xe8\xe5*q\xf1n\xe0\xc4" + "\xb4\x06t\x1b\xb5|\x9a\x0d\x99\xcc\xc2\x11\xac\x03\x0e\xeb" +
"E\x02\x06\xd9\x02=\xb2\x8a\xbfs\x108\xb1E\xb0\x0d" + "\x00'\xda^\x86Y\x96f\xe8+T]\x1df&\x00" +
"6\xaa\x9a\x163p(\x93w\xd6\xe6u\xad\x0b\xed\x82" + "\xed\xac\x9e\x8f\x03\x04\xd9\x0b\xfd<'u\xec\x06N\x9a" +
"\xe6~@f\xb8\x1f\xe2\xb4k\x17\x0eb\xa0\x1d_\xae" + "/`\x98i\xd0'\xab\xf4\xb1\xfd\xc0I\xad\x82c\xb2" +
"\xdd\x9dY\x95iV\xbc_\x1b\xd1K \x1f\xa8\x04\xf9" + "a\xcd\xb2\x99\x89\x03\xb9\xa2;7o\xe8]\xe8\x94t" +
"@\x11\xf2\xad!\xc8\x1f\xee\x01\x90\x1f\xe2Q~\x94C" + "\xef\x032\xd3\xfb \xd2\xaa]\xd8\x8f\xa1u|\xb5u" +
"\x91/b\xbe\xad\x1d@\xde\xcc\xa3\xfc\x04\x87v\xda\xd9" + "\xd7\xe65\xa6\xdbb\xaf>dT@\xdeW\x0b\xf2\xbe" +
"\xa4?\x03\x00>\x9a#L\xb1\x0a\x063IV\x078" + "2\xe4[#\x90o^\x02\xa0\xdc\xc6\xa3r\x17\x87\x12" +
"\xc8\xa3\x03z\x1d\xe0\xa6\x09f\x90\xee\xde!\xc4\x15#" + "_\xc6|\xdb<\x00e\x13\x8f\xca\xbd\x1c:Yw\x91" +
"=\xe6\x1f\xd44H\xf7\xadWMK\xd5FW;\xf2" + "\xde\x1c\x00\x04h\x0e1\xd5.\x99\xcc\"\xd9t\xc0~" +
"\xceA=\xab\xa6'\xc9\xaaZG\xcf\x96\x0e\x00D\xf1" + "\x1e]\xd0\xa7\x03n\x1cc&\xd9\xee\x1f\x82\xa8\x9a\xd9" +
"\xc6\xfb\x00\x90\x13\xc5\x1e\x80NuT\xd3\x0dfgT" + "\x91\xe0\xa0&@z\xe9:\xcd\xb25}x\xb5+\xef" +
"3\xadk\x1a\x03>mm\x1aV\xb2\x8a\x96f\xfeF" + "\xec7\xf2Zv=\xed\xaa\xd1\xb5\xb3u1\x00\xa2t" +
"U\xe5\x1b\xb9\x1b\xa4\x981\xc1\x8c[\x94\x10}\xe7\x0f" + "\xd9\x1a\x00\xe4$i\x09@\xa76\xac\x1b&sr\x9a" +
"*\x86\xc2\xe7L\xb9\xd6\xc7\xb1\xef>\x00\xb9\x97Gy" + "\x955t\x9d\x01\x9f\xb57\x0e\xaayU\xcf\xb2`\xa1" +
"0\x84\xe3\x0a\xc2\xf1\x1e\x1e\xe5{C8\x0e\x11\x8e\x83" + "\xba\xea\x85\xbc\x052\xcc\x1cc\xe6\x95j\x84\xbe\xb3\xfb" +
"<\xcak8\xb4uC\x1dU\xb5;\x19\xf0F\x98\x81" + "US\xe5\x0b\x96\xd2\x18\xe0\xb8t\x0d\x80\xd2\xc3\xa3\xd2" +
"\xa6\xa5)9F\x98\x15\xf1\xd8\xa4\xe7-U\xd7L\xac" + "\x1f\xc1q\x05\xe1\xb8\x9cG\xe5\x86\x08\x8e\x03\x84c?" +
"\x0fr\x0b \xd6\x87\x90\x12f\xe2\xe4-\x1e\xa5<F" + "\x8f\xcaZ\x0e\x1d\xc3\xd4\x865\xfdZ\x06\xbc\x19e\xa0" +
"\xe9\xda\xfc$3\x0bB\xd62\xe5\x88oI\xac\x03@" + "e\xebj\x81\x11fe<6\x1aE[3t\x0b\x9b" +
"\xae\xe6QNp\xd8i0\xb3\x90\xb5\xb0>(\x09>" + "\xc2\xac\x03\x88M\x11\xa4\x84\xc98y\xa5O)\x9fQ" +
"\x8e]=\xf8B4LV\xa2\xe1\x12\x009\xc3\xa3\x9c" + "\x86>;\xcd\xac\x92\x90\xb7-%\x16\xec$\xb1\x18@" +
"\xe7\x10\x8b\xe8\xe5zB\xd1\x80G\x97\x85\xebv\x03\xc8" + "\xa9\xe7QIr\xd8i2\xab\x94\xb7\xb1),'~" +
"\x16\x8f\xf2f\x0em\xd3\xdd\xa4\x1f0\xe3!\xda\x9a1" + "\x17\xab\xfa\xf0Eh\x98\xaeE\xc3\x05\x00J\x8eG\xa5" +
"\xad\xfe\xbc\xf7\xd7\xa6\x8ci\x0d\xea\x86\x85\x02p(\x00" + "\xc8!\x96\xd1+,\x89D\x03\x1e=\x16\xde\xb2\x1b@" +
"\xf1V7Y\xf7\x08\xf9T\x7f&\xcb\xeeRy\xcd\xc2" + "\xb1yT6q\xe8X\xde\"\xbd\x809\x1f\xd1\xb6\x9c" +
"(p\x18\x85i\x9d\xca\xe5G\x9c\x02\x9b\xeb\xed\x9e5" + "e\xf7\x16\xfd\xbf6\xe6,\xbb\xdf0m\x14\x80C\x01" +
"\x0b\x89\x0c\xbf\xc7\xa3\xfc\xfb!k\x16S\x1c\xbb\x8dG" + "\x88\xb7\x86\xc5\xba\x87\xc8\xa7zsyv\x9d\xc6\xeb6" +
"\xf9\x93\x1c\xdaJ:\xad\x174k5\xf0\xcah\x09\xe7" + "\xc6\x81\xc38L\xe8T\x1e?D\x0al\x9e\xb7\xfb\xbb" +
"S\x0c\xe2i\x83\x05t\xf0\xb6\xad\xae\xe0\xd6\xba6\xa2" + "\x99Kd\xf8#\x1e\x95?\x8e\xec\xa6\x83\xe2\xd8\xd5<" +
"\x8e\x16\x0c\xc5\x0a\x01^\xc8g\x14\x8bM\xf9\xe4\x9cs" + "*\x9f\xe2\xd0Q\xb3Y\xa3\xa4\xdb\xab\x81W\x87+8" +
"\x96\xbf\x8as\xf6\xab\x87k>g/2\x95\x9ct\xdc" + "\x9fa fM\x16\xd2\xc1_\xb6\xbe\x86[\x1b\xfa\x90" +
"Prf\x18\x9bd%l\xe8T?\xc1\xa3|{\xe5" + "6\\2U;\x02x\xa9\x98Sm6\xee\x93{\xce" +
"\x03\xdc\x94c\xa6\xa9\x8c\xb2\xb2\xf0\x10\xad\x88\x89\xc6\xd2" + "y\xfe\x02\xce9\xa8+\xa6|\xce~d\xaa8i\xd1" +
"du\x92\xb9I\xe6\x16\x83\x99B!k\x91\x16\xb5\xb6" + "T\x0bV\x14\x9bt-l\xe8T?\xc1\xa3rM\xed" +
"\xed\xaaA\xdc\x9a\xcf\xa3|\x1b\x871\xfc\xd0v\xf5X" + "\x03\xdcX`\x96\xa5\x0e\xb3\xaa\xf0\x10\xaf\x89\x89\xce\xb2" +
"\xf4tpF\xad\xcc0t\x03\xeb\x83$\\\x84$]" + "\xb4\xeb4\xf3\x92\xcc\x95&\xb3\x84R\xde&+\x1a\x1d" +
"\xdc\x00u\xad\x97Y\x8a\x9aErK\xbf\xda,\x01n" + "\xc73\x83\xb85\x9bG\xe5j\x0e\x13\xf8\xa1\xe3\xd91" +
"\xa6\xb8\x12\xc0\xe6\x8a\xe7w\x92w\xe4\xa6\x9c\x14\xd1\xbb" + "\xff\x81\xf0\x8c\xda\x98i\x1a&6\x85I\xb8\x0cI\xb6" +
"\x9eGy\x1e\x87\xf6\xa8\xa1\xa4\xd9 3P\xd53+" + "\xbc\x00\x1az\x0f\xb3U-\x8f\xe4\x96A\xa5Z\x01\xdc" +
"\x15MO\xf1,]F\xd6\xbak\xdd\xd4\xe1\x87e\x82" + "dq%\x84\xcd\x13\xcf\xee$\xef(\x8c;)\xa2w" +
"?k\xfa\xf9\x06+\x82P\x9c>\xd8\xea\xea\x9c\xf0u" + "\x13\x8f\xca,\x0e\x9daS\xcd\xb2~f\xa2f\xe4V" +
"\xde\xd8\x16$c\xff\x98\x1f\x1e\x0e\xb2\x85\x1f\x0f\x1f#" + "\xaa\xba\x91\xe1Y\xb6\x8a\xac\xd3\xa7\xba\xa8\xcb\x0f\xdb\x82" +
"gy\x94Gyg(\xaf\xec\xa0\xc8\xf9\x14\x8f\xf2W" + "`\xd4\xc4\xe3MV\x06\xa1<\xbc\xbf\xcd\xb39\x19\xd8" +
"9\x14#\x91\x04F\x00\xc4\xe7\x88%;y\x94\xf7r" + "|{{\x98\x8c\x83c\xde<\x18f\x8b \x1e\xdeM" +
"SS6\x9b`\x9a\xd5\xab\x8e\x82\xc0\xcc@J*\xf6" + "\xcer\x17\x8f\xca\xceH^\xd9A\x91\xf3~\x1e\x95\xaf" +
"\xaa\xa3\x0cx\xf3zck\xf5\x0cx\xe8\xc3\xa6\x9ee" + "q(\xc5bI\x8c\x01H\x8f\x10Kv\xf2\xa8\xec\xe1" +
"\x16\xebe\xe9\xacB.7\xc1\xdc\xefE2z\x87:" + "\xc6\xa7l6\xc6t\xbbG\x1b\x06\x81Y\xa1\x94L\xec" +
"\x1do\x93e\xdeC\xfc\x8d{UR\x88\x0em\x81\xe3" + "\xd1\x86\x19\xf0\xd6\xc5\xc6\xd6\xfaI\xf00\x06-#\xcf" +
"\x0a,T\xdcL\xa3\xad\xbb\xb8\x1b\x0c\xca8\x10xL" + "l\xd6\xc3\xb2y\x95\\n\x8cy\xdf\xcbd\xf4\x0fu" +
"\x91\x07h~,A\xc7\xb1\x19\xa78\x7fO\xe0u\x1e" + "\"\xde\xa6\xab\xbc\x87\xf8+\xfaUR\x84\x0e\xed\xa1\xe3" +
")\x16u\x04\x01\xc1\xaf\x09\"\xc0a\x04\xb03\xed," + "\x0a,R\xdcL`\xad7\xb9\x17\x0c\xaa8\x10zL" +
"X\x16\x0a#3i\xd5\xe9\xaa\xe5\x02GE\x98w\x17" + "\x99\x07h\xfdN\x82\x8e\xbbg\x1c\xe7\xfcKB\xaf\xf3" +
"E\xef\x02/\x8a\xfb\x80\x13c\x82\xedi\x8e\xde|\xa1" + "I1\x7fq\x18\x10\x82\x9a \x06\x1c\xc6\x00;\xb3\xee" +
"\xac\xa0\x8aL\x17eV\xe5-U\xd05\x93\xf6\x0a\xf1" + "\x84U\xa106\x99U\x9d\x9eY\x1epT\x84\xf9\xf7" +
"\xbf\xa3\x12\xff\x8d\x80\xff^B{lK\x98\xfe\xc5\x84" + "X\xf4/\xff\x92\xb4\x0f8)!8\xbe\xe5\xe8\x8f\x17" +
"\xb6cw\xc0t1\xc2\xb9\xf4\xdf\xb3\x0f@\xde\xcb\xa3" + "\xaa\x0a\xaa\xd8DQfU\xd1\xd6\x04C\xb7h\xad\x08" +
"\xfc\x12\x87\x9dn\xad\x85\xf5A\xe3\xa5HY\xb7\xa2\xb8" + "\xff\x17\xd7\xe2\xbf\x19\xf2\xdfOhwo\x89\xd2\xbf\x9c" +
"G\x87\xd6\xb4\x92\x0d\x92\x9em\xb0|VI\xb3>," + "\xd0v\xec\x0e\x99.\xc58\x8f\xfe\x8f\xee\x03P\xf6\xf0" +
"VO\x80\x08\x1c\xa2\xe3'\xb9\xbc\xc1L\x13U]\x93" + "\xa8|\x93\xc3N\xaf\xd6\xc2\xa6\xb0iS\xa6\xacWQ" +
"\x0bJV\xe5\xadI\xbf\xe2\xd5\x0a\xb9A\x83M\xa8\xa8" + ",7\xa0-\xab\xe6\xc3\xa4\xe7\x98\xac\x98W\xb3l)" +
"\x17\xccn\xcbb9!o\x99WS\x0f\x07\x00Q\x90" + "\x96\xab'@\x04\x0e\xd1\xf5\x93B\xd1d\x96\x85\x9a\xa1" +
"\x14\xd4\xacY\x92#\xdb\x03*\xf8\x00-\x1a\x0f\xf2@" + "+%5\xaf\xf1\xf6\xfa\xa0\xe2\xd5K\x85~\x93\x8di" +
"\xbcPP\xfd\x04`g\xf5\xb4s\xb2\x10_\xa9\xe4\xca" + "h\x94\xacn\xdbf\x05\xa1h[\x17R\x0f\x87\x00Q" +
"\xf3@\xd5\x8c\x01kJ\xb8\xf3\xd2\xd2oR\xfd6\xfd" + "\x90\x14\xb4\xbc\x0bP\xa4`\xa2\xca\xb1\x8bGey\x04" +
"\x95\x89Lw\xee\x14!\x95)\x0et\xf1(\xdf\x13R" + "\xa0^\xca\x91\xd7\xf1\xa8\xac\x0e\x01R\xbe\x07\xa0\xac\xe6" +
"\xb9\x7fI\xc8\x0eO\xe5\x15\xc3\x81\x1d\xc2\x1f\xb3IO" + "Q\xb9\x99C\xb1T\xd2\x82\xa4\xe0\xe4\x8d\xac{\xda " +
"\xabV\x96\xa3\xf4\xe5\x81Y4\xa6\x1b\x84\xbb\x831\xd3" + "\xaeT\x0b\x95\xb9\xa1\xd7\xe2\xd2\xac`\xd8,\xbf\xde\xe3" +
"\xe9\x17\x8e*\xab\xf2\xad\x8e\x85\xa4\xe3\xed\x9e\x8e\xd2$" + "h.\xdc\xf1\x85\xc6\xe6\x8a \xe9'\xb3\xdf\xa7\xaao" +
"\x0e\x00\xa4\xd6#\x8f\xa9\xad\x18\xa8)=\x8c=\x00\xa9" + "\xe2\x8b\x16\x81\x03\x15\xb8\xb7\xd7\xc2}Ad\x1f\xbe\xc9" +
"\x87H\xfe(\x06\x9aJ\xdb\xb0\x19 \xb5\x99\xe4O\xa0" + "+\x06\xc3}\x08\x7f\xc1\xd6\xfbV\xb5\xb1\x02%=\x1f" +
"\x7f\xb5\x93\x1e\xc3\x83\x00\xa9'H\xfc,\x0d\x8f\xf0\x8e" + "\xee\xf2f\xbaA\xb8>\xd4\x99j,r}p\xb9\x91" +
"KH\xbb\x9c\xe5w\x92|/\xc9\xa3\x91\x04F\x01\xa4" + "U\xf3\x95!D\xacL\x86\xd1\xb2\xe5\xc2\xc3Ct\xd1" +
"=\xd8\x0e\x90z\x96\xe4\xaf\x91\xbc\x8aK`\x15\x80t" + "U\xc56\x17V\x02\xe6\x1a\x7fby=\xf6\x01d\xd6" +
"\x08\xc7\x01R\xaf\x90\xfc\x0d\x92\x0b\xd1\x04\xddn\xa5\xd7" + "!\x8f\x99\xad\x18b#o\xc6%\x00\x99\xdbH~\x17" +
"\xd1\x00H\xfd-\xc9\xbfI\xf2\xea\xc6\x04V\x03HG" + "\x86\xf0\xc8\xdb0\x05\x90\xd9D\xf2{1\xb8\x85\xcaw" +
"\x1c\xf9\x9b$\xff>\xc9k\x9a\x12X\x03 \xfd\x13n" + "\xe3~\x80\xcc\xbd$~\x98\xd4c\xbc\xeb\xbd\xf2.w" +
"\x01H}\x97\xe4'H>\x0b\x138\x0b@:\x8e\xbb" + "\xfa\x9d$\xdfC\xf2x,\x89q\x00\xf9Q\x9c\x07\x90" +
"\x01R'H\xfe\xaf$\x9f]\x95\xc0\xd9\x00\xd2O\x1c" + "y\x98\xe4\x07H^\xc7%\xb1\x0e@~\x0aG\x012" +
"}N\x92\xfc\x17$\xaf\x8d$\xb0\x16@\xfa\x19\xee\x03" + "O\x92\xfcY\x92\x0b\xf1$]\xc4\xe5\x83h\x02d\xfe" +
"H\xfd\x82\xe4\xffM\xf2\x98\x90\xc0\x18\x80\xf4\xaec\xd7" + "\x9e\xe4\xdf'y\xfd\xcc$\xd6\x03\xc8\x87\\\xf9\xf3$" +
"y\x92Ws%7+\x8fQ%\xd7'^7\xfd#" + "\xff\x11\xc9\x1bZ\x92\xd8\x00 \x1f\xc6-\x00\x99\x1f\x92" +
"cE\x1fG\x97\xee\x83z\x9c\xaeH\x18\x0f\x1a\xaf\x80" + "\xfc5\x92O\xc3$N\x03\x90\x8f\xe2n\x80\xcck$" +
"\x18\x07\xb4\xf3\xba\x9e]9\x95\xa9qK\x195\xbd\xab" + "\xff7\x92_R\x97\xc4K\x00\xe4\xb7\\{\x8e\x91\xfc" +
"Z}\xd0\x9a\x02$\xa1_\xfc@\\\xd7\xfa3~ " + "W$o\x8c%\xb1\x11@\xfe\x05\xee\x03\xc8\xfc\x8a\xe4" +
"(\x8d:\x9e&\xaa\xd9]\xb0\xf4B\x1eZ)\xc8f" + "\xffM\xf2\x84\x90\xc4\x04\x80\xfc\x8e\xbb\xaf\xd3$\xaf\xe7" +
"\xfc\x98c\x14\xb4\xe5\x86\x9e[\x8d\xcc\xc8\xa9\x9a\x92\x9d" + "*.\x81>\x8d+nz\xbca\x05<a\xe5p\x84" +
"!\x1a\xd5\x00\x875P\x0c\x09\xde\xda\xd3\x87\xa6+_" + "\x9e\x8f\xf5\x1b\"\xdd\xe6P\x0c\xfb\xcb\x80(\x02:E" +
"<}Fs\xa5\x8cn\xcdw\xacVF\xaf&N-" + "\xc3\xc8\xaf\x1c\xef\x1e\xa2\xad\x0e[\xfe\xad\xb2)\xec\xaf" +
"\x09rV\\\x0b\x05\xa4\xd6\x09%[\xf8(\xe1ij" + "\x01\x920\xa8\xd3@4\xf4\xde\\\x10\xb3*\x03\xa4o" +
"=\x95\xect\xeb\xb1\x99\xcau\xaf\xf7T\x12J*T" + "\x89fu\x97l\xa3T\x846\xe2b.\x08\x16fI" +
"\x17C\xe5\xf99\xc9\xccV\xbf\x09\x132\xf8`\x10\x83" + "_f\x1a\x85\xd5\xc8\xcc\x82\xa6\xab\xf9I\x02g\x03p" +
"={\x97\xb5\x85\xee.Y\xc5b\xa6\xd5\x9d\xc7|V" + "\xd8\x00\xe5H\xe5\xcf=q\x14\xfd\xe8;r\xc0h\xae" +
"e\x99\xcf0#\x1eN\xd9\x15+\x92\xc8Le\xfa\xd4" + "\x92\xd1m\xc5\xc5\xab\xd5\xe1\x8ak\xc7\xbc0\xbb\x06\xae" +
"2\x07C]r2\x9c+\x1a|\xd5x\x8e2\xcb\xfd" + "=\x7fA\x98^E=\x12'\xdb\xc6\xd4|\xa9\xba\xa2" +
"\xd5\xaf\x8d\xe8T\x87\x08\xe1\xe2\xeb\xdaf'\x99\x19\xbf" + "\xae\x9bb\xe9\x97\xee\xf4J\xc7\xc9n\x16~\x9b\xac\"" +
"\x9a\xb3\x08\x9a\x863_\x9d*\x94c\x15\x8a1\xef&" + "~\xd5(\x84\x06\xaaK\x894\xb3\xda\x82~Qd\xc3" +
"\x10\xba&\x13\x19\xd7\xf0(\x8f\x85\xc8\xc8\x06*\\\x93" + "\xfb\xc3k\x83\xbf\xdfE\xed\x91kV^\xb5\x99ew" +
"\x93A\x7fL\xe4\xb9b\x83\x8c2W\x9eG\xf9!\x0e" + "\x17\xb1\x98\xd7X\xee\xb3\xcc\x14\xa3\xd5E\xcd\xe2)6" +
"\xe3J\xc1\x1a\xc3\xfa\xe0\xf1c\x8a\xd2S{8\xc4\xcd" + "\xd9\x8db|E\x86\x91\xc7\x00\xda8W\xde\xf0\x05\xe3" +
"~-\xc3\x00\xd7{\xee\x15\xcag~W~\xe6\x9a\xf9" + "9\xccl\xefW\xaf>dP\xc9$D\xeb\xc4\xa9\x8d" +
"\xea\xcc\xf6\xee\"3\x02\xee\xf7\xaeKv\xbe\xe2U\xbd" + "N3K\xbc\x90\xb3\x08\xfb\x9b\x93\xd7\xb9S\x89\xd6i" +
"\xd3\xdd\x94x\xd6\xe8T\x85^\xd7\x1f\xbd\x8e\xb0xh" + "\xd6\xe6ra\xa2[c\x8d\xf9j\xd4\xa1\xfe%(\xd2" +
"\x03p\xe2\x01\x01\x83^7z\xadmq\x8f\x01\x9c\xb8" + "! r\xaf\xe5Q\x19\x89\x90\x9b\xf5\xd5\xe8\x10\xa4\xc3" +
"K@\xce\x7f\x97A\xef\xfdE|\xecq\xe0\xc4m\x02" + "\xd6\xa0\xc4s\xe5\xde \xa5\xdf\"\x8f\xcam\x1c\x8aj" +
"\xf2\xfe\xb3\x0az]\xd2\xc5\x93\xb3\x108q\xa3\x80\x11" + "\xc9\x1e\xc1\xa6\xf0\xcdh\x1c\x08\xe3\xdbW\xc4\xf5^=" +
"\xff=\x0b\xbd\x1e\xab\xb8n\x1c8Q\x150\xea\xbf\xd8" + "\xc7\x00\xd7\xf9\xee\x1aI\xca\xc1c\xc6o\x05\xe3G\x96" +
"\xa0\xd7\xe2\x17\xd7n\x01N\x1c\x0az\x81\xd0\xe9\xda\xd1" + "\xdf\x16Lz\x80AC\xbfb\xe5\x8f\xecRtz\x8b" +
"\x85\xb6\xc7QhuX:\xb53\xe8\x8e\x02\xe8B\xdb" + "\x12og\xba\x05\xb1\xffV\x82~3\\zj\x03p" +
"\xbb\x99\xf0W\xba\x9a8\xa3\xbc\xe6\x16\xc4\xd3\x8a\xc5\xba" + "\xd27\x04\x0c\x1f\x00\xd0\xef\xf7K\x8f\x9a\xc0I\xbb\x04" +
"\xa8Zt\x03\x12\x16#\x12t\xa1\x1c\xc1P\x8b\x19\xe0" + "\xe4\x82\xe7,\xf4\x9f\xad\xa4\xbb\xef\x01N\xda& \x1f" +
"z[\x03I\xd6\xea\x9c\xf3G\xad\xe1\xbc\xf9\x1f1F" + "\xbcF\xa1\xdf \xeeX?\x0d\x81\x93n\x170\x16<" +
"\xf2\x95\xb4\xa6}\xfc&ih]*Kky\x94\x1b" + "\x03\xa2\xdf^\x96n\x19\x05N\xd2\x04\x8c\x07\x0f]\xe8" +
"\xb9\x19+\xd1\xc8\x95\xac\xf0\xc8\x1f\xa7\xc9\xb4\xfeo\xfb" + "\xbf{H7m\x01N\x1a\x08\xdb\xa0\xd0\xe9\xed\xa3\x0b" +
"\xeb\x1f\xa7\xf0\xfa}\x1e\xe5\x93!\xb7\xfe!\x09\xdf\xe1" + "\x1d\x9f\xf3\xd0\xe6\xb2~|S\xd4\xd3\x02\xe8B\xc7\xbf" +
"Q>\x1d\xaa\xe4~D\xbe~\x92G\xf9b\xd0\xf7~" + "\x94\xf1\x1fu+s\xb5\xfc\xbe\x1e\x88Y\xd5f]T" +
"\xffq\x00\xf9\"\x8f\xc9Pe$\xfe\x9a\x06\xfe\x8a\xea" + "({\x01\x0e\xcb\x11\x0e\xbaP\x89a\xa4\xbb\x0ep\xb1" +
"\x07\xa7.B\xb7.\x8a\xe2\xd3\x00\xa9j\xaa+\x12N" + "]\x91*?\x99b!\xea\x8f\xff-c._\xcbj" +
"]\x14q\xeb\"\x11\x87\x01R\xf5$\x9f\x17\xae\x8b\x9a" + "Z'\xe8\x0fG\xe6\xa5\x8a\xbc\x91Ge&7I\xc1" +
"\xf0>\x80T#\xc9\xe7\xe3\xd4\xdb\xa6P0\x82\xca1" + "]3tz\x06\xfb\xe4\x17i0\xcd\xff\x07\xc1\xfcG" +
"\xab\x8f\xde\xa3j\x15\x93\xad\xd7\x88Gk\xb9\xa2f\x0b" + ")\\\xff\x88G\xe5X\xc4\xad_'\xe1\xab<*o" +
"\x06\x83 \xd7\x17\x83Mo\xa8\xfcp;\xf4n3." + "F\xca\xd17\xc8\xd7\x8f\xf1\xa8|\x10\xb6\xfc\xdf\xbb\x07" +
"E$\xcc\xa0\xe97\xea\xae\xe1\x9e?]\xe6\xc9\xea\x85" + "@\xf9\x80\xc7t\xa4\xd2\x92\xce\x93\xe2o\xa8\x1eq\xeb" +
"\xccHV1X&\xc5\x0c\xc1\x0d\x08\x83|T\xae\xc6" + ",\xf4\xea\xac8>\x00\x90\xa9\xa7:%\xe9\xd6Y1" +
"\xd0\xab7@\xf0:\x19\"\xfb\xb4\x99\xac\xcf0t4" + "\xaf\xce\x92p\x10 \xd3D\xf2Y\xd1:\xab\x05\xd7\x00" +
"J\xaa\xf4%A\x95\xee\x17\xe9t\xd9\xb8\x8bGy5" + "df\x92|6\x8e\xbfh\x0b%3,\x7f\xf3\xc6\xf0" +
"\x1dm\x97{\xb4\xf2pp\xafhM+\x05\x93\x95a" + "rM\xaf\x99\xbc\xfd7\x08\xb4\x97\xa9Z\xbed2\xa8" +
"\x02<3\xfc^\x8f9\xa6\x17\xb2\x99$\x03\xc12&" + "\xbc\x82\xf4\xf6D\xca\x19\xefq\xc2\xebCf\x88\x849" +
"K \x9d\xb1ZO\xb1\xb8\x17\x09\xddG\x0a\xefy\x0e" + "\xb4\x82\x1e\xe5\x14Z\x1c\x13e\xb2\xbcQ\xca\x0d\xe5U" +
"\xbdW\xb8\xd0#\x85\xf7R\x84\xdeSo\xf9#\x85\x87" + "\x93\xe52\xcc\x14\xbc\x80\xd0\xcf\xc7\x95z\x8c\xfc\xb3\x00" +
"A\xd9#\x85\xfb\xc1\xe1\xfc\xd4;\xf5u4)\xdc\xb4" + "@\xf8\xa8\x1b!\xfb\x84\x99q\xa9i\x1ahV\\5" +
"\x18:\x94k\xea\xdd_u\xcb\xdb\xffw\x89\x92\xc8Q" + "\x16\x84W\x8d\xe0\xa6\xb1&\xbc\xe1I\\W\xf9\x8a7" +
"s\xbd\xcd /\xc1\xfd\x7f\x00\x00\x00\xff\xff\xf1\xc3d" + "\x18^\x8e\xda\xb2j\xc9bU\x98\x00\xcf\xcc\xa0\xcde" +
"\xc6" "\x8d\x18\xa5|.\xcd@\xb0\xcd\xf5U\xb7\xba\xd8d\xd1" +
"W\xf4#a\xa3\x1b\x09\xfd\x97I\xf4\x1f %e7" +
"p\xd2\x0a\x8a\x84\xfe#\x19\xfa/\xe4R\xf7~\xe0\xa4" +
"?\xa7H\xe8\xbf\x0f\xa3\xff\xe8)u\xbc\x04\x9c\xd4\x11" +
"y\xbb\xf1\xf1\xa9z\xbb\xf1>\xb8\xfe@\x1f\xca\x09\x95" +
"\xab\xcc\xa8\x14\xa1\xa2\x8d\x88\x8b\xe8\xecx\x095r\x9c" +
"Sz\xf0\xb8\xe0w\x82\xe0\xffS*bN\xc3\xc5v" +
"\xd0\xfc\xd4\xf8\xff\x01\x00\x00\xff\xff|\xba\xdf\xe8"
func init() { func init() {
schemas.Register(schema_db8274f9144abc7e, schemas.Register(schema_db8274f9144abc7e,
@ -4561,6 +4784,7 @@ func init() {
0xb5f39f082b9ac18a, 0xb5f39f082b9ac18a,
0xb70431c0dc014915, 0xb70431c0dc014915,
0xc082ef6e0d42ed1d, 0xc082ef6e0d42ed1d,
0xc5d6e311876a3604,
0xc793e50592935b4a, 0xc793e50592935b4a,
0xcbd96442ae3bb01a, 0xcbd96442ae3bb01a,
0xd4d18de97bb12de3, 0xd4d18de97bb12de3,
@ -4568,6 +4792,7 @@ func init() {
0xdbaa9d03d52b62dc, 0xdbaa9d03d52b62dc,
0xdc3ed6801961e502, 0xdc3ed6801961e502,
0xe3e37d096a5b564e, 0xe3e37d096a5b564e,
0xe5ceae5d6897d7be,
0xe6646dec8feaa6ee, 0xe6646dec8feaa6ee,
0xea50d822450d1f17, 0xea50d822450d1f17,
0xea58385c65416035, 0xea58385c65416035,

2
vendor/modules.txt vendored
View File

@ -347,7 +347,7 @@ github.com/urfave/cli/v2
github.com/urfave/cli/v2/altsrc github.com/urfave/cli/v2/altsrc
# go.opentelemetry.io/contrib/propagators v0.22.0 # go.opentelemetry.io/contrib/propagators v0.22.0
## explicit; go 1.15 ## explicit; go 1.15
go.opentelemetry.io/contrib/propagators/Jaeger go.opentelemetry.io/contrib/propagators/jaeger
# go.opentelemetry.io/otel v1.6.3 # go.opentelemetry.io/otel v1.6.3
## explicit; go 1.16 ## explicit; go 1.16
go.opentelemetry.io/otel go.opentelemetry.io/otel