TUN-2307: Capnp is the only serialization format used in tunnelpogs

This commit is contained in:
Chung-Ting Huang 2019-09-16 18:25:00 -05:00 committed by Chung Ting Huang
parent ff795a7beb
commit fe032843f3
9 changed files with 397 additions and 877 deletions

View File

@ -93,7 +93,7 @@ func (s *StreamHandler) UpdateConfig(newConfig []*pogs.ReverseProxyConfig) (fail
toAdd := s.tunnelHostnameMapper.ToAdd(newConfig) toAdd := s.tunnelHostnameMapper.ToAdd(newConfig)
for _, tunnelConfig := range toAdd { for _, tunnelConfig := range toAdd {
tunnelHostname := tunnelConfig.TunnelHostname tunnelHostname := tunnelConfig.TunnelHostname
originSerice, err := tunnelConfig.OriginConfigJSONHandler.OriginConfig.Service() originSerice, err := tunnelConfig.OriginConfig.Service()
if err != nil { if err != nil {
s.logger.WithField("tunnelHostname", tunnelHostname).WithError(err).Error("Invalid origin service config") s.logger.WithField("tunnelHostname", tunnelHostname).WithError(err).Error("Invalid origin service config")
failedConfigs = append(failedConfigs, &pogs.FailedConfig{ failedConfigs = append(failedConfigs, &pogs.FailedConfig{

View File

@ -49,12 +49,10 @@ func TestServeRequest(t *testing.T) {
reverseProxyConfigs := []*pogs.ReverseProxyConfig{ reverseProxyConfigs := []*pogs.ReverseProxyConfig{
{ {
TunnelHostname: testTunnelHostname, TunnelHostname: testTunnelHostname,
OriginConfigJSONHandler: &pogs.OriginConfigJSONHandler{
OriginConfig: &pogs.HTTPOriginConfig{ OriginConfig: &pogs.HTTPOriginConfig{
URLString: httpServer.URL, URLString: httpServer.URL,
}, },
}, },
},
} }
streamHandler.UpdateConfig(reverseProxyConfigs) streamHandler.UpdateConfig(reverseProxyConfigs)
@ -99,12 +97,10 @@ func TestServeBadRequest(t *testing.T) {
reverseProxyConfigs := []*pogs.ReverseProxyConfig{ reverseProxyConfigs := []*pogs.ReverseProxyConfig{
{ {
TunnelHostname: testTunnelHostname, TunnelHostname: testTunnelHostname,
OriginConfigJSONHandler: &pogs.OriginConfigJSONHandler{
OriginConfig: &pogs.HTTPOriginConfig{ OriginConfig: &pogs.HTTPOriginConfig{
URLString: "", URLString: "",
}, },
}, },
},
} }
streamHandler.UpdateConfig(reverseProxyConfigs) streamHandler.UpdateConfig(reverseProxyConfigs)
stream, err = muxPair.EdgeMux.OpenStream(ctx, headers, nil) stream, err = muxPair.EdgeMux.OpenStream(ctx, headers, nil)

View File

@ -194,7 +194,7 @@ func TestTunnelHostnameMapper_ToRemove(t *testing.T) {
func sampleConfig1() *pogs.ReverseProxyConfig { func sampleConfig1() *pogs.ReverseProxyConfig {
return &pogs.ReverseProxyConfig{ return &pogs.ReverseProxyConfig{
TunnelHostname: "mock.example.com", TunnelHostname: "mock.example.com",
OriginConfigJSONHandler: &pogs.OriginConfigJSONHandler{OriginConfig: &pogs.HelloWorldOriginConfig{}}, OriginConfig: &pogs.HelloWorldOriginConfig{},
Retries: 18, Retries: 18,
ConnectionTimeout: 5 * time.Second, ConnectionTimeout: 5 * time.Second,
CompressionQuality: 3, CompressionQuality: 3,
@ -204,7 +204,7 @@ func sampleConfig1() *pogs.ReverseProxyConfig {
func sampleConfig2() *pogs.ReverseProxyConfig { func sampleConfig2() *pogs.ReverseProxyConfig {
return &pogs.ReverseProxyConfig{ return &pogs.ReverseProxyConfig{
TunnelHostname: "mock2.example.com", TunnelHostname: "mock2.example.com",
OriginConfigJSONHandler: &pogs.OriginConfigJSONHandler{OriginConfig: &pogs.HelloWorldOriginConfig{}}, OriginConfig: &pogs.HelloWorldOriginConfig{},
Retries: 18, Retries: 18,
ConnectionTimeout: 5 * time.Second, ConnectionTimeout: 5 * time.Second,
CompressionQuality: 3, CompressionQuality: 3,

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/json"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@ -29,11 +28,43 @@ import (
// ClientConfig is a collection of FallibleConfig that determines how cloudflared should function // ClientConfig is a collection of FallibleConfig that determines how cloudflared should function
type ClientConfig struct { type ClientConfig struct {
Version Version `json:"version"` Version Version
SupervisorConfig *SupervisorConfig `json:"supervisor_config"` SupervisorConfig *SupervisorConfig
EdgeConnectionConfig *EdgeConnectionConfig `json:"edge_connection_config"` EdgeConnectionConfig *EdgeConnectionConfig
DoHProxyConfigs []*DoHProxyConfig `json:"doh_proxy_configs" capnp:"dohProxyConfigs"` DoHProxyConfigs []*DoHProxyConfig `capnp:"dohProxyConfigs"`
ReverseProxyConfigs []*ReverseProxyConfig `json:"reverse_proxy_configs"` ReverseProxyConfigs []*ReverseProxyConfig
}
func (c *ClientConfig) MarshalBytes() ([]byte, error) {
msg, firstSeg, err := capnp.NewMessage(capnp.SingleSegment(nil))
if err != nil {
return nil, err
}
capnpEntity, err := tunnelrpc.NewRootClientConfig(firstSeg)
if err != nil {
return nil, err
}
err = MarshalClientConfig(capnpEntity, c)
if err != nil {
return nil, err
}
return msg.Marshal()
}
func UnmarshalClientConfigFromBytes(clientConfigBytes []byte) (*ClientConfig, error) {
msg, err := capnp.Unmarshal(clientConfigBytes)
if err != nil {
return nil, err
}
capnpClientConfig, err := tunnelrpc.ReadRootClientConfig(msg)
if err != nil {
return nil, err
}
pogsClientConfig, err := UnmarshalClientConfig(capnpClientConfig)
if err != nil {
return nil, err
}
return pogsClientConfig, nil
} }
// Version type models the version of a ClientConfig // Version type models the version of a ClientConfig
@ -52,16 +83,17 @@ func (v Version) String() string {
} }
// FallibleConfig is an interface implemented by configs that cloudflared might not be able to apply // FallibleConfig is an interface implemented by configs that cloudflared might not be able to apply
//go-sumtype:decl FallibleConfig
type FallibleConfig interface { type FallibleConfig interface {
FailReason(err error) string FailReason(err error) string
jsonType() string isFallibleConfig()
} }
// SupervisorConfig specifies config of components managed by Supervisor other than ConnectionManager // SupervisorConfig specifies config of components managed by Supervisor other than ConnectionManager
type SupervisorConfig struct { type SupervisorConfig struct {
AutoUpdateFrequency time.Duration `json:"auto_update_frequency"` AutoUpdateFrequency time.Duration
MetricsUpdateFrequency time.Duration `json:"metrics_update_frequency"` MetricsUpdateFrequency time.Duration
GracePeriod time.Duration `json:"grace_period"` GracePeriod time.Duration
} }
// FailReason impelents FallibleConfig interface for SupervisorConfig // FailReason impelents FallibleConfig interface for SupervisorConfig
@ -69,23 +101,15 @@ func (sc *SupervisorConfig) FailReason(err error) string {
return fmt.Sprintf("Cannot apply SupervisorConfig, err: %v", err) return fmt.Sprintf("Cannot apply SupervisorConfig, err: %v", err)
} }
func (sc *SupervisorConfig) MarshalJSON() ([]byte, error) { func (_ *SupervisorConfig) isFallibleConfig() {}
marshaler := make(map[string]SupervisorConfig, 1)
marshaler[sc.jsonType()] = *sc
return json.Marshal(marshaler)
}
func (sc *SupervisorConfig) jsonType() string {
return "supervisor_config"
}
// EdgeConnectionConfig specifies what parameters and how may connections should ConnectionManager establish with edge // EdgeConnectionConfig specifies what parameters and how may connections should ConnectionManager establish with edge
type EdgeConnectionConfig struct { type EdgeConnectionConfig struct {
NumHAConnections uint8 `json:"num_ha_connections"` NumHAConnections uint8
HeartbeatInterval time.Duration `json:"heartbeat_interval"` HeartbeatInterval time.Duration
Timeout time.Duration `json:"timeout"` Timeout time.Duration
MaxFailedHeartbeats uint64 `json:"max_failed_heartbeats"` MaxFailedHeartbeats uint64
UserCredentialPath string `json:"user_credential_path"` UserCredentialPath string
} }
// FailReason impelents FallibleConfig interface for EdgeConnectionConfig // FailReason impelents FallibleConfig interface for EdgeConnectionConfig
@ -93,21 +117,13 @@ func (cmc *EdgeConnectionConfig) FailReason(err error) string {
return fmt.Sprintf("Cannot apply EdgeConnectionConfig, err: %v", err) return fmt.Sprintf("Cannot apply EdgeConnectionConfig, err: %v", err)
} }
func (cmc *EdgeConnectionConfig) MarshalJSON() ([]byte, error) { func (_ *EdgeConnectionConfig) isFallibleConfig() {}
marshaler := make(map[string]EdgeConnectionConfig, 1)
marshaler[cmc.jsonType()] = *cmc
return json.Marshal(marshaler)
}
func (cmc *EdgeConnectionConfig) jsonType() string {
return "edge_connection_config"
}
// DoHProxyConfig is configuration for DNS over HTTPS service // DoHProxyConfig is configuration for DNS over HTTPS service
type DoHProxyConfig struct { type DoHProxyConfig struct {
ListenHost string `json:"listen_host"` ListenHost string
ListenPort uint16 `json:"listen_port"` ListenPort uint16
Upstreams []string `json:"upstreams"` Upstreams []string
} }
// FailReason impelents FallibleConfig interface for DoHProxyConfig // FailReason impelents FallibleConfig interface for DoHProxyConfig
@ -115,23 +131,15 @@ func (dpc *DoHProxyConfig) FailReason(err error) string {
return fmt.Sprintf("Cannot apply DoHProxyConfig, err: %v", err) return fmt.Sprintf("Cannot apply DoHProxyConfig, err: %v", err)
} }
func (dpc *DoHProxyConfig) MarshalJSON() ([]byte, error) { func (_ *DoHProxyConfig) isFallibleConfig() {}
marshaler := make(map[string]DoHProxyConfig, 1)
marshaler[dpc.jsonType()] = *dpc
return json.Marshal(marshaler)
}
func (dpc *DoHProxyConfig) jsonType() string {
return "doh_proxy_config"
}
// ReverseProxyConfig how and for what hostnames can this cloudflared proxy // ReverseProxyConfig how and for what hostnames can this cloudflared proxy
type ReverseProxyConfig struct { type ReverseProxyConfig struct {
TunnelHostname h2mux.TunnelHostname `json:"tunnel_hostname"` TunnelHostname h2mux.TunnelHostname
OriginConfigJSONHandler *OriginConfigJSONHandler `json:"origin_config"` OriginConfig OriginConfig
Retries uint64 `json:"retries"` Retries uint64
ConnectionTimeout time.Duration `json:"connection_timeout"` ConnectionTimeout time.Duration
CompressionQuality uint64 `json:"compression_quality"` CompressionQuality uint64
} }
func NewReverseProxyConfig( func NewReverseProxyConfig(
@ -146,7 +154,7 @@ func NewReverseProxyConfig(
} }
return &ReverseProxyConfig{ return &ReverseProxyConfig{
TunnelHostname: h2mux.TunnelHostname(tunnelHostname), TunnelHostname: h2mux.TunnelHostname(tunnelHostname),
OriginConfigJSONHandler: &OriginConfigJSONHandler{originConfig}, OriginConfig: originConfig,
Retries: retries, Retries: retries,
ConnectionTimeout: connectionTimeout, ConnectionTimeout: connectionTimeout,
CompressionQuality: compressionQuality, CompressionQuality: compressionQuality,
@ -158,58 +166,29 @@ func (rpc *ReverseProxyConfig) FailReason(err error) string {
return fmt.Sprintf("Cannot apply ReverseProxyConfig, err: %v", err) return fmt.Sprintf("Cannot apply ReverseProxyConfig, err: %v", err)
} }
func (rpc *ReverseProxyConfig) MarshalJSON() ([]byte, error) { func (_ *ReverseProxyConfig) isFallibleConfig() {}
marshaler := make(map[string]ReverseProxyConfig, 1)
marshaler[rpc.jsonType()] = *rpc
return json.Marshal(marshaler)
}
func (rpc *ReverseProxyConfig) jsonType() string {
return "reverse_proxy_config"
}
//go-sumtype:decl OriginConfig //go-sumtype:decl OriginConfig
type OriginConfig interface { type OriginConfig interface {
// Service returns a OriginService used to proxy to the origin // Service returns a OriginService used to proxy to the origin
Service() (originservice.OriginService, error) Service() (originservice.OriginService, error)
// go-sumtype requires at least one unexported method, otherwise it will complain that interface is not sealed // go-sumtype requires at least one unexported method, otherwise it will complain that interface is not sealed
jsonType() string isOriginConfig()
}
type originType int
const (
httpType originType = iota
wsType
helloWorldType
)
func (ot originType) String() string {
switch ot {
case httpType:
return "Http"
case wsType:
return "WebSocket"
case helloWorldType:
return "HelloWorld"
default:
return "unknown"
}
} }
type HTTPOriginConfig struct { type HTTPOriginConfig struct {
URLString string `capnp:"urlString" json:"url_string" mapstructure:"url_string"` URLString string `capnp:"urlString"`
TCPKeepAlive time.Duration `capnp:"tcpKeepAlive" json:"tcp_keep_alive" mapstructure:"tcp_keep_alive"` TCPKeepAlive time.Duration `capnp:"tcpKeepAlive"`
DialDualStack bool `json:"dial_dual_stack" mapstructure:"dial_dual_stack"` DialDualStack bool
TLSHandshakeTimeout time.Duration `capnp:"tlsHandshakeTimeout" json:"tls_handshake_timeout" mapstructure:"tls_handshake_timeout"` TLSHandshakeTimeout time.Duration `capnp:"tlsHandshakeTimeout"`
TLSVerify bool `capnp:"tlsVerify" json:"tls_verify" mapstructure:"tls_verify"` TLSVerify bool `capnp:"tlsVerify"`
OriginCAPool string `json:"origin_ca_pool" mapstructure:"origin_ca_pool"` OriginCAPool string
OriginServerName string `json:"origin_server_name" mapstructure:"origin_server_name"` OriginServerName string
MaxIdleConnections uint64 `json:"max_idle_connections" mapstructure:"max_idle_connections"` MaxIdleConnections uint64
IdleConnectionTimeout time.Duration `json:"idle_connection_timeout" mapstructure:"idle_connection_timeout"` IdleConnectionTimeout time.Duration
ProxyConnectionTimeout time.Duration `json:"proxy_connection_timeout" mapstructure:"proxy_connection_timeout"` ProxyConnectionTimeout time.Duration
ExpectContinueTimeout time.Duration `json:"expect_continue_timeout" mapstructure:"expect_continue_timeout"` ExpectContinueTimeout time.Duration
ChunkedEncoding bool `json:"chunked_encoding" mapstructure:"chunked_encoding"` ChunkedEncoding bool
} }
func (hc *HTTPOriginConfig) Service() (originservice.OriginService, error) { func (hc *HTTPOriginConfig) Service() (originservice.OriginService, error) {
@ -248,15 +227,13 @@ func (hc *HTTPOriginConfig) Service() (originservice.OriginService, error) {
return originservice.NewHTTPService(transport, url, hc.ChunkedEncoding), nil return originservice.NewHTTPService(transport, url, hc.ChunkedEncoding), nil
} }
func (_ *HTTPOriginConfig) jsonType() string { func (*HTTPOriginConfig) isOriginConfig() {}
return httpType.String()
}
type WebSocketOriginConfig struct { type WebSocketOriginConfig struct {
URLString string `capnp:"urlString" json:"url_string" mapstructure:"url_string"` URLString string `capnp:"urlString"`
TLSVerify bool `capnp:"tlsVerify" json:"tls_verify" mapstructure:"tls_verify"` TLSVerify bool `capnp:"tlsVerify"`
OriginCAPool string `json:"origin_ca_pool" mapstructure:"origin_ca_pool"` OriginCAPool string
OriginServerName string `json:"origin_server_name" mapstructure:"origin_server_name"` OriginServerName string
} }
func (wsc *WebSocketOriginConfig) Service() (originservice.OriginService, error) { func (wsc *WebSocketOriginConfig) Service() (originservice.OriginService, error) {
@ -277,13 +254,11 @@ func (wsc *WebSocketOriginConfig) Service() (originservice.OriginService, error)
return originservice.NewWebSocketService(tlsConfig, url) return originservice.NewWebSocketService(tlsConfig, url)
} }
func (_ *WebSocketOriginConfig) jsonType() string { func (*WebSocketOriginConfig) isOriginConfig() {}
return wsType.String()
}
type HelloWorldOriginConfig struct{} type HelloWorldOriginConfig struct{}
func (_ *HelloWorldOriginConfig) Service() (originservice.OriginService, error) { func (*HelloWorldOriginConfig) Service() (originservice.OriginService, error) {
helloCert, err := tlsconfig.GetHelloCertificateX509() helloCert, err := tlsconfig.GetHelloCertificateX509()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Cannot get Hello World server certificate") return nil, errors.Wrap(err, "Cannot get Hello World server certificate")
@ -308,9 +283,7 @@ func (_ *HelloWorldOriginConfig) Service() (originservice.OriginService, error)
return originservice.NewHelloWorldService(transport) return originservice.NewHelloWorldService(transport)
} }
func (_ *HelloWorldOriginConfig) jsonType() string { func (*HelloWorldOriginConfig) isOriginConfig() {}
return helloWorldType.String()
}
/* /*
* Boilerplate to convert between these structs and the primitive structs * Boilerplate to convert between these structs and the primitive structs
@ -519,9 +492,9 @@ func UnmarshalDoHProxyConfig(s tunnelrpc.DoHProxyConfig) (*DoHProxyConfig, error
func MarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig, p *ReverseProxyConfig) error { func MarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig, p *ReverseProxyConfig) error {
s.SetTunnelHostname(p.TunnelHostname.String()) s.SetTunnelHostname(p.TunnelHostname.String())
switch config := p.OriginConfigJSONHandler.OriginConfig.(type) { switch config := p.OriginConfig.(type) {
case *HTTPOriginConfig: case *HTTPOriginConfig:
ss, err := s.Origin().NewHttp() ss, err := s.OriginConfig().NewHttp()
if err != nil { if err != nil {
return err return err
} }
@ -529,7 +502,7 @@ func MarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig, p *ReverseProxyCo
return err return err
} }
case *WebSocketOriginConfig: case *WebSocketOriginConfig:
ss, err := s.Origin().NewWebsocket() ss, err := s.OriginConfig().NewWebsocket()
if err != nil { if err != nil {
return err return err
} }
@ -537,7 +510,7 @@ func MarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig, p *ReverseProxyCo
return err return err
} }
case *HelloWorldOriginConfig: case *HelloWorldOriginConfig:
ss, err := s.Origin().NewHelloWorld() ss, err := s.OriginConfig().NewHelloWorld()
if err != nil { if err != nil {
return err return err
} }
@ -560,9 +533,9 @@ func UnmarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig) (*ReverseProxyC
return nil, err return nil, err
} }
p.TunnelHostname = h2mux.TunnelHostname(tunnelHostname) p.TunnelHostname = h2mux.TunnelHostname(tunnelHostname)
switch s.Origin().Which() { switch s.OriginConfig().Which() {
case tunnelrpc.ReverseProxyConfig_origin_Which_http: case tunnelrpc.ReverseProxyConfig_originConfig_Which_http:
ss, err := s.Origin().Http() ss, err := s.OriginConfig().Http()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -570,9 +543,9 @@ func UnmarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig) (*ReverseProxyC
if err != nil { if err != nil {
return nil, err return nil, err
} }
p.OriginConfigJSONHandler = &OriginConfigJSONHandler{config} p.OriginConfig = config
case tunnelrpc.ReverseProxyConfig_origin_Which_websocket: case tunnelrpc.ReverseProxyConfig_originConfig_Which_websocket:
ss, err := s.Origin().Websocket() ss, err := s.OriginConfig().Websocket()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -580,9 +553,9 @@ func UnmarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig) (*ReverseProxyC
if err != nil { if err != nil {
return nil, err return nil, err
} }
p.OriginConfigJSONHandler = &OriginConfigJSONHandler{config} p.OriginConfig = config
case tunnelrpc.ReverseProxyConfig_origin_Which_helloWorld: case tunnelrpc.ReverseProxyConfig_originConfig_Which_helloWorld:
ss, err := s.Origin().HelloWorld() ss, err := s.OriginConfig().HelloWorld()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -590,7 +563,7 @@ func UnmarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig) (*ReverseProxyC
if err != nil { if err != nil {
return nil, err return nil, err
} }
p.OriginConfigJSONHandler = &OriginConfigJSONHandler{config} p.OriginConfig = config
} }
p.Retries = s.Retries() p.Retries = s.Retries()
p.ConnectionTimeout = time.Duration(s.ConnectionTimeout()) p.ConnectionTimeout = time.Duration(s.ConnectionTimeout())
@ -690,13 +663,13 @@ func (i ClientService_PogsImpl) UseConfiguration(p tunnelrpc.ClientService_useCo
} }
type UseConfigurationResult struct { type UseConfigurationResult struct {
Success bool `json:"success"` Success bool
FailedConfigs []*FailedConfig `json:"failed_configs"` FailedConfigs []*FailedConfig
} }
type FailedConfig struct { type FailedConfig struct {
Config FallibleConfig `json:"config"` Config FallibleConfig
Reason string `json:"reason"` Reason string
} }
func MarshalFailedConfig(s tunnelrpc.FailedConfig, p *FailedConfig) error { func MarshalFailedConfig(s tunnelrpc.FailedConfig, p *FailedConfig) error {

View File

@ -61,13 +61,13 @@ func ClientConfigTestCases() []*ClientConfig {
sampleReverseProxyConfig(func(c *ReverseProxyConfig) { sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
}), }),
sampleReverseProxyConfig(func(c *ReverseProxyConfig) { sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleHTTPOriginConfig()} c.OriginConfig = sampleHTTPOriginConfig()
}), }),
sampleReverseProxyConfig(func(c *ReverseProxyConfig) { sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleHTTPOriginConfigUnixPath()} c.OriginConfig = sampleHTTPOriginConfigUnixPath()
}), }),
sampleReverseProxyConfig(func(c *ReverseProxyConfig) { sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleWebSocketOriginConfig()} c.OriginConfig = sampleWebSocketOriginConfig()
}), }),
} }
} }
@ -83,21 +83,14 @@ func ClientConfigTestCases() []*ClientConfig {
} }
func TestClientConfig(t *testing.T) { func TestClientConfig(t *testing.T) {
for i, testCase := range ClientConfigTestCases() { for _, testCase := range ClientConfigTestCases() {
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil)) b, err := testCase.MarshalBytes()
capnpEntity, err := tunnelrpc.NewClientConfig(seg) assert.NoError(t, err)
if !assert.NoError(t, err) {
t.Fatal("Couldn't initialize a new message") clientConfig, err := UnmarshalClientConfigFromBytes(b)
} assert.NoError(t, err)
err = MarshalClientConfig(capnpEntity, testCase)
if !assert.NoError(t, err, "testCase index %v failed to marshal", i) { assert.Equal(t, testCase, clientConfig)
continue
}
result, err := UnmarshalClientConfig(capnpEntity)
if !assert.NoError(t, err, "testCase index %v failed to unmarshal", i) {
continue
}
assert.Equal(t, testCase, result, "testCase index %v didn't preserve struct through marshalling and unmarshalling", i)
} }
} }
@ -167,13 +160,13 @@ func TestReverseProxyConfig(t *testing.T) {
testCases := []*ReverseProxyConfig{ testCases := []*ReverseProxyConfig{
sampleReverseProxyConfig(), sampleReverseProxyConfig(),
sampleReverseProxyConfig(func(c *ReverseProxyConfig) { sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleHTTPOriginConfig()} c.OriginConfig = sampleHTTPOriginConfig()
}), }),
sampleReverseProxyConfig(func(c *ReverseProxyConfig) { sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleHTTPOriginConfigUnixPath()} c.OriginConfig = sampleHTTPOriginConfigUnixPath()
}), }),
sampleReverseProxyConfig(func(c *ReverseProxyConfig) { sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleWebSocketOriginConfig()} c.OriginConfig = sampleWebSocketOriginConfig()
}), }),
} }
for i, testCase := range testCases { for i, testCase := range testCases {
@ -324,7 +317,7 @@ func sampleDoHProxyConfig(overrides ...func(*DoHProxyConfig)) *DoHProxyConfig {
func sampleReverseProxyConfig(overrides ...func(*ReverseProxyConfig)) *ReverseProxyConfig { func sampleReverseProxyConfig(overrides ...func(*ReverseProxyConfig)) *ReverseProxyConfig {
sample := &ReverseProxyConfig{ sample := &ReverseProxyConfig{
TunnelHostname: "mock-non-lb-tunnel.example.com", TunnelHostname: "mock-non-lb-tunnel.example.com",
OriginConfigJSONHandler: &OriginConfigJSONHandler{&HelloWorldOriginConfig{}}, OriginConfig: &HelloWorldOriginConfig{},
Retries: 18, Retries: 18,
ConnectionTimeout: 5 * time.Second, ConnectionTimeout: 5 * time.Second,
CompressionQuality: 3, CompressionQuality: 3,

View File

@ -1,101 +0,0 @@
package pogs
import (
"encoding/json"
"fmt"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
// ScopeUnmarshaler can marshal a Scope pog from JSON.
type ScopeUnmarshaler struct {
Scope Scope
}
// UnmarshalJSON takes in a JSON string, and attempts to marshal it into a Scope.
// If successful, the Scope member of this ScopeUnmarshaler is set and nil is returned.
// If unsuccessful, returns an error.
func (su *ScopeUnmarshaler) UnmarshalJSON(b []byte) error {
var scopeJSON map[string]interface{}
if err := json.Unmarshal(b, &scopeJSON); err != nil {
return errors.Wrapf(err, "cannot unmarshal %s into scopeJSON", string(b))
}
if group, ok := scopeJSON["group"]; ok {
if val, ok := group.(string); ok {
su.Scope = NewGroup(val)
return nil
}
return fmt.Errorf("JSON should have been a Scope, but the 'group' key contained %v", group)
}
if systemName, ok := scopeJSON["system_name"]; ok {
if val, ok := systemName.(string); ok {
su.Scope = NewSystemName(val)
return nil
}
return fmt.Errorf("JSON should have been a Scope, but the 'system_name' key contained %v", systemName)
}
return fmt.Errorf("JSON should have been an object with one root key, either 'system_name' or 'group'")
}
// OriginConfigJSONHandler is a wrapper to serialize OriginConfig with type information, and deserialize JSON
// into an OriginConfig.
type OriginConfigJSONHandler struct {
OriginConfig OriginConfig
}
func (ocjh *OriginConfigJSONHandler) MarshalJSON() ([]byte, error) {
marshaler := make(map[string]OriginConfig, 1)
marshaler[ocjh.OriginConfig.jsonType()] = ocjh.OriginConfig
return json.Marshal(marshaler)
}
func (ocjh *OriginConfigJSONHandler) UnmarshalJSON(b []byte) error {
var originJSON map[string]interface{}
if err := json.Unmarshal(b, &originJSON); err != nil {
return errors.Wrapf(err, "cannot unmarshal %s into originJSON", string(b))
}
if originConfig, ok := originJSON[httpType.String()]; ok {
httpOriginConfig := &HTTPOriginConfig{}
if err := mapstructure.Decode(originConfig, httpOriginConfig); err != nil {
return errors.Wrapf(err, "cannot decode %+v into HTTPOriginConfig", originConfig)
}
ocjh.OriginConfig = httpOriginConfig
return nil
}
if originConfig, ok := originJSON[wsType.String()]; ok {
wsOriginConfig := &WebSocketOriginConfig{}
if err := mapstructure.Decode(originConfig, wsOriginConfig); err != nil {
return errors.Wrapf(err, "cannot decode %+v into WebSocketOriginConfig", originConfig)
}
ocjh.OriginConfig = wsOriginConfig
return nil
}
if originConfig, ok := originJSON[helloWorldType.String()]; ok {
helloWorldOriginConfig := &HelloWorldOriginConfig{}
if err := mapstructure.Decode(originConfig, helloWorldOriginConfig); err != nil {
return errors.Wrapf(err, "cannot decode %+v into HelloWorldOriginConfig", originConfig)
}
ocjh.OriginConfig = helloWorldOriginConfig
return nil
}
return fmt.Errorf("cannot unmarshal %s into OriginConfig", string(b))
}
// FallibleConfigMarshaler is a wrapper for FallibleConfig to implement custom marshal logic
type FallibleConfigMarshaler struct {
FallibleConfig FallibleConfig
}
func (fcm *FallibleConfigMarshaler) MarshalJSON() ([]byte, error) {
marshaler := make(map[string]FallibleConfig, 1)
marshaler[fcm.FallibleConfig.jsonType()] = fcm.FallibleConfig
return json.Marshal(marshaler)
}

View File

@ -1,342 +0,0 @@
package pogs
import (
"encoding/json"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestScopeUnmarshaler_UnmarshalJSON(t *testing.T) {
type fields struct {
Scope Scope
}
type args struct {
b []byte
}
tests := []struct {
name string
fields fields
args args
wantErr bool
wantScope Scope
}{
{
name: "group_successful",
args: args{b: []byte(`{"group": "my-group"}`)},
wantScope: NewGroup("my-group"),
},
{
name: "system_name_successful",
args: args{b: []byte(`{"system_name": "my-computer"}`)},
wantScope: NewSystemName("my-computer"),
},
{
name: "not_a_scope",
args: args{b: []byte(`{"x": "y"}`)},
wantErr: true,
},
{
name: "malformed_group",
args: args{b: []byte(`{"group": ["a", "b"]}`)},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
su := &ScopeUnmarshaler{
Scope: tt.fields.Scope,
}
err := su.UnmarshalJSON(tt.args.b)
if !tt.wantErr {
if err != nil {
t.Errorf("ScopeUnmarshaler.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
}
if !eqScope(tt.wantScope, su.Scope) {
t.Errorf("Wanted scope %v but got scope %v", tt.wantScope, su.Scope)
}
}
})
}
}
func TestUnmarshalOrigin(t *testing.T) {
tests := []struct {
jsonLiteral string
exceptedOriginConfig OriginConfig
}{
{
jsonLiteral: `{
"Http":{
"url_string":"https.example.com",
"tcp_keep_alive":7000000000,
"dial_dual_stack":true,
"tls_handshake_timeout":11000000000,
"tls_verify":true,
"origin_ca_pool":"/etc/cert.pem",
"origin_server_name":"secure.example.com",
"max_idle_connections":19,
"idle_connection_timeout":17000000000,
"proxy_connection_timeout":15000000000,
"expect_continue_timeout":21000000000,
"chunked_encoding":true
}
}`,
exceptedOriginConfig: sampleHTTPOriginConfig(),
},
{
jsonLiteral: `{
"WebSocket":{
"url_string":"ssh://example.com",
"tls_verify":true,
"origin_ca_pool":"/etc/cert.pem",
"origin_server_name":"secure.example.com"
}
}`,
exceptedOriginConfig: sampleWebSocketOriginConfig(),
},
{
jsonLiteral: `{
"HelloWorld": {}
}`,
exceptedOriginConfig: &HelloWorldOriginConfig{},
},
}
for _, test := range tests {
originConfigJSON := prettyToValidJSON(test.jsonLiteral)
var OriginConfigJSONHandler OriginConfigJSONHandler
err := json.Unmarshal([]byte(originConfigJSON), &OriginConfigJSONHandler)
assert.NoError(t, err)
assert.Equal(t, test.exceptedOriginConfig, OriginConfigJSONHandler.OriginConfig)
}
}
func TestUnmarshalClientConfig(t *testing.T) {
prettyClientConfigJSON := `{
"version":10,
"supervisor_config":{
"auto_update_frequency":86400000000000,
"metrics_update_frequency":300000000000,
"grace_period":30000000000
},
"edge_connection_config":{
"num_ha_connections":4,
"heartbeat_interval":5000000000,
"timeout":30000000000,
"max_failed_heartbeats":5,
"user_credential_path":"~/.cloudflared/cert.pem"
},
"doh_proxy_configs":[{
"listen_host": "localhost",
"listen_port": 53,
"upstreams": ["https://1.1.1.1/dns-query", "https://1.0.0.1/dns-query"]
}],
"reverse_proxy_configs":[{
"tunnel_hostname":"sdfjadk33.cftunnel.com",
"origin_config":{
"Http":{
"url_string":"https://127.0.0.1:8080",
"tcp_keep_alive":30000000000,
"dial_dual_stack":true,
"tls_handshake_timeout":10000000000,
"tls_verify":true,
"origin_ca_pool":"",
"origin_server_name":"",
"max_idle_connections":100,
"idle_connection_timeout":90000000000,
"proxy_connection_timeout":90000000000,
"expect_continue_timeout":90000000000,
"chunked_encoding":true
}
},
"retries":5,
"connection_timeout":30,
"compression_quality":0
}]
}`
// replace new line and tab
clientConfigJSON := prettyToValidJSON(prettyClientConfigJSON)
var clientConfig ClientConfig
err := json.Unmarshal([]byte(clientConfigJSON), &clientConfig)
assert.NoError(t, err)
assert.Equal(t, Version(10), clientConfig.Version)
supervisorConfig := SupervisorConfig{
AutoUpdateFrequency: time.Hour * 24,
MetricsUpdateFrequency: time.Second * 300,
GracePeriod: time.Second * 30,
}
assert.Equal(t, supervisorConfig, *clientConfig.SupervisorConfig)
edgeConnectionConfig := EdgeConnectionConfig{
NumHAConnections: 4,
HeartbeatInterval: time.Second * 5,
Timeout: time.Second * 30,
MaxFailedHeartbeats: 5,
UserCredentialPath: "~/.cloudflared/cert.pem",
}
assert.Equal(t, edgeConnectionConfig, *clientConfig.EdgeConnectionConfig)
dohProxyConfig := DoHProxyConfig{
ListenHost: "localhost",
ListenPort: 53,
Upstreams: []string{"https://1.1.1.1/dns-query", "https://1.0.0.1/dns-query"},
}
assert.Len(t, clientConfig.DoHProxyConfigs, 1)
assert.Equal(t, dohProxyConfig, *clientConfig.DoHProxyConfigs[0])
reverseProxyConfig := ReverseProxyConfig{
TunnelHostname: "sdfjadk33.cftunnel.com",
OriginConfigJSONHandler: &OriginConfigJSONHandler{
OriginConfig: &HTTPOriginConfig{
URLString: "https://127.0.0.1:8080",
TCPKeepAlive: time.Second * 30,
DialDualStack: true,
TLSHandshakeTimeout: time.Second * 10,
TLSVerify: true,
OriginCAPool: "",
OriginServerName: "",
MaxIdleConnections: 100,
IdleConnectionTimeout: time.Second * 90,
ProxyConnectionTimeout: time.Second * 90,
ExpectContinueTimeout: time.Second * 90,
ChunkedEncoding: true,
},
},
Retries: 5,
ConnectionTimeout: 30,
CompressionQuality: 0,
}
assert.Len(t, clientConfig.ReverseProxyConfigs, 1)
assert.Equal(t, reverseProxyConfig, *clientConfig.ReverseProxyConfigs[0])
}
func TestMarshalFallibleConfig(t *testing.T) {
tests := []struct {
fallibleConfig FallibleConfig
expctedJSONLiteral string
}{
{
fallibleConfig: sampleSupervisorConfig(),
expctedJSONLiteral: `{
"supervisor_config":{
"auto_update_frequency":75600000000000,
"metrics_update_frequency":660000000000,
"grace_period":31000000000
}
}`,
},
{
fallibleConfig: sampleEdgeConnectionConfig(),
expctedJSONLiteral: `{
"edge_connection_config":{
"num_ha_connections":49,
"heartbeat_interval":5000000000,
"timeout":9000000000,
"max_failed_heartbeats":9001,
"user_credential_path":"/Users/example/.cloudflared/cert.pem"
}
}`,
},
{
fallibleConfig: sampleDoHProxyConfig(),
expctedJSONLiteral: `{
"doh_proxy_config":{
"listen_host":"127.0.0.1",
"listen_port":53,
"upstreams":["1.1.1.1","1.0.0.1"]
}
}`,
},
{
fallibleConfig: sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleHTTPOriginConfig()}
}),
expctedJSONLiteral: `{
"reverse_proxy_config":{
"tunnel_hostname":"mock-non-lb-tunnel.example.com",
"origin_config":{
"Http":{
"url_string":"https.example.com",
"tcp_keep_alive":7000000000,
"dial_dual_stack":true,
"tls_handshake_timeout":11000000000,
"tls_verify":true,
"origin_ca_pool":"/etc/cert.pem",
"origin_server_name":"secure.example.com",
"max_idle_connections":19,
"idle_connection_timeout":17000000000,
"proxy_connection_timeout":15000000000,
"expect_continue_timeout":21000000000,
"chunked_encoding":true
}
},
"retries":18,
"connection_timeout":5000000000,
"compression_quality":3
}
}`,
},
{
fallibleConfig: sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{sampleWebSocketOriginConfig()}
}),
expctedJSONLiteral: `{
"reverse_proxy_config":{
"tunnel_hostname":"mock-non-lb-tunnel.example.com",
"origin_config":{
"WebSocket":{
"url_string":"ssh://example.com",
"tls_verify":true,
"origin_ca_pool":"/etc/cert.pem",
"origin_server_name":"secure.example.com"
}
},
"retries":18,
"connection_timeout":5000000000,
"compression_quality":3
}
}`,
},
{
fallibleConfig: sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
c.OriginConfigJSONHandler = &OriginConfigJSONHandler{&HelloWorldOriginConfig{}}
}),
expctedJSONLiteral: `{
"reverse_proxy_config":{
"tunnel_hostname":"mock-non-lb-tunnel.example.com",
"origin_config":{
"HelloWorld":{}
},
"retries":18,
"connection_timeout":5000000000,
"compression_quality":3
}
}`,
},
}
for _, test := range tests {
b, err := json.Marshal(test.fallibleConfig)
assert.NoError(t, err)
assert.Equal(t, prettyToValidJSON(test.expctedJSONLiteral), string(b))
}
}
type prettyJSON string
func prettyToValidJSON(prettyJSON string) string {
return strings.ReplaceAll(strings.ReplaceAll(prettyJSON, "\n", ""), "\t", "")
}
func eqScope(s1, s2 Scope) bool {
return s1.Value() == s2.Value() && s1.PostgresType() == s2.PostgresType()
}

View File

@ -136,7 +136,7 @@ struct EdgeConnectionConfig {
struct ReverseProxyConfig { struct ReverseProxyConfig {
tunnelHostname @0 :Text; tunnelHostname @0 :Text;
origin :union { originConfig :union {
http @1 :HTTPOriginConfig; http @1 :HTTPOriginConfig;
websocket @2 :WebSocketOriginConfig; websocket @2 :WebSocketOriginConfig;
helloWorld @3 :HelloWorldOriginConfig; helloWorld @3 :HelloWorldOriginConfig;

View File

@ -1374,27 +1374,27 @@ func (p EdgeConnectionConfig_Promise) Struct() (EdgeConnectionConfig, error) {
} }
type ReverseProxyConfig struct{ capnp.Struct } type ReverseProxyConfig struct{ capnp.Struct }
type ReverseProxyConfig_origin ReverseProxyConfig type ReverseProxyConfig_originConfig ReverseProxyConfig
type ReverseProxyConfig_origin_Which uint16 type ReverseProxyConfig_originConfig_Which uint16
const ( const (
ReverseProxyConfig_origin_Which_http ReverseProxyConfig_origin_Which = 0 ReverseProxyConfig_originConfig_Which_http ReverseProxyConfig_originConfig_Which = 0
ReverseProxyConfig_origin_Which_websocket ReverseProxyConfig_origin_Which = 1 ReverseProxyConfig_originConfig_Which_websocket ReverseProxyConfig_originConfig_Which = 1
ReverseProxyConfig_origin_Which_helloWorld ReverseProxyConfig_origin_Which = 2 ReverseProxyConfig_originConfig_Which_helloWorld ReverseProxyConfig_originConfig_Which = 2
) )
func (w ReverseProxyConfig_origin_Which) String() string { func (w ReverseProxyConfig_originConfig_Which) String() string {
const s = "httpwebsockethelloWorld" const s = "httpwebsockethelloWorld"
switch w { switch w {
case ReverseProxyConfig_origin_Which_http: case ReverseProxyConfig_originConfig_Which_http:
return s[0:4] return s[0:4]
case ReverseProxyConfig_origin_Which_websocket: case ReverseProxyConfig_originConfig_Which_websocket:
return s[4:13] return s[4:13]
case ReverseProxyConfig_origin_Which_helloWorld: case ReverseProxyConfig_originConfig_Which_helloWorld:
return s[13:23] return s[13:23]
} }
return "ReverseProxyConfig_origin_Which(" + strconv.FormatUint(uint64(w), 10) + ")" return "ReverseProxyConfig_originConfig_Which(" + strconv.FormatUint(uint64(w), 10) + ")"
} }
// ReverseProxyConfig_TypeID is the unique identifier for the type ReverseProxyConfig. // ReverseProxyConfig_TypeID is the unique identifier for the type ReverseProxyConfig.
@ -1439,12 +1439,14 @@ func (s ReverseProxyConfig) SetTunnelHostname(v string) error {
return s.Struct.SetText(0, v) return s.Struct.SetText(0, v)
} }
func (s ReverseProxyConfig) Origin() ReverseProxyConfig_origin { return ReverseProxyConfig_origin(s) } func (s ReverseProxyConfig) OriginConfig() ReverseProxyConfig_originConfig {
return ReverseProxyConfig_originConfig(s)
func (s ReverseProxyConfig_origin) Which() ReverseProxyConfig_origin_Which {
return ReverseProxyConfig_origin_Which(s.Struct.Uint16(0))
} }
func (s ReverseProxyConfig_origin) Http() (HTTPOriginConfig, error) {
func (s ReverseProxyConfig_originConfig) Which() ReverseProxyConfig_originConfig_Which {
return ReverseProxyConfig_originConfig_Which(s.Struct.Uint16(0))
}
func (s ReverseProxyConfig_originConfig) Http() (HTTPOriginConfig, error) {
if s.Struct.Uint16(0) != 0 { if s.Struct.Uint16(0) != 0 {
panic("Which() != http") panic("Which() != http")
} }
@ -1452,7 +1454,7 @@ func (s ReverseProxyConfig_origin) Http() (HTTPOriginConfig, error) {
return HTTPOriginConfig{Struct: p.Struct()}, err return HTTPOriginConfig{Struct: p.Struct()}, err
} }
func (s ReverseProxyConfig_origin) HasHttp() bool { func (s ReverseProxyConfig_originConfig) HasHttp() bool {
if s.Struct.Uint16(0) != 0 { if s.Struct.Uint16(0) != 0 {
return false return false
} }
@ -1460,14 +1462,14 @@ func (s ReverseProxyConfig_origin) HasHttp() bool {
return p.IsValid() || err != nil return p.IsValid() || err != nil
} }
func (s ReverseProxyConfig_origin) SetHttp(v HTTPOriginConfig) error { func (s ReverseProxyConfig_originConfig) SetHttp(v HTTPOriginConfig) error {
s.Struct.SetUint16(0, 0) s.Struct.SetUint16(0, 0)
return s.Struct.SetPtr(1, v.Struct.ToPtr()) return s.Struct.SetPtr(1, v.Struct.ToPtr())
} }
// NewHttp sets the http field to a newly // NewHttp sets the http field to a newly
// allocated HTTPOriginConfig struct, preferring placement in s's segment. // allocated HTTPOriginConfig struct, preferring placement in s's segment.
func (s ReverseProxyConfig_origin) NewHttp() (HTTPOriginConfig, error) { func (s ReverseProxyConfig_originConfig) NewHttp() (HTTPOriginConfig, error) {
s.Struct.SetUint16(0, 0) s.Struct.SetUint16(0, 0)
ss, err := NewHTTPOriginConfig(s.Struct.Segment()) ss, err := NewHTTPOriginConfig(s.Struct.Segment())
if err != nil { if err != nil {
@ -1477,7 +1479,7 @@ func (s ReverseProxyConfig_origin) NewHttp() (HTTPOriginConfig, error) {
return ss, err return ss, err
} }
func (s ReverseProxyConfig_origin) Websocket() (WebSocketOriginConfig, error) { func (s ReverseProxyConfig_originConfig) Websocket() (WebSocketOriginConfig, error) {
if s.Struct.Uint16(0) != 1 { if s.Struct.Uint16(0) != 1 {
panic("Which() != websocket") panic("Which() != websocket")
} }
@ -1485,7 +1487,7 @@ func (s ReverseProxyConfig_origin) Websocket() (WebSocketOriginConfig, error) {
return WebSocketOriginConfig{Struct: p.Struct()}, err return WebSocketOriginConfig{Struct: p.Struct()}, err
} }
func (s ReverseProxyConfig_origin) HasWebsocket() bool { func (s ReverseProxyConfig_originConfig) HasWebsocket() bool {
if s.Struct.Uint16(0) != 1 { if s.Struct.Uint16(0) != 1 {
return false return false
} }
@ -1493,14 +1495,14 @@ func (s ReverseProxyConfig_origin) HasWebsocket() bool {
return p.IsValid() || err != nil return p.IsValid() || err != nil
} }
func (s ReverseProxyConfig_origin) SetWebsocket(v WebSocketOriginConfig) error { func (s ReverseProxyConfig_originConfig) SetWebsocket(v WebSocketOriginConfig) error {
s.Struct.SetUint16(0, 1) s.Struct.SetUint16(0, 1)
return s.Struct.SetPtr(1, v.Struct.ToPtr()) return s.Struct.SetPtr(1, v.Struct.ToPtr())
} }
// NewWebsocket sets the websocket field to a newly // NewWebsocket sets the websocket field to a newly
// allocated WebSocketOriginConfig struct, preferring placement in s's segment. // allocated WebSocketOriginConfig struct, preferring placement in s's segment.
func (s ReverseProxyConfig_origin) NewWebsocket() (WebSocketOriginConfig, error) { func (s ReverseProxyConfig_originConfig) NewWebsocket() (WebSocketOriginConfig, error) {
s.Struct.SetUint16(0, 1) s.Struct.SetUint16(0, 1)
ss, err := NewWebSocketOriginConfig(s.Struct.Segment()) ss, err := NewWebSocketOriginConfig(s.Struct.Segment())
if err != nil { if err != nil {
@ -1510,7 +1512,7 @@ func (s ReverseProxyConfig_origin) NewWebsocket() (WebSocketOriginConfig, error)
return ss, err return ss, err
} }
func (s ReverseProxyConfig_origin) HelloWorld() (HelloWorldOriginConfig, error) { func (s ReverseProxyConfig_originConfig) HelloWorld() (HelloWorldOriginConfig, error) {
if s.Struct.Uint16(0) != 2 { if s.Struct.Uint16(0) != 2 {
panic("Which() != helloWorld") panic("Which() != helloWorld")
} }
@ -1518,7 +1520,7 @@ func (s ReverseProxyConfig_origin) HelloWorld() (HelloWorldOriginConfig, error)
return HelloWorldOriginConfig{Struct: p.Struct()}, err return HelloWorldOriginConfig{Struct: p.Struct()}, err
} }
func (s ReverseProxyConfig_origin) HasHelloWorld() bool { func (s ReverseProxyConfig_originConfig) HasHelloWorld() bool {
if s.Struct.Uint16(0) != 2 { if s.Struct.Uint16(0) != 2 {
return false return false
} }
@ -1526,14 +1528,14 @@ func (s ReverseProxyConfig_origin) HasHelloWorld() bool {
return p.IsValid() || err != nil return p.IsValid() || err != nil
} }
func (s ReverseProxyConfig_origin) SetHelloWorld(v HelloWorldOriginConfig) error { func (s ReverseProxyConfig_originConfig) SetHelloWorld(v HelloWorldOriginConfig) error {
s.Struct.SetUint16(0, 2) s.Struct.SetUint16(0, 2)
return s.Struct.SetPtr(1, v.Struct.ToPtr()) return s.Struct.SetPtr(1, v.Struct.ToPtr())
} }
// NewHelloWorld sets the helloWorld field to a newly // NewHelloWorld sets the helloWorld field to a newly
// allocated HelloWorldOriginConfig struct, preferring placement in s's segment. // allocated HelloWorldOriginConfig struct, preferring placement in s's segment.
func (s ReverseProxyConfig_origin) NewHelloWorld() (HelloWorldOriginConfig, error) { func (s ReverseProxyConfig_originConfig) NewHelloWorld() (HelloWorldOriginConfig, error) {
s.Struct.SetUint16(0, 2) s.Struct.SetUint16(0, 2)
ss, err := NewHelloWorldOriginConfig(s.Struct.Segment()) ss, err := NewHelloWorldOriginConfig(s.Struct.Segment())
if err != nil { if err != nil {
@ -1597,27 +1599,27 @@ func (p ReverseProxyConfig_Promise) Struct() (ReverseProxyConfig, error) {
return ReverseProxyConfig{s}, err return ReverseProxyConfig{s}, err
} }
func (p ReverseProxyConfig_Promise) Origin() ReverseProxyConfig_origin_Promise { func (p ReverseProxyConfig_Promise) OriginConfig() ReverseProxyConfig_originConfig_Promise {
return ReverseProxyConfig_origin_Promise{p.Pipeline} return ReverseProxyConfig_originConfig_Promise{p.Pipeline}
} }
// ReverseProxyConfig_origin_Promise is a wrapper for a ReverseProxyConfig_origin promised by a client call. // ReverseProxyConfig_originConfig_Promise is a wrapper for a ReverseProxyConfig_originConfig promised by a client call.
type ReverseProxyConfig_origin_Promise struct{ *capnp.Pipeline } type ReverseProxyConfig_originConfig_Promise struct{ *capnp.Pipeline }
func (p ReverseProxyConfig_origin_Promise) Struct() (ReverseProxyConfig_origin, error) { func (p ReverseProxyConfig_originConfig_Promise) Struct() (ReverseProxyConfig_originConfig, error) {
s, err := p.Pipeline.Struct() s, err := p.Pipeline.Struct()
return ReverseProxyConfig_origin{s}, err return ReverseProxyConfig_originConfig{s}, err
} }
func (p ReverseProxyConfig_origin_Promise) Http() HTTPOriginConfig_Promise { func (p ReverseProxyConfig_originConfig_Promise) Http() HTTPOriginConfig_Promise {
return HTTPOriginConfig_Promise{Pipeline: p.Pipeline.GetPipeline(1)} return HTTPOriginConfig_Promise{Pipeline: p.Pipeline.GetPipeline(1)}
} }
func (p ReverseProxyConfig_origin_Promise) Websocket() WebSocketOriginConfig_Promise { func (p ReverseProxyConfig_originConfig_Promise) Websocket() WebSocketOriginConfig_Promise {
return WebSocketOriginConfig_Promise{Pipeline: p.Pipeline.GetPipeline(1)} return WebSocketOriginConfig_Promise{Pipeline: p.Pipeline.GetPipeline(1)}
} }
func (p ReverseProxyConfig_origin_Promise) HelloWorld() HelloWorldOriginConfig_Promise { func (p ReverseProxyConfig_originConfig_Promise) HelloWorld() HelloWorldOriginConfig_Promise {
return HelloWorldOriginConfig_Promise{Pipeline: p.Pipeline.GetPipeline(1)} return HelloWorldOriginConfig_Promise{Pipeline: p.Pipeline.GetPipeline(1)}
} }
@ -3704,229 +3706,228 @@ func (p ClientService_useConfiguration_Results_Promise) Result() UseConfiguratio
return UseConfigurationResult_Promise{Pipeline: p.Pipeline.GetPipeline(0)} return UseConfigurationResult_Promise{Pipeline: p.Pipeline.GetPipeline(0)}
} }
const schema_db8274f9144abc7e = "x\xda\xacY}l]\xe5y\x7f\x9e\xf3^\xfb\xd8\x89" + const schema_db8274f9144abc7e = "x\xda\xacY}p\x1c\xe5y\x7f\x9e}OZ\xc9\xd6" +
"o\xae\x0f\xe7\"b\x13\xcbU\x04jCI\x06\xf1\xb2" + "\xf9n\xd9\xcb`\x09k\x94z\xc8$&\xd8\xc5Vi" +
"\x11o\xeb\x8d\xed$\xb5\xdd|\xdc\xe3\x8f\x00!\x91r" + "\xb1Zr\x96d;\x92\xe2\x8f[}\x18b\xcc\x8c\xd7" +
"r\xef\xeb\xeb\xe3\x9c{\xce\xcd\xf9\x08v\x946\x90\x85" + "w\xaf\xa4\x95\xf7vO\xfba$\x8f\x89\xb1\xeb\x14\xac" +
"\x01\x1e)\x09m&\x92\x86\x0a\xb2f|(]\x09\x0d" + "B0$\xee`b2\xe0\xc6\xe5c\x9c\x06\x133-" +
"\xda\xca\xa0*\xd3\x18d\xad\x04h0\xc1\xc6\xfeX!" + "\x142i\xa7\x14\xdc$\x03\xb4\xd0!-\xfc\x13\xf0t" +
"\x9a@\x8b\x18\xb4\x12\xa2*\x9c\xe99\xdf\xbe\xbeu\xc2" + "\xca\x94\xa1&\xc90\xc9$l\xe7\xd9o\x9d\x0e\xd9\xee" +
"\xd4\x7f\x92\xab\xe7<\xef\xfb>\x9f\xbf\xe7\xc37e[" + "\xf4\x1f\xfb\xe6\xd9\xe7}\xdf\xe7\xf3\xf7|\xe8\x86\\\xeb" +
"\xd7\x0977\x99Y\x00\xe5TS\xb3\xf7\xa7\xd5WO" + "\x06am\x93\x99\x05PN65{\x7fR}\xf5\xd4" +
"\xff\xd1\xf1\x9f\x1f\x06\xa9S\xf0\xbe\xf5\xfcp\xfeS\xe7" + "\x1f\x1e\xff\xf1\x11\x90:\x04\xefk/\x0c\x15~\xed\x1c" +
"\xd0\x7f\x00`\xcf#\xcd\xfbQ>\xd7,\x02\xc8?l" + "\xfe\x0f\x00\xec~\xa4y?\xcag\x9bE\x00\xf9{\xcd" +
"\xde\x0a\xe8\xfd\xebM\x07\xde\xdb\xf5\xabc\xf7\x81\xd4\x89" + "\xdb\x01\xbd\x7f\xbd\xe1\xc0{\xbb\x7f\xf1\xc0= u`" +
"\x09gF\x04\xe8y\xa9y\x16\xe5\xffl\x16\x81y\x8f" + "\xc2\x99\x11\x01\xba_j\x9eC\xf9\x9df\x11\x98\xf7\xc8" +
"\xdc\x91\xff\x17|\xf4\x93c }\x05\x01\x9a\x90>\xff" + "m\x85\x7f\xc6G?~\x00\xa4/ @\x13\xd2\xe7\xe7" +
"\xa4y\x91\x00(\xbf\xde\\\x00\xf4^\xbd\xf1\xf9\xe7\x8e" + "\x9a\x97\x08\x80\xf2\xeb\xcdE@\xef\xd5\xeb_x\xfe\xd8" +
"\xfe\xf8\xde\xef\x81\xf2eD\x08\xce\x7f\xd4\xfc\x1b\x04\x94" + "\x0f\xee\xfe6(\x9fG\x84\xe0\xfc\xc5\xe6\xdf \xa0\xdc" +
"\x9bDb\xf8\xe8\x07_\xcd\xfc\xf0\xd5\xab\xbe\xef3x" + "$\x12\xc3\xc5\xef~1\xf3\xbdW\xaf\xfa\x8e\xcf\xe0\x9d" +
"g^\xbf\xf5\x99\xa3?\xfe\xd2\x070.\x88\x98\x01\xe8" + "~\xfd\x96g\x8e\xfd\xe0\xb3\xef\xc3\x98 b\x06\xa0{" +
"Y)Z\xc4\xbbV\xfco@\xef\xbbo\xbd\xb0\xa5z" + "\xb5h\x11\xefz\xf1?\x01\xbdo\xbd\xf5\xe2\xb6\xea\x03" +
"\xec\xe4i\x90\xbe\x1c\xdd\xd5\xd1\"\x08\x90\xf1\xd6\xfc\xfb" + "\x0f\x9f\x02\xe9\xf3\xd1]\xed-\x82\x00\x19\xef\xc6\x7f\xbf" +
"\xc5\xad\x9b\x9f\x99x<\xf8\x12\xc8\x91my\x86\x8ev" + "\xb0}\xeb3\xe3\x8f\x07_\x029\xb2-\xcf\xd0\xd1\xce" +
"\xb5\xd03\xaf\xdc\xd9\xfe@\xdf\x1f?\xf88(\x9d\x98" + "\x16z\xe6\x95;\xf2\xf7\xf6\xfe\xd1\xfd\x8f\x83\xd2\x81)" +
"\xd2\xa7\xa9\x898\xfbZfQ\xbe\xbd\x85~\x8e\xb7\xdc" + "}\x9a\x9a\x88\xb3\xb7e\x0e\xe5\xaf\xb6\xd0\xcf\xb1\x96[" +
"\x8a\x80\xde\xec\xda\x17\xb6\xfd\xea/\xec\xa7@Y\x89\x19" + "\x10\xd0\x9b[\xff\xe2\x8e_\xfc\x99\xfd\x14(\xab1\xe3" +
"\xef\x9f\xee\x7fw\xdf\x8a''^\xf6\xa5b\x00=\x17" + "\xfd\xe3\xd1w\xf7\xadzr\xfce_*\x06\xd0}\xbe" +
"ZO\xd3\xd5o\xb7\xfe\x08\xd0\xcb\xfe\xc3\x0d[\x1e|" + "\xf5_\xe8\xeawZ\xbf\x0f\xe8e\xff\xee\xbam\xf7\xbf" +
"o\xd39\xba:e\xd4@\x88\x99E\xbd(\xdf\xbf\x88" + "\xb7\xe5,]\x9d2j \xc4\x9dKzP\xbeo\x09" +
"\xecz\xcf\"\xe2~\xed\xc6m?\xfd\xe9\xd3\x95s\xf5" + "\xd9\xf5\xe8\x12\xe2~\xed\xfa\x1d?\xfc\xe1\xd3\x13g\xeb" +
"\x82\x08\xc4}\xfd\xe2a\x94\xd7.&\xee5\x8b\x89\xfb" + "\x05\x11\x88{\xd5\xd2!\x94o^J\xdc\xeb\x97\x12\xf7" +
"\xea!|\xe7g7g\xfe.\xd4\x8b\x11\xd3\xfb\x8b?" + "g\x06\xf1\xed\x1f\xad\xcd\xfcM\xa8\x17#\xa6\x0f\x96\xbe" +
"\xa0\xc7?\xf3\x19\xee\xf8\xed\xb3\xff\xb8\xe1\xc37~\x92" + "O\x8fc\x1b1\xdc\xf6\xdbg\xffa\xd3\x87o<\x97" +
"v\xc0#m\x029\xe0\\\x1b)\xdeu\xa9?k|" + "v\xc0cm\x029\xe0\xd96R\xbc\xf3\x83\xbe\xac\xf1" +
"x\xe8gs\xfd\x18\xdc\xf4v\xdb0\xca\x97\xda\xe8\xb9" + "\xe1\xe1\x1f\xcd\xf7cp\xd3;mC(_l\xa3\xe7" +
"\xf7\xdb\xe8\xb6\xbfr\xdfz\xc3\x1c\x1e~\xa9^8\xff" + ">\xf0o\xfb\x0b\xf7\xad7\xcc\xa1\xa1\x97\xea\x85\xf3\xaf" +
"\xda{\xb2\x02\xca\xc7\xb2\xc4}$[\x00\xfc\xe4\xa9{" + "=\x9a\x15P>\x9e%\xee\x07\xb2E\xc0\x8f\x9f\xba\xfb" +
"\x8f\x0e\xbd\xbb\xfee\xa5\x133\xf5\xbc\xc7\xb2\xfbQ>" + "\xd8\xe0\xbb\x1b_V:0S\xcf{<\xbb\x1f\xe5'" +
"C\xbc=\x8fe\xbb\xc9\xa2\xb1\x0d\xeb\xd8}\xbd__" + "\x89\xb7\xfbt\xb6\x8b,\x1a\xdb\xb0\x8e\xdd\xd7\xfb\xcde" +
"2\x85\xf2\xc5%\xf4\xf3\xbf\x96\xf8\xec\xc3w|\xe7\xa1" + "S(\xff\xd72\xfaya\x99\xcf>t\xdb7\x1fl" +
"\xa6\x8b\xdfy\xb9\xde\xa8\xa2o\x81\x9c\x85\xf2g9\xfa" + "\xba\xf0\xcd\x97\xeb\x8d*\xfa\x01\x94\xb3Pn\xca\xd3O" +
"\xf9i\xeeq\x01\xd0\xfb\xcd\xd9?\xe7\x17W\xbdr\x01" + "\xcc?.\x00z\xbf9\xf3\xa7\xfc\xc2\x9aW\xce\x83\xf2" +
"\x94/aJ\x8dq\x14Q\x00\xe8\xb9x\xd5j2\xd9" + "YL\xa91\x86\"\x0ad\xb2\xab\xd6\x91\xc9~u\xd5" +
"\xa5\xab\xee\x04\xf4:\x9f\xfe\x93\xbf\xed/\xbf\xfd\xf3:" + "\x1d\x80^\xc7\xd3\x7f\xfc\xd7}\x95\x9f\xfd\xb8\xce\"$" +
"\x8b\x90 \xf2f\xf9c\xf9v\x99~\x8d\xcb\xc4{\xef" + "\x88<&\x7f$\xab2\xfd\xba]&\xde\xbb\xbf8\xbb" +
"Wg\xf6o\xb9~\xf6\xcd\x86\x069'\xcf\xa2|\xc1" + "\x7f\xdb\xe7\xe6\xdelh\x90\xe7\xe49\x94_\xf7\xb9\x7f" +
"\xe7~\xc9\xe7\x16.\xaa\x1dw\xfd\xdb\xd7\xdeI\xc5\xe7" + "\xeas\x0b\x17\xd4\xf6\xbb\xfe\xedKo\xa7\xe2\xf3\xe6\xc2" +
"\x9a\xfc/\x112\xde\x96mwL\xb5~\xf3\xddw\xd3" + "\xcf\x112\xde\xb6\x1d\xb7M\xb5\xde\xf9\xee\xbb\xe9\xf8\\" +
"\xf1\xb9\"\xef\xfb\xf1\xcf\xf2\xe4\xa6\xf3\xd2C\xf2\xf3\x8f" + "[\xf0\xfd\xb8\xa9@n:'=(\xbf\xf0\xd8_\xbd" +
"\xfd\xcd{\xf4\x90X\xef\xa7\x9d\xf9\xed(\xef\xcd\xd3\xcf" + "G\x0f\x89\xf5~\xe2\x85\x9d(\xcf\x16\xe8\xa7[\xf0\xf5" +
"j\xde\xd77\xce\x93FQ\xa4]\xd3\x8b\xf2\xcc5$" + "\x8d\xf3\xa4Q\x14M_\xdd\x83\xf2\xa1\xabI\xae;\xaf" +
"\x97{\x0d\xc9\xb5fW\x1f\xdfq\xcbm\x1f\x80\xd4\xc9" + "&\xb9n\xdc\xdd\xcbw\xddt\xeb\xfb u\xb0yY" +
"\xe6d\xfd\xb3\xc4\xf9\x12q\xf6\xbcx\x8d\x88\xf2\xde\xa5" + "\xff\"q\xfe\x948\xbb\xcf_-\xa2<\xbb\\\x04\xf0" +
"\"\x80\xf7\xed\xca\xf6\x0b\x1f\x0d<\xf6\xbf\xf5\x97\xfb\x0a" + "\xbe1\xb1\xf3\xfc\xc5\xfe\xc7\xfe\xa7\xfer_!uy" +
"\xdd\xbe\xb4\x17e\x8d\xf8z\xf8R\xdfU=7\xff\xe5" + "\x0f\xca\xd3\xc4\xd7]]\xee\xbb\xaa{\xed\x9f\x7fp\xfc" +
"\xa5\xe3\x7f=\xf0\xd1\xbc\xdb\xcfu\xf4\xa3\xfcb\x07\xc9" + "/\xfb/.\xb8\xfd\xb9\xf6>\x94\xcf\xb7\x93\x1c/\xb5" +
"\xf1B\xc7\xd7\xe5K\x1d\xfe\xe5\xdfZ\xbfu\xed\xf2\x17" + "\x7fY\xfeU\xbb\x7f\xf9\xd76n_\xbf\xf2\xef?J" +
"?N[\xe2\xcd\x8e\x8f\xc9\x12\xefw\x90%&n\xf9" + "[\xe2\x9d\xf6\x8f\xc8\x12\x17\xdb\xc9\x12\xe37\xfd\xf7\x97" +
"\x9f\xaf_\xff\xed\x7f\xfe\xb8\xce=>ck\xe7\x0d(" + "?\xf7\x8d\x7f\xfa\xa8\xce=>\xa3\xd4q\x1d\xca\xbf\xd7" +
"wt\xd2\x8dWw\x16\x00?\xdc\xf8\xfd7:s\x9d" + "A7vv\x14\x01?\xdc\xfc\x9d7:r\x1d\xbfl" +
"\xbfn$\xe8\xda\xce)\x947\x13o\xcfP\xa7/\xe8" + "$ho\xc7\x14\xcac\xc4\xdb\xadt\xf8\x82\xde\xfa\xf3" +
"m\xbf<yg\xe1{\xbf\xfe\x84\xf4bu\x986s" + "\x87\xef(~\xfb\x97\x1f\x93^\xac\x0e\xd3\x0e]\xb3\x13" +
"\xedv\x94\x8f\\K7\xdf\x7f-\xa5\xc2\xa6\xb3o\x7f" + "\xe5\xe3\xd7\xf8\xc1}\x0d\xa5\xc2\x963?\xfb\xd2\xe4\xf1" +
"m\xf2\xf8+\x9f\xd6\x1b\xc1w\xc8\x9ae\x87P\x1eZ" + "W~]o\x04\xdf!7\xaf8\x8c\xb2\xb2\x82\xb8\xb7" +
"F\xdc\x1b\x96\x112\x1d\xf8\xf0\xc4\xe0\x83;\xce~\x9e" + "\xae d:\xf0\xe1\x89\x81\xfbw\x9d\xf9$\xad\xd5\x8d" +
"\xd6je\xd7s\xbe\x7f\xbbH\xab\xa9\xe3\x07\x9c\xc1\x87" + "\x9d\xcf\xfb\xfe\xed$\xad\xa6\x8e\x1fp\x06\x1e\xba\xcfk" +
"\x8fx\x8d\xd2pgW?\xca\xd5.\xbaM\xeb\xfa\x11" + "\x94\x86\xbc\xb3\x0fe\xb7\x93n\x9b\xee\xfc>\xac\xf6\x1c" +
"\xac\xf4\x1c\xd70\xb8n\xd52\xa5?\x88~\x96V\x95" + "\xd70\xb8n\xd52\xe5\xdf\x8f~\x96\xd7\x94\xd5\x9aQ" +
"\xd4\x9aQ\xeb\xdd0\xad\xd9\x8efT\xc6|z\xa1h" + "\xeb\xd94\xa3\xd9\x8efL\x8c\xfa\xf4b\xc9\xd4\xb5\xf2" +
"\xeaZi\xa6\x88\xa8\xb4Q\xa0K]\xbd\x00\x88\xd2\xd5" + "l\x09Qi\xa3@\x97:{\x00\x10\xa5\xcf\xec\x04@" +
"\xdb\x01P\x90\xa4~\x80\x82V1L\x8b{e\xcd." + "A\x92\xfa\x00\x8a\xda\x84aZ\xdc\xabhv\xd94\x0c" +
"\x99\x86\xc1\x81\x95\x9c\x83\xbbU]5J<~\xa8i" + "\x0e\xac\xec\x1c\xdc\xa3\xea\xaaQ\xe6\xf1CM\x0b\x1f\x1a" +
"\xfeC\x83\\\xd7\xcd[MK/o\xb5\xb4\x8af\x0c" + "\xe0\xban\xdebZze\xbb\xa5MhF\xbfi\x8c" +
"\x98\xc6\x84V\x01(\"\xc6\xc7\xc4\xf9\xc7\x06t\x8d\x1b" + "k\x13\x00%\xc4\xf8\x98\xb8\xf0X\xbf\xaeq\xc3\x19\xe1" +
"\xce(\xb7\xf6i%\xbe\xca\xb5yp\xce\xb5TG3" + "\xd6>\xad\xcc\xd7\xb86\x0f\xce\xb9\x96\xeah\xa6q\xed" +
"\x8d\xebF\xb8\xed\xea\x8e\x0d\xa0dX\x06 \x83\x00R" + "0\xb7]\xdd\xb1\x01\x94\x0c\xcb\x00d\x10@\xca\xf6\x00" +
"\xb6\x17@ia\xa8\xe4\x05,X>\x03\xb6'\x99\x07" + "(-\x0c\x95\x82\x80E\xcbg\xc0|\x92y\x80\x98\x87" +
"\x88\xed\x90\xbc\xd9<\xff\xcd\xc0\x16\xf4&\xb7V\xb9\x86" + "\xe4\xcd\xe6\x85o\x06\xb6\xa07\xb9\xb5\xc65,>\xa1" +
"\xc5+\x9a\xedp+ _W(\xaa\x96Z\xb5\xd3\x0f" + "\xd9\x0e\xb7\x02\xf2\xb5\xc5\x92j\xa9U;\xfd\xe0\xc3\x00" +
"\x9e\x04P\xda\x19*\xcb\x04\xf4*\x96Z\xe2En\xa1" + "J\x9e\xa1\xb2B@o\xc2R\xcb\xbc\xc4-\xd4\xcc\xca" +
"f\x96\xb7\xa8\x869\xcax\x09\x9b@\xc0\xa6\xd4\xa3\x0d" + "6\xd50G\x18/c\x13\x08\xd8\x94z\xb4\x81#6" +
"\x1c\xb1Q\xd5t^\x0e\xb4[U\xea\xf6\xffW\xdaY" + "\xab\x9a\xce+\x81vk\xca]\xfe\xffJ\x9ee\xda<" +
"\xa6\xcd\xf3\xfcG\xd4\xed\x00\xca.\x86\x8a.`\x16?" + "\xcf\x7fD\xdd\x09\xa0\xecf\xa8\xe8\x02f\xf1\x13\xaf@" +
"\xf7\xf2T\xfe$m?\x802\xc9Pq\x04\xcc\x0a\x9f" + "\xe5O\xd2\xf6\x03(\x93\x0c\x15G\xc0\xac\xf0;\xaf\xe0" +
"yy\xdfk{\x97\x03(:CeZ\xc0,\xfb\xad" + "{mz%\x80\xa23Tf\x04\xcc\xb2\xdfz\x05*" +
"\x97\xa7\"#\xb9S\x00\x8a\xc3P\xb9K@\xcfvk" + "2\x92;\x05\xa08\x0c\x95\xbb\x04\xf4l\xb7F6\xb5" +
"dS\x1b\x98ia{\x12\xca\xa1ux\xb9B\x966" + "\x81\x99\x16\xe6\x93P\x0e\xad\xc3+\x13di\x03\x8a\xbc" +
"\xa0\xc0Kdhl\x8f\xd09`\x10\xcb\xe6$\xb6'" + "L\x86\xc6|\x84\xce\x01\x83X1'1\x9f\x14\x9f\xf0" +
"\xc5'<f\xf1}\xdc\xb2y\x11r\x969=\x83\xed" + "\x98\xc5\xf7q\xcb\xe6%\xc8Y\xe6\xcc,\xe6\x13\x94\xae" +
"\x09J\xd7Y=\xfbE\xad\x1e9:>\xb5\xf0y?" + "\xb3z\xf6J\xad\x1e9:>\xb5\xf8y?4\xcb\xce" +
"4K\xceu\xc5\xeey\xce\";\xb61T\x96\x0a\xe8" + "\xb5\xa5\xae\x05\xce\";\xb61T\x96\x0b\xe8\xd5\xe8+" +
"\xd5\xe8+w80\xcb\xc6\xf6\xa4\xa8\xd7I\xdb \x9c" + "w80\xcb\xc6|R\xd4\xeb\xa4m\x10\xce\xfd\xf4o" +
"\x07\xe8\xdf\x81\xe0\x95bx\x8be\xfb\xe1\xac,\x8d\x1f" + "\x7f\xf0J)\xbc\xc5\xb2\xfdpV\x96\xc7\x8f\x9d\xa0\xc7" +
";A\x8f=\xccP\xf9\x81\x80\x12b\xe0\xb3\xc7,\x00" + "\x1eb\xa8|W@\x091\xf0\xd9c\x16\x80\xf2(C" +
"\xe5Q\x86\xcaY\x01Q\x08<\xf6\xe4i\x00\xe5,C" + "\xe5\x8c\x80(\x04\x1e{\xf2\x14\x80r\x86\xa1\xf2\xb7\x02" +
"\xe5\xef\x05\x94\x98\x108\xec\xd9\x1b\x00\x94\xa7\x19*\xbf" + "JL\x08\x1c\xf6\xecu\x00\xca\xd3\x0c\x95\x9f\x08(e" +
"\x10P\xca\xb0<50\xd2\x05\x0a\xb6_0T\xde\x12" + "X\x81\x1a\x18\xe9<\x05\xdbO\x18*o\x09(5e" +
"Pj\xca\xe4\xb1\x09@zs5\x80\xf2\x1aC\xe5\x1d" + "\x0a\xd8\x04 \xbd\xb9\x0e@y\x8d\xa1\xf2\xb6\x80\x9e\x19" +
"\x01=3\xc8/R\xca\xc1,\x08\x98\x05\xf4J\xba\xe9" + "\xe4\x17)\xe5`\x16\x04\xcc\x02ze\xddt+\xe3\xba" +
"\x96't\x15\xba-^\x1eZ\x1f\xd3\x0d\xb7Z\xb4\xf8" + "\x0a]\x16\xaf\x0cn\x8c\xe9\x86[-Y|\x9f\x86\xa6" +
">\x0dM\xd7\xees\x1c^\x15k\x8e\x8d\xcd `3" + "k\xf7:\x0e\xaf\x8a5\xc7\xc6f\x10\xb0\x190\xe7\xa8" +
"`\xceQ+6.\x01,2\xc4\xf6\xa4\xd0\x01\x121" + "\x136.\x03,1\xc4|R\xe8\x00\x89\x18\xdf\x89\x16" +
"\xbe\x13-^\xde\xc6-[c\xa6\x81m `\x1b`" + "\xaf\xec\xe0\x96\xad1\xd3\xc06\x10\xb0\x0d\xb0\xcb.\x9b" +
"\xb7]2k\x1c\xdb\x93\xdayy\x9b\x8e\x84\xd1C\xb1" + "5\x8e\xf9\xa4v^:\xef\x86\xc3\xe8\xa1\xd8\x09\x13\xc1" +
"\x13&\x82iibE3\x946\x96Y\xe6y\xa1\x01" + "L\xb0\x02'\x946\x96Y\xe1y\xa1\x197\x91u6" +
"7\x90]\xd61T6\x09\xd8\x85\x9f\x13\x99l84" + "0T\xb6\x08\xd8\x89\x9f\x10\x99,98\x0c\xa0\x0c0" +
"\x02\xa0\x0c2T\xc6\x04\xec\x12>#2YQ!\x1f" + "TF\x05\xec\x14~Gd\xb2\xa5B\x9e(1Tv" +
"\x14\x19*;\x04\xccM:N\x0d\xdb\x93\xea\x18\x0au" + "\x09\x98\x9bt\x9c\x1a\xe6\x93\x1a\x19\x8av\x07\xdfc\x9b" +
"'\xdfm\x9b\xa5=\x1c\x90\xa0\"\x86\xea\xf0\xebd\x08" + "\xe5\xbd\x1c\x90\x00#\x06\xec\xf0\xebd\x08`\xc0\xf4\x0a" +
"]\xc0\xf42\xb6'\x9dl\x9dF\xacA\x94\xf8\x01R" + "\xe6\x93~\xb6N/\xd6 V\xfc0):\x9b,\xcb" +
"p6X\x96i\xf9\xa8\x1a\x87\xc6\x86\xd5\x89\x12Qd" + "\xb4|l\x8d\x03d\xd3\xbaD\x89(>\x06w&\x1a" +
"\x0cmO4\x90\x84u\x81Z\xca\xeeD\xfe\xee\x92\xea" + "H\xc2\x86@-eO\"\x7fWYum\x1eY\xda" +
"\xda<\xb2\xb1gq\xc7\x9a\xe9\x9bp\x80q+\xc6\x18" + "\xb3\xb8c\xcd\xf6\x8e;\xc0\xb8\x15#\x8d=i\xbaz" +
"{\xd2t\xf5\xf2\x08\x07\xd1\xb1f\x10A@\\\x18y" + "e\x98\x83\xe8X\xb3\x88 .\x8e?\x1b\xcd\x81\x94" +
"\xd6\x9b\x83)\x93\x07!\x9c\x92\x93dZ\xcfP)&" + "\xe1\x83@N\xc9I2md\xa8\x94\x129\xb7\x12m" +
"rn&\xda&\x86\xcam$gh\xfeq2\xff\x18" + "\x0bC\xe5V\x9234\xff\x18\x99\x7f\x94\xa1R\x13\xd0" +
"C\xa5&\xa0\xa7S\xee\x1a\x83&0\xdb\x89\xc5\x0d\x88" + "\xd3)\x83\x8d\x01\x13\x98\xed\xc4\xe2\x06\xc4\x92\xe9\x87\xa7" +
"E\xd3\x0fL\x11\x04\x14\x01=\xb7f;\x16W\xab\x80" + "\x08\x02\x8a\x80\x9e[\xb3\x1d\x8b\xabU\xc08\xde\x88\x7f" +
"q\xa4\x11\xff\x92/\x00\xd1uPQTs~\xce7" + "\xd9\x15\x00u\x1d`\x94\xd4\x9c\x9f\xf9\x8du\x88\x93q" +
"\xd6!N\xc3\xcd\xc3i%\xc2<\x1c\xefO\x8c\xdd8" + "\xebPZ\x890\x1b\xc7\xfa\x12c7N\xa7I\xd3v" +
"\x91&M\xdb1\xd4*\x07\x80H\xb1\x83f\x8d0\x92" + "\x0c\xb5\xca\x01 R\xec\xa0Y#\xa4$\x1c\x89\x9b\xcd" +
"\x10$n3\xebb\xe3\x8bW\xb6\xa0\xca\xcc\xa9k\xa7" + "\xba\xd8\xb8\xf2\xfa\x16\xd4\x9ay\xd5\xedT\xaa\xd8\x94\xc3" +
"Se\xa6\x14\x9eF\xff\xf8\x80i\x88\x13Z\x05\xdb\x93" + "\xd3\xe8\x1f\xef7\x0dq\\\x9b\xc0|\xd2q\xd5\x09\xd0" +
"^\xabN\x80\x06~\xefs\x9dIn8Z\xc9\x7fp" + "\xc0\xef\xbd\xae3\xc9\x0dG+\xfb\x0f.\xf0\xfb\xca$" +
"\x9e\xdf\x97'\xf1\x19\xdblhu\xca\x90\x91\xcd6\xef" + ">c\x9b\x0d\xaeK\x192\xb2\xd9\xd6=\x89!\xc5\xbd" +
"N\x0c)\xee\xe131\x04\xf0\xaa\xaa\xe9\xb1\xf7Ck" + "|6\x06\x02^U5=\xf6~h\xcd^\x10\xbf\x92" +
"\xf6\x81\xf8\x8d\x84g\xa1\xe4\x19%\x04\xf1\xa5\xf2m\x80" + "\xf0,\x96<#\x84#\xbeT\xbe\x0d0\xd5\x9bK\xd9" +
"\xa9\xae\\\xca\xae\x06\xa1{\x9f\xaa\xbb|\xc1\xe6&\xac" + "u t\xedSu\x97/\xda\xe2\x84\xb5,\xa8d\xc5" +
"bA\x0d+\x04\x06\xa6\x0b\xf3\xb1\x9a\xdf\x9c\x05P\xee" + "\xc0\xc0ta!V\xf3\xce9\x00\xe5.\x86\xca\xbd)" +
"b\xa8<\x90R\xf3\xfe\x87\x00\x94\x07\x18*\x0f\xa7\xd4" + "5\x8f>\x08\xa0\xdc\xcbPy(\xa5\xe6q\x0a\x8dc" +
"<N\xa1q\x94\xa1r\x8a \x9a\x05\xe0r\x82|r" + "\x0c\x95\x93\x04\xd4,\x00\x97\x13\xe4\x93\x93\x0c\x95'\x04" +
"\x8a\xa1\xf2\x84\x80\x98\x09\x10\xfa\x0c!\xf4\x13\x0c\x95\xf3" + "\xc4L\x80\xd3\xa7\x09\xa7\x9f`\xa8\x9c\x13|\x94\x1d\xe8" +
"\x82\x8f\xaf\x83}\x03\xa6\x81\xa1\x106@\x84\xae\xde$" + "\xed7\x0d\x0c\x85\xb0\x01\"\x8c\xf5&\xb9j9{\xb8" +
"W-g7W\xd1\x192\x1cn\xedSQ\x8f\xb2\xf8" + "\x8a\xce\xa0\xe1pk\x9f\x8az\x94\xc5\x07\x1d\xad\xcaM" +
"\xa0\xa3U\xb9\xe9:qVW\xd5i\xbfC\xc0\xf2`" + "\xd7\x89\xb3\xba\xaa\xce\xf8}\x02V\x06\x82S\xa2\xea\xd8" +
"pJT\x1d\x1b[A\xc0VJ\"\x9b[\x03\x16/" + "\xd8\x0a\x02\xb6R\x12\xd9\xdc\xea\xb7x\x05\xc9\x9f\xaa^" +
"#\xf9S\xd5\x8b*s&\xe7\x998s9\xc4\xcd5" + "R\x993\xb9\xc0\xc4\x99K\xe1n\xae\x81y\xa8\xcb8" +
"0\x0f\xf5\x17\x07\x18*\xf7Q\xf6cj\x90\x95\xee\xe9" + "\xc0P\xb9\x87\xb2\x1fS\xe3\xac\xf4\xf5)\x10\xfc\xe4'" +
"\x05\xc1O~\xd2\xb9\xda\x9f\xf4!~\xfd\xa2\xaa\xb4\xf7" + "\x9d\xa7\xfb\x92\xbe\xc3\xafbT\x9b\\2\xe3\x0cC\xe5" +
"\xa1\xa4\xe1\xf0\xebW3\xddx21x(\xda\xa0\x09" + "HX\xc5\x9a\x01\xa4Cd\x9d#\x0c\x95cB$\xda" +
"\x85 \xa9\"\x99\x0bA\xb0\x1c$\x80\xd3x\xa2gX" + "\x80\x09\xc5 \xa9\xea\x83\xc5\x04_\xa6\x83\x04t\x1aO" +
"\xd654\x8d1\xdf@\x98X\xa8dVk\x16\xb7m" + "\xf4\x0d\x8b\xbc\x86\xa61\xea\x1b\x0a\x13K\x95\xcdj\xcd" +
"\xd4LCqU]c\xceL|pA\x1b\x10z\x04" + "\xe2\xb6\x8d\x9ai(\xae\xaak\xcc\x99\x8d\x0f.j\x0b" +
"Y\xb7\xb5\xd6\xed;\x89\x8cpSd\x04\xb9\x0f\x87\x01" + "B\x91 \xfb\xb6\xd7\xba|g\x911n\x88\x8c!\xf7" +
"F\xd7!\xc3\xd1M\x98\x84\x89<\x84\xfd\x00\xa3\xeb\x89" + "\xe2\x10\xc0\xc8\x06d8\xb2\x05\x93p\x91\x07\xb1\x0f`" +
"^\xc4$R\xe4\xcd\xd8\x090:H\xf41\x14\x10\x83" + "d#\xd1K\x98D\x8c\xbc\x15;\x00F\x06\x88>\x8a" +
"X\x91\x15|\x0a`t\x8c\xc8\xbb0\xa9\xe8\xf2N\xff" + "\x02b\x103\xb2\x82O\x01\x8c\x8c\x12y7&\xf5]" +
"\xfa\x1dD\x9f\xc4\xa4\xa8\xcb\x1co\x00\x18\xddE\xf4\x03" + "\xbe\xdd\xbf~\x17\xd1'1)\xf12\xc7\xeb\x00Fv" +
"Do\x16|\x0b\xca38\x050:M\xf4\xc3D\x17" + "\x13\xfd\x00\xd1\x9b\x05\xdf\x92\xf2,N\x01\x8c\xcc\x10\xfd" +
"\x9b\xf24\x1f\xc8w\xa3\x050z\x17\xd1\x1f z\xcb" + "\x08\xd1\xc5\xa6\x02M\x0b\xf2!\xb4\x00F\xee\"\xfa\xbd" +
"\xd2<\xb6\xd0\xfc\xe1\xd3\xef#\xfaw\x89\xde\xda\x91\xc7" + "DoY^\xc0\x16\x00\xf9\xa8O\xbf\x87\xe8\xdf\"z" +
"V\x00\xf9\x18\x1e\x02\x18=J\xf4SD_\x84y\\" + "k{\x01[iJ\xc1\xc3\x00#\xc7\x88~\x92\xe8K" +
"\x04 \x9f\xc0\x93\x00\xa3\xa7\x88\xfe\x04\xd1\x177\xe7q" + "\xb0\x80K\x00\xe4\x13\xf80\xc0\xc8I\xa2?A\xf4\xa5" +
"1\x80|\xc6\x97\xe7Q\xa2\x9f\xc5\x18\x82\x86\xcai$" + "\xcd\x05\\\x0a \x9f\xf6\xe5y\x94\xe8g0\x86\xa2\xc1" +
"\xa4p\xd2\x92.\x80\x99v\x1c\x86<\x9c40\x80\xe9" + "J\x1a\x11)\xac\xb4\xa4'`\xa6\x1d\xbb\x96\x87s\x07" +
"\xa2\x99\xa3Q\x03s\xc9\x0e\x09\x10s\x80^\xcd4\xf5" + "\x06p]2s4x`.\xd9(\x01b\x0e\xd0\xab" +
"-s\x11\xf6r\x8dH\x18\x16\x903\x8d\xa1r\x9c_" + "\x99\xa6\xbem>\xd2^\xaa-\x09\xc3\x02r\xa61X" +
"A\x10m2\xa1\xbb\xa4\xeaC\xb5X\x12\xcd\xees\x1d" + "\x89\xf3,\x08\xa6-&t\x95U}\xb0\x16K\xa2\xd9" +
"\xd3\xadAwYux9\xae\x91\x96kl\xb4\xcc\xea" + "\xbd\xaec\xba5\xe8\xaa\xa8\x0e\xaf\xc4\xb5\xd2r\x8d\xcd" +
"\x18r\xab\xaa\x19\xaa\x0e\xf1\x97\x85b+\xe7\xbaZ\xf9" + "\x96Y\x1dEnU5C\xd5!\xfe\xb2Xl\xe5\\" +
"\x8a\xf1lU\x80ZJK\xd2\xd9\xaf\xa0\xea\xf4\x15\x86" + "W\xab\\6\xae\xad\x09\xd0KiI\xfa\xfcUT\xa5" +
"\xca\x1f\xa6;\xfb\x9b\x09jod\xa8\xdcB\xdd\xfa\x8c" + "\xbe\xc0P\xf9\x83t\x9f\xbf\x96 \xf7z\x86\xcaM\xd4" +
"\xed\xf0\xea\x16\x15X\x92#\xdd\x15\xcbtk\xf3\x1e\x16" + "\xbb\xcf\xda\x0e\xafnS\x81%\xb9\xd25a\x99nm" +
"\xea\x1f\xee\xae\xf5\x8e\xa9~Z\xb7\xc4i\xbd\x82:\xa8" + "\xc1\xc3B\xfd\xc3]\xb5\x9eQ\xd5O\xef\x968\xbdW" +
"\xeb\x18*7\xa5Po\xe5\xeaD\x8e\\:\x1b\x03\x91" + "Q'u-C\xe5\x86\x14\xfa\xad^\x97\xc8\x91Kg" +
"\xe7\xbd\xd4\xa0\x83\x1b\xaf\xabbA\xd7\x1e\x94\x96\xd4\xeb" + "e \xf2\x82\x97\x1a\xf4\xc8cu\xd5,\xe8\xe1\x83\x12" +
"\xfd\xc9\xeb\xf1\xe3V\xa8\xee\xa0\x80\x07m\xb7T\"k" + "\x93z\xbd/y=~\xdc\x0a\xd5\x1d\x10\xf0\xa0\xed\x96" +
"G\xe6\x9f\x08g#\xe8\xa6\xbbS\x81\x10\xaf-\xc2@" + "\xcbd\xed\xc8\xfc\xe3\xe1\xa4\x04]tw*\x10\xe2%" +
"\xb8\xd2\x8e\xa1\xc2\x9d\xe0\xd7\x901aR\xa9\x15\xd5\xaa" + "F\x18\x08\x97\xdb9Lp'\xf85h\x8c\x9bTr" +
"\xfd\xff<=\xc2\xed\x1c\x8d&\x97\x9d@\xe3E\xc4\xe5" + "E\xb5j\xff\x1fO\x0fs;G\x83\xca%\xe7\xd1x" +
"K\xf3\xe0\xd8X1\x19\x93Y\x80\xcai@\x1aI\x03" + "-q\xe9\x12=0:ZJ\x86f\x16\xa0s\x1a\x90" +
"R\x82GSi\xdc\x89:HY\xf1\x01\xa0H\xf4\x1d" + "\x86\xd3\x80\x94\xe0\xd1T\x1aw\xa2NRV|\x00(" +
"\x98\xcc\x17\xf2\xedxz\x0e\xf0d\xfa\x02@\xe2\xfe\xf5" + "\x11}\x17&\xd3\x86\xfcU<5\x0fx2\xbd\x01 " +
"e\xa2\xd7|@\xc2\x00\x90\xaa\xfe\xfd:\xd1\xa7\xd3\x80" + "q\xff\xfa\x0a\xd1k> a\x00HU\xff~\x9d\xe8" +
"\xe4\xe2\xec\\@b\x11 \x11\x90\x1c&\xfaQ\x1f\x90" + "3i@rqn> \xb1\x08\x90\x08H\x8e\x10\xfd" +
"2\x01 \x1d\xc1g\xe6\x00OkS\x00H'\xf0\xb9" + "\x98\x0fH\x99\x00\x90\xee\xc3g\xe6\x01OkS\x00H" +
"9\xc0\xb3\xa89\x00\xa43>\xff\x13D?\xef\x03R" + "'\xf0\xf9y\xc0\xb3\xa49\x00\xa4\xd3>\xff\x13D?" +
"\x7f\x00H\xe7|\x00{\x9a\xe8\xcf\x13 \xb9\x96>\xea" + "\xe7\x03R_\x00Hg}\x00{\x9a\xe8/\x10 \xb9" +
"X\x9a\x01XI\x82\xb5T\xfb\x06\xe7\xb5>\xc8\xe9\xda" + "\x96>\xe2X\x9a\x018\x91\x04k\xb9\xf6\x15\xcek\xbd" +
">\x1e\x17\x8b\xb2\xa6\xea\xeb]U\x87\xeeQG-\xed" + "\x90\xd3\xb5}<.\x16\x15M\xd57\xba\xaa\x0e]#" +
"I\xdad\xdd\x1eT\x8d\xb2\x8d\x93\xea\x1eN%FL" + "\x8eZ\xde\x9b\xb4\xcb\xba=\xa0\x1a\x15\x1b'\xd5\xbd\x9c" +
"\x17aG\xb7\xb7qK\x9b\x00L\x1a\xeb\xb8\xad\xc9\x15" + "J\x8c\x98.\xc6\x8en\xef\xe0\x966\x0e\x984\xd8q" +
"M\xb3\xbe\xdb\xf1\xfb3n\x05h\x16\x7f\xab\xaa\xd3C" + "{\x93+\x99f}\xd7\xe3\xf7i\xdc\x0a\xd0,\xfeV" +
"e\x9d\x0f`\xd4\x9a0#)q\x1a}1\x0d\x03\x83" + "Ug\x06+:\xef\xc7\xa8EaFR\xe24\xfab" +
"~aL\xeb\x9e\xdb\x08\xd4\xc2V=j(\xc6\x0au" + "\x1a\x06\x06}\xc3\xa8\xd65\xbf!\xa8\x85-{\xd4X" +
"\x9d\x02\x9f\xae\xf1\x923`\xa2\xe1h\x86\xcb\xe7]P" + "\x8c\x16\xeb:\x06>S\xe3e\xa7\xdfD\xc3\xd1\x0c\x97" +
"\x9at\x8d=\xbc\xbc\x01\x8d\x92Y\xd6\x8c\x0a\xcc\x9b\x11" + "/\xb8\xa0<\xe9\x1a{ye\x13\x1ae\xb3\xa2\x19\x13" +
"\xd8\xef\xdaN\xa4:\xa8\x96\xb0%\x8b\xd7\xed\xd2\x0a\xea" + "\xb0`V`\x9f\xb6\xabHuR-ak\x16/\xdf" +
"\x070\xec\x07\xa4\xded\xca.\x94\xfcS\x05\x8b\xabv" + "\xa5U= \xf8XB}\x81\xd4\x93\xcc\xdc\xc5\xb2\x7f" +
"R\x1a\x16z-\\F\x05IF\xaf\xb5\xb3&\x80x" + "\xaahq\xd5NJ\xc3b\xaf\x85\xab\xa9 \xc9\xe8\xb5" +
"y\x8d\xd1\xceO\xda\xbb\x1f\x04I\x131Y\x95b\xb4" + "<k\x02\x88W\xd9\x18m\x00\xa5\xe9\xfd H\x9a\x88" +
"\x19\x95vZ H\xe3\"\x0a\xf1\xdf\x0c0\xda\xf7K" + "\xc9\xe2\x14\xa3=\xa9t\xbb\x05\x824&\xa2\x10\xff\x05" +
"C\xb3 H\x1bDd\xf1\xa2\x1f\xa3\x8d\x9b\xb4\xb6\x1f" + "\x01\xa3\xed\xbf48\x07\x82\xb4ID\x16\xaf\xfd1\xda" +
"\x04i\xa5\xe8ES\x05\x14\x02q\xd6\xa1\x17%>t" + "\xbfI\xeb\xfb@\x90V\x8b^4]@1\x10g\x03" +
"\xfb\xa9\xbf\x0e\xbdhO\x81\xd1\xf4\x01\xb0\x0e\x0f\x86\xf5" + "zQ\xe2C\x97\x9f\xfa\x1b\xd0\x8b\xb6\x16\x18M!\x00" +
"h\x1d\xa6\x97[\xecw\x8d\x00\x8d\xfbR\xc2\xc8i\x86" + "\x1b\xf0`X\x8f6`z\xd5\xc5>m\x14h\xdc\x9f" +
"\xca\xe1\x04#\xef\xa6^\xf50C\xe5hj\xec:\xf2" + "\xf6%=T\x84\x91\x87\xe6\x92\x16*\x1e\xbf\xee{*" +
"T\xba-\x0d7\x07'\x0e\x85{\x87\xf3\xa9\xcd\xc19" + "\xdd\x9e\x86{\x84\x13\x87\xc3-\xc4\xb9\xd4\x1e\xe1,\xf5" +
"\xeaU\xcf3T^\x13\x92B\x1d\x85]\xb4\x0fB\xd3" + "\xac\xe7\x18*\xaf\x09I\xa1\x8e\xc2.\xda\x0e\xa1iE" +
"\x8a\xe6\xc0\x05\xd6Bap\x86-c\xfdr\xc8+\x9b" + "\xf3\xe0\"K\xa208\xc3\xd6\xb1~U\xe4U\xccI" +
"\x93~K\x89\xc1U6$\x88\x9d\xde\x18-Im\x8c" + "\xbf\xb5\xc4\xe0*\x1b\x12\xc4N\xef\x8f\x96\xa5\xf6G\x18" +
"0\x9a@\xc59\x00\x9f\xde\x1f-Y\x183\xe7\xccS" + "M\xa2\xe2<\x80Oo\x93\x96-\x8e\x99\xf3\xe6\xaap" +
"\xe1\xd8@Q\x13\xfdE\x03\xa3\xbf-I\x12y?+" + "|\xa0\xa8\x89\xfe\xbe\x81\xd1_\x9a$\x89\xbc\x9f\x15\xbd" +
"z\xd1\xcc\x85Q\xb9\"\xe7\xa5]\xf6\x05\x07\xcf\x11\xde" + "h\xf6\xc2\xa8\\\x91\xf3\xd2.\xbb\xc2\x01t\x98w\xd9" +
"m_I%\x88\xb6\xcc\x97\xdf\x1f\x04\xef\xe4(\xd8\xe2" + "\x97S\x09\xa2\x9d\xf3\xa5\xf7\x08\xc1;9\x0a\xb6x\x1e" +
"9(\xb8w*\xb5\xc5\xd2\xcdp\x84\xcbmIU\xed" + "\x0a\xee\x9dJ\xed\xb4t3\x1c\xe5r\xdb\xd2\xbd\xf4\"" +
"\x85l\x15\x08\x1cu\xbe9:\\\x17~\xcb\x93\xf0\x8b" + "\xb6\x0a\x04\x8e:\xdf\x1c\x1d\xae\x0b\xbf\x95\xa9\x16>\x8e" +
"\x1b\x84\xbb\x97'\xc3@<\x16\xdd3\x1c\x06\xe5\xa3q" + "\xbf\x95\xc9P\x10\x8fG_\x1f\x0a\x83\xf2\xd1\xb8\xd3\x95" +
"\xa7+=2\x9bl\xb8\xe2\xf0{r8\x19\x8bDn" + "\x1e\x99K\xf6]q\xf8=9\x94\x8cG\"\xb7\xacH" +
"Y\x91\x9c\xa2k%\xb0\xa9\x9b\x95M\x9a\xc1m\xea\xfd" + "N\xd1\xb5\x12\xd8\xd4\xcd\x89-\x9a\xc1m\xea\xfd\xea\xb6" +
"\xea\xb6\x015nUU\x83\x1b\xe8\x10\x18\xb9\x16!\xea" + "\x025nUU\x83\x1b\xe8\x10\x18\xb9\x16!\xea|\xe4" +
"\\\xe4\x1aZ\x9fj\x19\x17R\x7f4\x0c\xf6 \xd6\xc3" + "\x1a\xdc\x98j\x19\x17S\x7f$\x0c\xf6 \xd6\xc3\xf2\x9a" +
"\xf2\x9a\x1a}O\xa7\xd60\x91\xf2\xcas\xe1zcW" + "\x1a\x81O\xa5\xd61\x91\xf2\xca\xf3\xe1\x9acwJ\xf9" +
"J\xf9\x9d4\xfa\xee`\xa8L\x0a\xe8\xa9\xaec\x8e\xd7" + "\xdbi\x04\xde\xc5P\x99\x14\xd0S]\xc7\x1c\xabUT" +
"\xca*:|\xa3\xc5\xf7\xba\\4J3\xc9\x00G\xa3" + "t\xf8f\x8bO\xbb\\4\xca\xb3\xc9 G\xa3L\xd9" +
"L\xc9\x1e\xc7\x1a5\x9d\x1b-^\xd8\xeb\xf24C\xb4" + "\x1e\xc3\x1a5\x9d\x9b-^\x9cvy\x9a!Z#\x83" +
"8\x06Q3\xcb\xf36\xc6\x0d\x9a\xad[\xf9\xeeQ\xb3" + "\xa8\x99\x95\x05\xfb\xe3\x06\xcd\xd6-|\xcf\x88Y\xde\xcb" +
"\xb4\x87;s\x16\xea\x01\\F\xaa\xa8#\xc9\xd68\xd2" + "\x9dy\xeb\xf5\x00.#U\xd4\xe1d\x87\x1ci\xa2\x0d" +
"D\x1bI\xcdj\x11\x8c\xec\xa5\x80\xaa1T\x0e\xa4`" + "'\x1b\xe4\x18F\xa6)\xa0j\x0c\x95\x03)\x18\x99\x9d" +
"df6qx\xe3\xea\xfa\xfb)\x88\x0b(\xd9p\xab" + "K\x1c\xde\xb8\xba\xfe\xff\x14\xc4E\x94l\xb8\xe3\x1d." +
";R\xe0W\x94h\xc9_I.\xdfr\x85{\x82\xb0" + "\xf2\xcbJ\xb4\xe4o&\x97n\xb9\xc2}A\xd8\xb1^" +
"c\xbd\x92]\xc8\x9ce]\x18\x10\xcaT\xb2?\xf2\x83" + "\xceNd\xde\xd2.\x0c\x08e*\xd9#\xf9A\x9eO" +
"\xbc=\xf9sn(\x83\x1d\xb6\x8e\xc0&\xcc\x06]a" + "\xfe\xb8\x1b\xca`\x87\xad#\xb0q\xb3AW\x18LU" +
"0U\x0d\x98\x10Bk\xfdF\xe7\xff\x02\x00\x00\xff\xff" + "\xd1\x04\xbcp\xb3\xf3\xbf\x01\x00\x00\xff\xff\x82\xd9\x7f\x1e"
"\xd4\xcdz3"
func init() { func init() {
schemas.Register(schema_db8274f9144abc7e, schemas.Register(schema_db8274f9144abc7e,