lib/config, lib/connections: Configurable protocol priority (ref #8626) (#8868)

This makes the various protocol priorities configurable among the other
options. With this, it's possible to prefer QUIC over TCP for WAN
connections, for example. Both sides need to be similarly configured for
this to work properly.

The default priority order remains the same as previously (TCP, QUIC,
Relay, with LAN better than WAN).

To make this happen I made each dialer & listener more priority aware,
and moved the check for whether a connection is LAN or not into the
dialer / listener -- this is the new "lanChecker" type that's passed
around.
This commit is contained in:
Jakob Borg 2023-04-16 12:54:28 +00:00 committed by GitHub
parent c867a5f5b3
commit 9b660c1959
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 622 additions and 361 deletions

View File

@ -1256,8 +1256,9 @@ angular.module('syncthing.core')
case "relaywan": case "relaywan":
return $translate.instant('Connections via relays might be rate limited by the relay'); return $translate.instant('Connections via relays might be rate limited by the relay');
case "quiclan": case "quiclan":
return $translate.instant('Using a QUIC connection over LAN');
case "quicwan": case "quicwan":
return $translate.instant('QUIC connections are in most cases considered suboptimal'); return $translate.instant('Using a QUIC connection over WAN');
case "tcpwan": case "tcpwan":
return $translate.instant('Using a direct TCP connection over WAN'); return $translate.instant('Using a direct TCP connection over WAN');
case "tcplan": case "tcplan":

View File

@ -47,44 +47,49 @@ func TestDefaultValues(t *testing.T) {
Version: CurrentVersion, Version: CurrentVersion,
Folders: []FolderConfiguration{}, Folders: []FolderConfiguration{},
Options: OptionsConfiguration{ Options: OptionsConfiguration{
RawListenAddresses: []string{"default"}, RawListenAddresses: []string{"default"},
RawGlobalAnnServers: []string{"default"}, RawGlobalAnnServers: []string{"default"},
GlobalAnnEnabled: true, GlobalAnnEnabled: true,
LocalAnnEnabled: true, LocalAnnEnabled: true,
LocalAnnPort: 21027, LocalAnnPort: 21027,
LocalAnnMCAddr: "[ff12::8384]:21027", LocalAnnMCAddr: "[ff12::8384]:21027",
MaxSendKbps: 0, MaxSendKbps: 0,
MaxRecvKbps: 0, MaxRecvKbps: 0,
ReconnectIntervalS: 60, ReconnectIntervalS: 60,
RelaysEnabled: true, RelaysEnabled: true,
RelayReconnectIntervalM: 10, RelayReconnectIntervalM: 10,
StartBrowser: true, StartBrowser: true,
NATEnabled: true, NATEnabled: true,
NATLeaseM: 60, NATLeaseM: 60,
NATRenewalM: 30, NATRenewalM: 30,
NATTimeoutS: 10, NATTimeoutS: 10,
AutoUpgradeIntervalH: 12, AutoUpgradeIntervalH: 12,
KeepTemporariesH: 24, KeepTemporariesH: 24,
CacheIgnoredFiles: false, CacheIgnoredFiles: false,
ProgressUpdateIntervalS: 5, ProgressUpdateIntervalS: 5,
LimitBandwidthInLan: false, LimitBandwidthInLan: false,
MinHomeDiskFree: Size{1, "%"}, MinHomeDiskFree: Size{1, "%"},
URURL: "https://data.syncthing.net/newdata", URURL: "https://data.syncthing.net/newdata",
URInitialDelayS: 1800, URInitialDelayS: 1800,
URPostInsecurely: false, URPostInsecurely: false,
ReleasesURL: "https://upgrades.syncthing.net/meta.json", ReleasesURL: "https://upgrades.syncthing.net/meta.json",
AlwaysLocalNets: []string{}, AlwaysLocalNets: []string{},
OverwriteRemoteDevNames: false, OverwriteRemoteDevNames: false,
TempIndexMinBlocks: 10, TempIndexMinBlocks: 10,
UnackedNotificationIDs: []string{"authenticationUserAndPassword"}, UnackedNotificationIDs: []string{"authenticationUserAndPassword"},
SetLowPriority: true, SetLowPriority: true,
CRURL: "https://crash.syncthing.net/newcrash", CRURL: "https://crash.syncthing.net/newcrash",
CREnabled: true, CREnabled: true,
StunKeepaliveStartS: 180, StunKeepaliveStartS: 180,
StunKeepaliveMinS: 20, StunKeepaliveMinS: 20,
RawStunServers: []string{"default"}, RawStunServers: []string{"default"},
AnnounceLANAddresses: true, AnnounceLANAddresses: true,
FeatureFlags: []string{}, FeatureFlags: []string{},
ConnectionPriorityTCPLAN: 10,
ConnectionPriorityQUICLAN: 20,
ConnectionPriorityTCPWAN: 30,
ConnectionPriorityQUICWAN: 40,
ConnectionPriorityRelay: 50,
}, },
Defaults: Defaults{ Defaults: Defaults{
Folder: FolderConfiguration{ Folder: FolderConfiguration{
@ -239,45 +244,50 @@ func TestNoListenAddresses(t *testing.T) {
func TestOverriddenValues(t *testing.T) { func TestOverriddenValues(t *testing.T) {
expected := OptionsConfiguration{ expected := OptionsConfiguration{
RawListenAddresses: []string{"tcp://:23000"}, RawListenAddresses: []string{"tcp://:23000"},
RawGlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"}, RawGlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"},
GlobalAnnEnabled: false, GlobalAnnEnabled: false,
LocalAnnEnabled: false, LocalAnnEnabled: false,
LocalAnnPort: 42123, LocalAnnPort: 42123,
LocalAnnMCAddr: "quux:3232", LocalAnnMCAddr: "quux:3232",
MaxSendKbps: 1234, MaxSendKbps: 1234,
MaxRecvKbps: 2341, MaxRecvKbps: 2341,
ReconnectIntervalS: 6000, ReconnectIntervalS: 6000,
RelaysEnabled: false, RelaysEnabled: false,
RelayReconnectIntervalM: 20, RelayReconnectIntervalM: 20,
StartBrowser: false, StartBrowser: false,
NATEnabled: false, NATEnabled: false,
NATLeaseM: 90, NATLeaseM: 90,
NATRenewalM: 15, NATRenewalM: 15,
NATTimeoutS: 15, NATTimeoutS: 15,
AutoUpgradeIntervalH: 24, AutoUpgradeIntervalH: 24,
KeepTemporariesH: 48, KeepTemporariesH: 48,
CacheIgnoredFiles: true, CacheIgnoredFiles: true,
ProgressUpdateIntervalS: 10, ProgressUpdateIntervalS: 10,
LimitBandwidthInLan: true, LimitBandwidthInLan: true,
MinHomeDiskFree: Size{5.2, "%"}, MinHomeDiskFree: Size{5.2, "%"},
URSeen: 8, URSeen: 8,
URAccepted: 4, URAccepted: 4,
URURL: "https://localhost/newdata", URURL: "https://localhost/newdata",
URInitialDelayS: 800, URInitialDelayS: 800,
URPostInsecurely: true, URPostInsecurely: true,
ReleasesURL: "https://localhost/releases", ReleasesURL: "https://localhost/releases",
AlwaysLocalNets: []string{}, AlwaysLocalNets: []string{},
OverwriteRemoteDevNames: true, OverwriteRemoteDevNames: true,
TempIndexMinBlocks: 100, TempIndexMinBlocks: 100,
UnackedNotificationIDs: []string{"asdfasdf"}, UnackedNotificationIDs: []string{"asdfasdf"},
SetLowPriority: false, SetLowPriority: false,
CRURL: "https://localhost/newcrash", CRURL: "https://localhost/newcrash",
CREnabled: false, CREnabled: false,
StunKeepaliveStartS: 9000, StunKeepaliveStartS: 9000,
StunKeepaliveMinS: 900, StunKeepaliveMinS: 900,
RawStunServers: []string{"foo"}, RawStunServers: []string{"foo"},
FeatureFlags: []string{"feature"}, FeatureFlags: []string{"feature"},
ConnectionPriorityTCPLAN: 40,
ConnectionPriorityQUICLAN: 45,
ConnectionPriorityTCPWAN: 50,
ConnectionPriorityQUICWAN: 55,
ConnectionPriorityRelay: 9000,
} }
expectedPath := "/media/syncthing" expectedPath := "/media/syncthing"
@ -514,7 +524,7 @@ func TestFolderCheckPath(t *testing.T) {
n := t.TempDir() n := t.TempDir()
testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, n) testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, n)
err := os.MkdirAll(filepath.Join(n, "dir", ".stfolder"), os.FileMode(0777)) err := os.MkdirAll(filepath.Join(n, "dir", ".stfolder"), os.FileMode(0o777))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -55,6 +55,15 @@ func (opts *OptionsConfiguration) prepare(guiPWIsSet bool) {
if opts.ConnectionLimitMax < 0 { if opts.ConnectionLimitMax < 0 {
opts.ConnectionLimitMax = 0 opts.ConnectionLimitMax = 0
} }
if opts.ConnectionPriorityQUICWAN <= opts.ConnectionPriorityQUICLAN {
l.Warnln("Connection priority number for QUIC over WAN must be worse (higher) than QUIC over LAN. Correcting.")
opts.ConnectionPriorityQUICWAN = opts.ConnectionPriorityQUICLAN + 1
}
if opts.ConnectionPriorityTCPWAN <= opts.ConnectionPriorityTCPLAN {
l.Warnln("Connection priority number for TCP over WAN must be worse (higher) than TCP over LAN. Correcting.")
opts.ConnectionPriorityTCPWAN = opts.ConnectionPriorityTCPLAN + 1
}
} }
// RequiresRestartOnly returns a copy with only the attributes that require // RequiresRestartOnly returns a copy with only the attributes that require

View File

@ -82,7 +82,13 @@ type OptionsConfiguration struct {
ConnectionLimitMax int `protobuf:"varint,52,opt,name=connection_limit_max,json=connectionLimitMax,proto3,casttype=int" json:"connectionLimitMax" xml:"connectionLimitMax"` ConnectionLimitMax int `protobuf:"varint,52,opt,name=connection_limit_max,json=connectionLimitMax,proto3,casttype=int" json:"connectionLimitMax" xml:"connectionLimitMax"`
// When set, this allows TLS 1.2 on sync connections, where we otherwise // When set, this allows TLS 1.2 on sync connections, where we otherwise
// default to TLS 1.3+ only. // default to TLS 1.3+ only.
InsecureAllowOldTLSVersions bool `protobuf:"varint,53,opt,name=insecure_allow_old_tls_versions,json=insecureAllowOldTlsVersions,proto3" json:"insecureAllowOldTLSVersions" xml:"insecureAllowOldTLSVersions"` InsecureAllowOldTLSVersions bool `protobuf:"varint,53,opt,name=insecure_allow_old_tls_versions,json=insecureAllowOldTlsVersions,proto3" json:"insecureAllowOldTLSVersions" xml:"insecureAllowOldTLSVersions"`
ConnectionPriorityTCPLAN int `protobuf:"varint,54,opt,name=connection_priority_tcp_lan,json=connectionPriorityTcpLan,proto3,casttype=int" json:"connectionPriorityTcpLan" xml:"connectionPriorityTcpLan" default:"10"`
ConnectionPriorityQUICLAN int `protobuf:"varint,55,opt,name=connection_priority_quic_lan,json=connectionPriorityQuicLan,proto3,casttype=int" json:"connectionPriorityQuicLan" xml:"connectionPriorityQuicLan" default:"20"`
ConnectionPriorityTCPWAN int `protobuf:"varint,56,opt,name=connection_priority_tcp_wan,json=connectionPriorityTcpWan,proto3,casttype=int" json:"connectionPriorityTcpWan" xml:"connectionPriorityTcpWan" default:"30"`
ConnectionPriorityQUICWAN int `protobuf:"varint,57,opt,name=connection_priority_quic_wan,json=connectionPriorityQuicWan,proto3,casttype=int" json:"connectionPriorityQuicWan" xml:"connectionPriorityQuicWan" default:"40"`
ConnectionPriorityRelay int `protobuf:"varint,58,opt,name=connection_priority_relay,json=connectionPriorityRelay,proto3,casttype=int" json:"connectionPriorityRelay" xml:"connectionPriorityRelay" default:"50"`
ConnectionPriorityUpgradeThreshold int `protobuf:"varint,59,opt,name=connection_priority_upgrade_threshold,json=connectionPriorityUpgradeThreshold,proto3,casttype=int" json:"connectionPriorityUpgradeThreshold" xml:"connectionPriorityUpgradeThreshold" default:"0"`
// Legacy deprecated // Legacy deprecated
DeprecatedUPnPEnabled bool `protobuf:"varint,9000,opt,name=upnp_enabled,json=upnpEnabled,proto3" json:"-" xml:"upnpEnabled,omitempty"` // Deprecated: Do not use. DeprecatedUPnPEnabled bool `protobuf:"varint,9000,opt,name=upnp_enabled,json=upnpEnabled,proto3" json:"-" xml:"upnpEnabled,omitempty"` // Deprecated: Do not use.
DeprecatedUPnPLeaseM int `protobuf:"varint,9001,opt,name=upnp_lease_m,json=upnpLeaseM,proto3,casttype=int" json:"-" xml:"upnpLeaseMinutes,omitempty"` // Deprecated: Do not use. DeprecatedUPnPLeaseM int `protobuf:"varint,9001,opt,name=upnp_lease_m,json=upnpLeaseM,proto3,casttype=int" json:"-" xml:"upnpLeaseMinutes,omitempty"` // Deprecated: Do not use.
@ -135,211 +141,228 @@ func init() {
} }
var fileDescriptor_d09882599506ca03 = []byte{ var fileDescriptor_d09882599506ca03 = []byte{
// 3261 bytes of a gzipped FileDescriptorProto // 3521 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x5a, 0x5d, 0x6c, 0x1d, 0x47, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x5a, 0x5d, 0x6c, 0x1d, 0x47,
0xd9, 0xce, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x1e, 0x3b, 0xf6, 0x36, 0x49, 0xbd, 0xee, 0xc9, 0x15, 0xce, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x1e, 0x3b, 0xf6, 0x26, 0x4e, 0xbd, 0xee, 0xcd,
0x49, 0xeb, 0xfe, 0x25, 0xb6, 0x93, 0xe6, 0x4b, 0x23, 0x7d, 0xea, 0xe7, 0x9f, 0xfa, 0xab, 0x1b, 0x4d, 0xeb, 0xb6, 0x69, 0x62, 0x3b, 0x3f, 0x4d, 0x8d, 0x50, 0xf1, 0x4f, 0x4d, 0xdd, 0xd8, 0x8e,
0x3b, 0xb1, 0xc6, 0xf6, 0xf7, 0xa1, 0x22, 0xb4, 0x1a, 0xef, 0xce, 0xb1, 0x17, 0xef, 0x99, 0x3d, 0x3b, 0xb6, 0x6b, 0x54, 0x84, 0x56, 0xe3, 0xbd, 0x73, 0xed, 0xad, 0xf7, 0xee, 0xde, 0xec, 0xce,
0xdd, 0x99, 0xf5, 0x4f, 0x8b, 0xa0, 0x2a, 0x82, 0x72, 0x07, 0x58, 0xfc, 0x48, 0x20, 0xa1, 0x22, 0xfa, 0xa7, 0x45, 0x50, 0x15, 0x41, 0x79, 0xa3, 0x5c, 0x15, 0x90, 0x40, 0xaa, 0x8a, 0x00, 0x89,
0x40, 0xa2, 0x94, 0x22, 0x24, 0x24, 0x24, 0xb8, 0xa1, 0x42, 0x42, 0xaa, 0xe0, 0xc2, 0xbe, 0x44, 0x52, 0x8a, 0x90, 0x90, 0x90, 0x40, 0x42, 0x54, 0x48, 0x48, 0x15, 0x3c, 0xf8, 0x3e, 0x21, 0x24,
0xa2, 0x2c, 0xaa, 0xd3, 0xab, 0x73, 0x81, 0xc4, 0xb9, 0x34, 0x37, 0x68, 0x66, 0xff, 0x66, 0x77, 0xca, 0xa2, 0x3a, 0x7d, 0xba, 0x0f, 0x3c, 0xdc, 0x47, 0xf3, 0x82, 0x66, 0xf6, 0x6f, 0x76, 0x77,
0xe7, 0x24, 0xb9, 0x3b, 0xfb, 0x3e, 0xef, 0xfb, 0xce, 0xf3, 0xce, 0xcf, 0x3b, 0xef, 0xcc, 0x1c, 0xd6, 0xce, 0xdb, 0xdd, 0xf3, 0x9d, 0x39, 0x73, 0xbe, 0xf9, 0x39, 0x73, 0xce, 0xcc, 0x95, 0x2f,
0xfd, 0xb2, 0xe7, 0xae, 0x5e, 0xb5, 0x7d, 0xd2, 0x70, 0xd7, 0xae, 0xfa, 0x2d, 0xe6, 0xfa, 0x84, 0x9b, 0xc6, 0xea, 0x35, 0xdd, 0xb6, 0xaa, 0xc6, 0xda, 0x35, 0xbb, 0x4e, 0x0c, 0xdb, 0x72, 0x83,
0xc6, 0x5f, 0x61, 0x80, 0xf8, 0xd7, 0x95, 0x56, 0xe0, 0x33, 0x1f, 0x9c, 0x88, 0x85, 0xe7, 0x87, 0x2f, 0xcf, 0x41, 0xf4, 0xeb, 0x6a, 0xdd, 0xb1, 0x89, 0x0d, 0x4e, 0x04, 0xc2, 0x0b, 0x7d, 0x9c,
0x24, 0x75, 0x16, 0x12, 0x97, 0xac, 0xc5, 0x0a, 0xe7, 0xcf, 0x49, 0x00, 0x75, 0xdf, 0xc4, 0x89, 0x3a, 0xf1, 0x2c, 0xc3, 0x5a, 0x0b, 0x14, 0x2e, 0x9c, 0xe3, 0x00, 0xd7, 0x78, 0x1d, 0x87, 0xe2,
0xf8, 0x24, 0xde, 0x66, 0xf1, 0xcf, 0xda, 0xbf, 0xe6, 0xf4, 0x81, 0xbb, 0x71, 0x0b, 0xd3, 0x72, 0x93, 0x78, 0x9b, 0x04, 0x3f, 0x4b, 0xef, 0x2d, 0xca, 0x3d, 0x77, 0x83, 0x1e, 0x26, 0xf9, 0x1e,
0x0b, 0xe0, 0x47, 0x9a, 0x7e, 0xd6, 0x73, 0x29, 0xc3, 0xc4, 0x42, 0x8e, 0x13, 0x60, 0x4a, 0x31, 0xc0, 0x7b, 0x92, 0x7c, 0xd6, 0x34, 0x5c, 0x82, 0x2d, 0x0d, 0x55, 0x2a, 0x0e, 0x76, 0x5d, 0xec,
0x35, 0xb4, 0x91, 0x63, 0xa3, 0x27, 0xa7, 0xe8, 0x41, 0x64, 0x02, 0x88, 0xb6, 0xe6, 0x05, 0x3c, 0x2a, 0xd2, 0xe0, 0xb1, 0xa1, 0x93, 0x13, 0xee, 0x9e, 0xaf, 0x02, 0x88, 0xb6, 0x66, 0x19, 0x3c,
0x99, 0xa2, 0xed, 0xc8, 0x3c, 0xe3, 0x15, 0x45, 0x9d, 0xc8, 0xbc, 0xbc, 0xdd, 0xf4, 0x6e, 0xd5, 0x1e, 0xa1, 0x2d, 0x5f, 0x3d, 0x63, 0xa6, 0x45, 0x6d, 0x5f, 0xbd, 0xbc, 0x5d, 0x33, 0xc7, 0x4a,
0x0a, 0xf2, 0xda, 0x88, 0x83, 0x1b, 0x28, 0xf4, 0xd8, 0xad, 0x5a, 0xf2, 0xa3, 0x76, 0xb8, 0x57, 0x29, 0x79, 0x69, 0xb0, 0x82, 0xab, 0xc8, 0x33, 0xc9, 0x58, 0x29, 0xfc, 0x51, 0xda, 0xdf, 0x2d,
0x7f, 0x34, 0xf9, 0xbd, 0xbb, 0x5f, 0x57, 0x38, 0x87, 0x65, 0xd7, 0xe0, 0x9f, 0x9a, 0x6e, 0xac, 0x3f, 0x1c, 0xfe, 0x6e, 0x34, 0xcb, 0x02, 0xe3, 0x30, 0x6b, 0x1a, 0xfc, 0x57, 0x92, 0x95, 0x35,
0x79, 0xfe, 0x2a, 0xf2, 0x2c, 0xc7, 0xa5, 0xb6, 0xbf, 0x89, 0x83, 0x1d, 0x8b, 0xe2, 0x60, 0x13, 0xd3, 0x5e, 0x45, 0xa6, 0x56, 0x31, 0x5c, 0xdd, 0xde, 0xc4, 0xce, 0x8e, 0xe6, 0x62, 0x67, 0x13,
0x07, 0xd4, 0x38, 0x2a, 0x88, 0xfe, 0x46, 0x3b, 0x88, 0xcc, 0x7e, 0x88, 0xb6, 0xfe, 0x57, 0xe8, 0x3b, 0xae, 0x72, 0x94, 0x39, 0xfa, 0x3b, 0x69, 0xcf, 0x57, 0xbb, 0x21, 0xda, 0xfa, 0x32, 0xd3,
0x4d, 0x12, 0xb2, 0x14, 0xe3, 0xed, 0xc8, 0x3c, 0xb7, 0x96, 0xca, 0xfc, 0x90, 0xd8, 0x38, 0x01, 0x1b, 0xb7, 0xac, 0xc5, 0x00, 0x6f, 0xf9, 0xea, 0xb9, 0xb5, 0x48, 0x66, 0x7b, 0x96, 0x8e, 0x43,
0x3a, 0x91, 0xf9, 0xbc, 0x20, 0xac, 0x42, 0x15, 0xbc, 0xdb, 0x7b, 0xf5, 0x01, 0x95, 0x6a, 0x67, 0xa0, 0xed, 0xab, 0x57, 0x98, 0xc3, 0x22, 0x54, 0xe0, 0x77, 0x6b, 0xb7, 0xdc, 0x23, 0x52, 0x6d,
0xaf, 0xae, 0x6e, 0xa0, 0x18, 0xa8, 0x8a, 0x1b, 0x1c, 0x8c, 0x0d, 0x67, 0xd2, 0xa0, 0x12, 0x39, 0xef, 0x96, 0xc5, 0x1d, 0xa4, 0x89, 0x8a, 0x7c, 0x83, 0xbd, 0x41, 0xc3, 0xa9, 0x88, 0x54, 0x28,
0xf8, 0x4c, 0x15, 0x30, 0x26, 0x68, 0xd5, 0xc3, 0x8e, 0x71, 0x6c, 0x44, 0x1b, 0x7d, 0x6c, 0xea, 0x07, 0x9f, 0x8b, 0x08, 0x63, 0x0b, 0xad, 0x9a, 0xb8, 0xa2, 0x1c, 0x1b, 0x94, 0x86, 0x1e, 0x99,
0x7d, 0x1e, 0xf0, 0xd9, 0xcc, 0xe3, 0x2b, 0x31, 0x58, 0x8d, 0x36, 0x01, 0x3a, 0x91, 0xf9, 0xac, 0xf8, 0x80, 0x12, 0x3e, 0x1b, 0x5b, 0x7c, 0x21, 0x00, 0xf3, 0x6c, 0x43, 0xa0, 0xed, 0xab, 0x4f,
0x22, 0xda, 0x04, 0x95, 0xc2, 0x65, 0x41, 0x88, 0x79, 0xac, 0x5d, 0xdc, 0x74, 0x03, 0x0e, 0xf7, 0x09, 0xd8, 0x86, 0x28, 0x47, 0x97, 0x38, 0x1e, 0xa6, 0x5c, 0x0b, 0xcc, 0x14, 0x01, 0xfb, 0xbb,
0xea, 0x8f, 0x70, 0xd3, 0xdd, 0xfd, 0x7a, 0x85, 0x54, 0x25, 0xcc, 0x44, 0x0e, 0x3e, 0xd1, 0xf4, 0xe5, 0x87, 0x68, 0xd3, 0x46, 0xb3, 0x9c, 0x73, 0x2a, 0x47, 0x33, 0x94, 0x83, 0x4f, 0x25, 0xb9,
0x21, 0xcf, 0xb7, 0x95, 0x51, 0x3e, 0x22, 0xa2, 0xfc, 0x09, 0x8f, 0xf2, 0xcc, 0x3c, 0xd7, 0x29, 0xcf, 0xb4, 0x75, 0x21, 0xcb, 0x87, 0x18, 0xcb, 0x9f, 0x51, 0x96, 0x67, 0x66, 0xa9, 0x4e, 0x8a,
0x04, 0x39, 0xe0, 0x25, 0xa2, 0x52, 0x8c, 0xcf, 0xc4, 0x53, 0x50, 0x01, 0x2a, 0x42, 0x54, 0x3b, 0x64, 0x8f, 0x19, 0x8a, 0x32, 0x1c, 0x9f, 0x0c, 0x96, 0xa0, 0x00, 0x14, 0x50, 0x14, 0x1b, 0x29,
0xe9, 0x22, 0x97, 0x02, 0x2c, 0xf3, 0x81, 0xe7, 0x84, 0x41, 0x25, 0xbc, 0xbf, 0x68, 0x7a, 0x7f, 0x90, 0x73, 0x04, 0xb3, 0xfe, 0xc0, 0x73, 0xac, 0x41, 0x8e, 0xde, 0xdf, 0x25, 0xb9, 0x3b, 0xa0,
0x1c, 0x1e, 0x4a, 0x7c, 0x59, 0x2d, 0x3f, 0x60, 0xc6, 0xf1, 0x11, 0x6d, 0xf4, 0xf8, 0xd4, 0x0f, 0x87, 0x42, 0x5b, 0x5a, 0xdd, 0x76, 0x88, 0x72, 0x7c, 0x50, 0x1a, 0x3a, 0x3e, 0xf1, 0x63, 0x4a,
0x78, 0x68, 0x3d, 0xa9, 0xab, 0x45, 0x3f, 0x60, 0xed, 0xc8, 0xec, 0x2b, 0x34, 0xcd, 0x85, 0x9d, 0xad, 0x23, 0x32, 0xb5, 0x60, 0x3b, 0xa4, 0xe5, 0xab, 0x5d, 0xa9, 0xae, 0xa9, 0xb0, 0xed, 0xab,
0xc8, 0x7c, 0xba, 0x1a, 0x14, 0x47, 0xa4, 0x88, 0x26, 0xc6, 0xc7, 0x26, 0xfe, 0xab, 0x76, 0x18, 0x4f, 0xe4, 0x49, 0x51, 0x84, 0x63, 0x34, 0x3a, 0x32, 0x3c, 0xfa, 0x6c, 0x69, 0xdf, 0x57, 0x8f,
0x99, 0xc7, 0x5c, 0xc2, 0xda, 0x7b, 0x75, 0x85, 0x1b, 0x95, 0xf0, 0x70, 0xaf, 0x7e, 0x5c, 0x98, 0x19, 0x16, 0x69, 0xed, 0x96, 0x05, 0x66, 0x44, 0xc2, 0xfd, 0xdd, 0xf2, 0x71, 0xd6, 0xb4, 0xd1,
0xee, 0xee, 0xd7, 0x0b, 0x4c, 0x60, 0x55, 0x17, 0x7c, 0xf5, 0xa8, 0x3e, 0x52, 0x8a, 0xa6, 0x19, 0x2c, 0xa7, 0x3c, 0x81, 0x79, 0x5d, 0xf0, 0xad, 0xa3, 0xf2, 0x60, 0x86, 0x4d, 0xcd, 0x33, 0x89,
0x7a, 0xcc, 0xb5, 0x11, 0x65, 0x69, 0xde, 0x30, 0x4e, 0x8c, 0x68, 0xa3, 0x27, 0xa7, 0x7e, 0xc7, 0xa1, 0x23, 0x97, 0x44, 0x71, 0x43, 0x39, 0x31, 0x28, 0x0d, 0x9d, 0x9c, 0xf8, 0x03, 0xa5, 0xd6,
0x43, 0xeb, 0x4d, 0x1d, 0x2e, 0x4c, 0xf3, 0x95, 0xdc, 0x8e, 0xcc, 0xfe, 0x82, 0xd3, 0x58, 0xdc, 0x19, 0x19, 0x9c, 0x9b, 0xa4, 0x3b, 0xb9, 0xe5, 0xab, 0xdd, 0x29, 0xa3, 0x81, 0xb8, 0xed, 0xab,
0x89, 0xcc, 0x1b, 0xd5, 0xf0, 0x62, 0x4c, 0x0a, 0xf0, 0xf3, 0x8d, 0xc6, 0xf8, 0xc4, 0xad, 0x5b, 0xb7, 0xf2, 0xf4, 0x02, 0x8c, 0x23, 0xf8, 0xd5, 0x6a, 0x75, 0x64, 0x74, 0x6c, 0xec, 0xf6, 0xf5,
0x37, 0xaf, 0xdd, 0xbc, 0xfe, 0x85, 0x5b, 0x71, 0xb4, 0xed, 0xbd, 0xba, 0xd2, 0xa1, 0x5a, 0x7c, 0xdb, 0x37, 0xbe, 0x36, 0x16, 0xb0, 0x6d, 0xed, 0x96, 0x85, 0x06, 0xc5, 0xe2, 0xfd, 0xdd, 0x32,
0xb8, 0x57, 0x07, 0x55, 0x27, 0xbb, 0xfb, 0xf5, 0x12, 0x4d, 0xf8, 0x44, 0xd1, 0x38, 0x8d, 0x30, 0xc8, 0x1b, 0x69, 0x34, 0xcb, 0x19, 0x37, 0xe1, 0xa3, 0xe9, 0xc6, 0x11, 0xc3, 0x30, 0x18, 0x81,
0x49, 0x46, 0xe0, 0xae, 0x7e, 0xba, 0x89, 0xb6, 0x2d, 0x8a, 0x89, 0x63, 0x6d, 0xac, 0xb6, 0xa8, 0xbb, 0xf2, 0xe9, 0x1a, 0xda, 0xd6, 0x5c, 0x6c, 0x55, 0xb4, 0x8d, 0xd5, 0xba, 0xab, 0x3c, 0xcc,
0xf1, 0xa8, 0x18, 0xcc, 0xe7, 0xda, 0x91, 0x79, 0xaa, 0x89, 0xb6, 0x97, 0x30, 0x71, 0x6e, 0xaf, 0x26, 0xf3, 0xe9, 0x96, 0xaf, 0x9e, 0xaa, 0xa1, 0xed, 0x45, 0x6c, 0x55, 0xee, 0xac, 0xd6, 0x69,
0xb6, 0x78, 0x72, 0xe9, 0x13, 0x61, 0x49, 0xb2, 0x74, 0x7c, 0xa0, 0xac, 0x98, 0x3a, 0x0c, 0xb0, 0x70, 0xe9, 0x62, 0xb4, 0x38, 0x59, 0x34, 0x3f, 0x90, 0x57, 0x8c, 0x0c, 0x3a, 0x58, 0xdf, 0x0c,
0xbd, 0x19, 0x3b, 0x7c, 0xac, 0xe0, 0x10, 0x62, 0x7b, 0xb3, 0xec, 0x30, 0x95, 0x15, 0x1c, 0xa6, 0x0c, 0x3e, 0x92, 0x32, 0x08, 0xb1, 0xbe, 0x99, 0x35, 0x18, 0xc9, 0x52, 0x06, 0x23, 0x21, 0xf8,
0x42, 0xf0, 0x5b, 0x4d, 0x1f, 0x0a, 0xb0, 0xed, 0x13, 0x82, 0x6d, 0x9e, 0xde, 0x2d, 0x97, 0x30, 0xbd, 0x24, 0xf7, 0x39, 0x58, 0xb7, 0x2d, 0x0b, 0xeb, 0x34, 0xbc, 0x6b, 0x86, 0x45, 0xb0, 0xb3,
0x1c, 0x6c, 0x22, 0xcf, 0xa2, 0xc6, 0x49, 0xe1, 0xfb, 0xcb, 0x22, 0xa9, 0xa7, 0x2a, 0x73, 0x09, 0x89, 0x4c, 0xcd, 0x55, 0x4e, 0x32, 0xdb, 0xdf, 0x60, 0x41, 0x3d, 0x52, 0x99, 0x09, 0xe1, 0x45,
0xbc, 0xc4, 0x73, 0x87, 0x6c, 0x98, 0x01, 0x9d, 0xc8, 0x1c, 0x15, 0x6d, 0x2b, 0x51, 0x69, 0x94, 0x1a, 0x3b, 0xf8, 0x86, 0x31, 0xd0, 0xf6, 0xd5, 0x21, 0xd6, 0xb7, 0x10, 0xe5, 0x66, 0xe9, 0xd6,
0x6e, 0x8c, 0xa5, 0x94, 0x0e, 0xf7, 0xea, 0x47, 0x6f, 0x8c, 0x89, 0xfc, 0x5e, 0x69, 0x07, 0xaa, 0x70, 0xe4, 0xd2, 0xfe, 0x6e, 0xf9, 0xe8, 0xad, 0x61, 0x16, 0xdf, 0x73, 0xfd, 0x40, 0x71, 0x2f,
0x5b, 0x01, 0x0d, 0xbd, 0x37, 0xc0, 0x1e, 0xda, 0xa1, 0x59, 0x0e, 0xd0, 0x45, 0x0e, 0x78, 0xb9, 0xa0, 0x2a, 0x77, 0x3a, 0xd8, 0x44, 0x3b, 0x6e, 0x1c, 0x03, 0x64, 0x16, 0x03, 0x9e, 0x6f, 0xf9,
0x1d, 0x99, 0xa7, 0x63, 0x24, 0x5f, 0xe8, 0xb5, 0x84, 0x90, 0x24, 0x2d, 0xaf, 0xf0, 0x74, 0xc5, 0xea, 0xe9, 0x00, 0x49, 0x36, 0x7a, 0x29, 0x74, 0x88, 0x93, 0x66, 0x77, 0x78, 0xb4, 0x63, 0x61,
0xc2, 0xa2, 0x31, 0x78, 0xe7, 0xa8, 0x7e, 0x21, 0x69, 0x28, 0x23, 0x92, 0x77, 0x52, 0xd3, 0x38, 0xba, 0x31, 0x78, 0xeb, 0xa8, 0xdc, 0x1f, 0x76, 0x14, 0x3b, 0x92, 0x0c, 0x52, 0x4d, 0x39, 0xc5,
0x25, 0x3a, 0xe9, 0x8f, 0x7c, 0x0e, 0x0f, 0x41, 0xae, 0x57, 0x09, 0x61, 0xa1, 0x1d, 0x99, 0x43, 0x06, 0xe9, 0x2f, 0x74, 0x0d, 0xf7, 0x41, 0xaa, 0x97, 0xa3, 0x30, 0xd7, 0xf2, 0xd5, 0x3e, 0x47,
0x81, 0x1a, 0xca, 0x12, 0x6d, 0x17, 0x5c, 0x62, 0x39, 0x3e, 0x26, 0x2d, 0xd9, 0xae, 0xfe, 0xba, 0x0c, 0xc5, 0x81, 0xb6, 0x00, 0xe7, 0xbc, 0x1c, 0x19, 0xe6, 0xb6, 0x6c, 0xa1, 0xbd, 0x62, 0x88,
0x43, 0xbc, 0x93, 0xc7, 0x79, 0x27, 0x77, 0xa3, 0x09, 0x8d, 0x38, 0xce, 0x2a, 0x02, 0x56, 0xf5, 0x0e, 0xf2, 0x08, 0x1d, 0xe4, 0x22, 0x37, 0xa1, 0x12, 0xf0, 0xcc, 0x23, 0x60, 0x55, 0x3e, 0xed,
0xd3, 0x94, 0xa1, 0x80, 0x59, 0xab, 0x81, 0xbf, 0x45, 0x71, 0x60, 0xf4, 0x88, 0xbe, 0xfe, 0xef, 0x12, 0xe4, 0x10, 0x6d, 0xd5, 0xb1, 0xb7, 0x5c, 0xec, 0x28, 0x1d, 0x6c, 0xac, 0xbf, 0xd8, 0xf2,
0x76, 0x64, 0xf6, 0x08, 0x60, 0x2a, 0x96, 0x77, 0x22, 0xf3, 0x49, 0x11, 0x8e, 0x2c, 0xec, 0xda, 0xd5, 0x0e, 0x06, 0x4c, 0x04, 0xf2, 0xb6, 0xaf, 0x3e, 0xc6, 0xe8, 0xf0, 0xc2, 0xc2, 0x91, 0x4e,
0xd3, 0x05, 0x53, 0xf0, 0x33, 0x4d, 0x3f, 0x47, 0x10, 0xb3, 0x58, 0x80, 0xf8, 0xae, 0x86, 0xbc, 0x35, 0x05, 0xbf, 0x90, 0xe4, 0x73, 0x16, 0x22, 0x1a, 0x71, 0x10, 0x3d, 0xd5, 0x90, 0x19, 0x4f,
0x6c, 0x60, 0x7b, 0x45, 0x63, 0x6f, 0x1c, 0x44, 0xa6, 0x7e, 0x67, 0x72, 0x39, 0x4f, 0xeb, 0x3a, 0x6c, 0x27, 0xeb, 0xec, 0xde, 0x9e, 0xaf, 0xca, 0xf3, 0xe3, 0x4b, 0x49, 0x58, 0x97, 0x2d, 0x44,
0x41, 0x2c, 0x1f, 0x63, 0x53, 0x34, 0x9c, 0x8b, 0x14, 0x29, 0x5c, 0x36, 0x28, 0x7c, 0x49, 0xe9, 0x92, 0x39, 0x56, 0x59, 0xc7, 0x89, 0x48, 0x10, 0xc2, 0xf9, 0x06, 0xa9, 0x2f, 0x2e, 0x5c, 0x73,
0x5a, 0x6a, 0x02, 0xf6, 0x13, 0xc4, 0x96, 0x53, 0x3a, 0xe9, 0x84, 0xf8, 0x7d, 0x85, 0xa7, 0x87, 0x5d, 0xc0, 0x6e, 0x0b, 0x91, 0xa5, 0xc8, 0x9d, 0x68, 0x41, 0xfc, 0x31, 0xe7, 0xa7, 0x89, 0x91,
0x11, 0xc5, 0x56, 0xd3, 0x38, 0x23, 0xa6, 0xc2, 0xd7, 0xf9, 0x54, 0x38, 0x79, 0x67, 0x72, 0x79, 0x8b, 0xb5, 0x9a, 0x72, 0x86, 0x2d, 0x85, 0xef, 0xd0, 0xa5, 0x70, 0x72, 0x7e, 0x7c, 0x69, 0x96,
0x9e, 0x8b, 0xf9, 0xe0, 0x9f, 0x21, 0x88, 0xc5, 0x1f, 0x2e, 0x09, 0x99, 0x28, 0x7e, 0x6a, 0x29, 0x8a, 0xe9, 0xe4, 0x9f, 0xb1, 0x10, 0x09, 0x3e, 0x0c, 0xcb, 0x23, 0x2c, 0xf9, 0x29, 0x45, 0xce,
0x59, 0x59, 0xae, 0x5c, 0x1b, 0xed, 0xbd, 0x7a, 0xc5, 0xbe, 0x2a, 0xca, 0x56, 0x50, 0xde, 0x30, 0xf2, 0x72, 0xe1, 0xde, 0x68, 0xed, 0x96, 0x73, 0xed, 0xf3, 0xa2, 0x78, 0x07, 0x25, 0x1d, 0x43,
0x04, 0x32, 0xfb, 0x58, 0x06, 0xfe, 0xac, 0xe9, 0x43, 0x45, 0xf2, 0x01, 0x26, 0x78, 0x4b, 0xcc, 0xc0, 0x7b, 0x1f, 0xc8, 0xc0, 0xdf, 0x24, 0xb9, 0x2f, 0xed, 0xbc, 0x83, 0x2d, 0xbc, 0xc5, 0x56,
0xe4, 0xb3, 0x82, 0xfe, 0x2e, 0xa7, 0x7f, 0xea, 0xce, 0xe4, 0x32, 0x8c, 0x01, 0x1e, 0x40, 0x1f, 0xf2, 0x59, 0xe6, 0x7e, 0x83, 0xba, 0x7f, 0x6a, 0x7e, 0x7c, 0x09, 0x06, 0x00, 0x25, 0xd0, 0x65,
0x41, 0x2c, 0xfd, 0xcc, 0x42, 0xa8, 0xa7, 0x21, 0x14, 0x11, 0x29, 0x88, 0x6b, 0x72, 0x10, 0x0a, 0x21, 0x12, 0x7d, 0xc6, 0x14, 0xca, 0x11, 0x85, 0x34, 0xc2, 0x91, 0xb8, 0xce, 0x93, 0x10, 0xd8,
0x1f, 0x2a, 0x21, 0x0f, 0xe4, 0x1a, 0x0f, 0x44, 0xa6, 0x00, 0x07, 0xe4, 0x50, 0x52, 0xa9, 0x22, 0x10, 0x09, 0x29, 0x91, 0xeb, 0x94, 0x08, 0xef, 0x02, 0xec, 0xe1, 0xa9, 0x44, 0x52, 0x01, 0x19,
0x18, 0xe6, 0x36, 0xb1, 0x1f, 0x32, 0x8b, 0x1a, 0x7d, 0xc5, 0x60, 0x96, 0x63, 0x60, 0x29, 0x09, 0x62, 0xd4, 0xb0, 0xed, 0x11, 0xcd, 0x55, 0xba, 0xd2, 0x64, 0x96, 0x02, 0x60, 0x31, 0x24, 0x13,
0x26, 0xfd, 0xe4, 0x33, 0xdd, 0x29, 0x04, 0x53, 0x44, 0xba, 0x2d, 0x3f, 0x85, 0x0f, 0x95, 0x30, 0x7d, 0xd2, 0x95, 0x5e, 0x49, 0x91, 0x49, 0x23, 0x45, 0xdb, 0x4f, 0x60, 0x43, 0x24, 0x8c, 0xb7,
0x5b, 0x72, 0x32, 0x85, 0x62, 0x30, 0xa9, 0x14, 0xfc, 0x50, 0xd3, 0x8d, 0x90, 0xa2, 0x35, 0x6c, 0x1c, 0xef, 0x42, 0x9a, 0x4c, 0x24, 0x05, 0x3f, 0x91, 0x64, 0xc5, 0x73, 0xd1, 0x1a, 0xd6, 0x1c,
0x05, 0x98, 0xef, 0xfb, 0x2e, 0x59, 0xb3, 0x90, 0x6d, 0xe3, 0x16, 0xc3, 0x8e, 0x01, 0x44, 0x34, 0x4c, 0xcf, 0x7d, 0xc3, 0x5a, 0xd3, 0x90, 0xae, 0xe3, 0x3a, 0xc1, 0x15, 0x05, 0x30, 0x36, 0x88,
0x88, 0xaf, 0x80, 0x15, 0x38, 0x99, 0x48, 0xf9, 0x0a, 0x08, 0x83, 0xf4, 0xab, 0x13, 0x99, 0x67, 0xee, 0x80, 0x65, 0x38, 0x1e, 0x4a, 0xe9, 0x0e, 0xf0, 0x9c, 0xe8, 0xab, 0xed, 0xab, 0x67, 0x19,
0x45, 0x10, 0xb9, 0x48, 0x22, 0x2c, 0x2b, 0x16, 0xbe, 0xf8, 0x8c, 0xcf, 0x5d, 0xc2, 0x41, 0x41, 0x89, 0x44, 0xc4, 0x39, 0xcc, 0x2b, 0xa6, 0xbe, 0xe8, 0x8a, 0x4f, 0x4c, 0xc2, 0x5e, 0xe6, 0x02,
0x01, 0xa6, 0x0c, 0x52, 0x39, 0x78, 0x4b, 0x1f, 0x28, 0x93, 0xa3, 0x18, 0x13, 0xa3, 0x5f, 0x10, 0x8c, 0x3c, 0x88, 0xe4, 0xe0, 0x0d, 0xb9, 0x27, 0xeb, 0x9c, 0x8b, 0xb1, 0xa5, 0x74, 0x33, 0xc7,
0x9b, 0x3b, 0x88, 0xcc, 0x13, 0x2b, 0x70, 0x09, 0x63, 0xd2, 0x8e, 0xcc, 0x13, 0x61, 0xc0, 0x7f, 0x66, 0xf6, 0x7c, 0xf5, 0xc4, 0x32, 0x5c, 0xc4, 0xd8, 0x6a, 0xf9, 0xea, 0x09, 0xcf, 0xa1, 0xbf,
0x75, 0x22, 0xb3, 0x27, 0x21, 0xc4, 0x3f, 0x25, 0x32, 0xa9, 0x42, 0xf6, 0x6b, 0x77, 0xbf, 0x9e, 0xda, 0xbe, 0xda, 0x11, 0x3a, 0x44, 0x3f, 0x39, 0x67, 0x22, 0x85, 0xf8, 0x57, 0xa3, 0x59, 0x0e,
0x98, 0x43, 0x50, 0x24, 0xc0, 0x65, 0xe0, 0xbb, 0x9a, 0xfe, 0x78, 0xb9, 0xf5, 0x90, 0xb8, 0x6f, 0x9b, 0x43, 0x90, 0x76, 0x80, 0xca, 0xc0, 0x0f, 0x24, 0xf9, 0x7c, 0xb6, 0x77, 0xcf, 0x32, 0xee,
0x84, 0xd8, 0x72, 0x1d, 0x63, 0x40, 0x14, 0x11, 0xaf, 0xc7, 0x7d, 0xb3, 0x22, 0xc4, 0x73, 0x33, 0x79, 0x58, 0x33, 0x2a, 0x4a, 0x0f, 0x4b, 0x22, 0x5e, 0x0d, 0xc6, 0x66, 0x99, 0x89, 0x67, 0xa6,
0x71, 0xdf, 0x24, 0x5f, 0x72, 0xdf, 0xa4, 0x0a, 0xb5, 0xb8, 0x53, 0xd2, 0xcf, 0x8e, 0xfc, 0x95, 0x82, 0xb1, 0x09, 0xbf, 0xf8, 0xb1, 0x89, 0x14, 0x4a, 0xc1, 0xa0, 0x44, 0x9f, 0x6d, 0xfe, 0x2b,
0x74, 0x4a, 0x8a, 0x95, 0x3b, 0x25, 0xd5, 0x02, 0x1f, 0x69, 0x7a, 0x7f, 0x85, 0x57, 0xe0, 0x19, 0x1c, 0x94, 0x08, 0xcb, 0x0e, 0x4a, 0xa4, 0x05, 0x3e, 0x96, 0xe4, 0xee, 0x9c, 0x5f, 0x8e, 0xa9,
0xe7, 0x04, 0xa3, 0x6f, 0xf2, 0xb9, 0x77, 0x7c, 0x05, 0xae, 0xc0, 0xf9, 0x76, 0x64, 0x1e, 0x0f, 0x9c, 0x63, 0x1e, 0x7d, 0x8f, 0xae, 0xbd, 0xe3, 0xcb, 0x70, 0x19, 0xce, 0xb6, 0x7c, 0xf5, 0xb8,
0x83, 0x15, 0x38, 0xdf, 0x89, 0xcc, 0x9b, 0x29, 0x11, 0x38, 0x2f, 0xcd, 0xae, 0x75, 0xc6, 0x5a, 0xe7, 0x2c, 0xc3, 0xd9, 0xb6, 0xaf, 0xde, 0x8e, 0x1c, 0x81, 0xb3, 0xdc, 0xea, 0x5a, 0x27, 0xa4,
0xf4, 0xd6, 0xd5, 0xab, 0x0e, 0x62, 0xe8, 0x0a, 0xdd, 0x21, 0x36, 0x5b, 0xe7, 0x87, 0x35, 0x82, 0xee, 0x8e, 0x5d, 0xbb, 0x56, 0x41, 0x04, 0x5d, 0x75, 0x77, 0x2c, 0x9d, 0xac, 0xd3, 0x62, 0xcd,
0xd9, 0x55, 0x82, 0xb7, 0xb8, 0x94, 0x13, 0x4e, 0x9c, 0xa4, 0x3f, 0x0e, 0xf7, 0xea, 0x0f, 0x61, 0xc2, 0xe4, 0x9a, 0x85, 0xb7, 0xa8, 0x94, 0x3a, 0x1c, 0x1a, 0x89, 0x7e, 0xec, 0xef, 0x96, 0x1f,
0xb8, 0xbb, 0x5f, 0x8f, 0x59, 0xc0, 0xbe, 0x52, 0x1c, 0x81, 0x07, 0xfe, 0xa1, 0xe9, 0x66, 0x39, 0xa0, 0x61, 0xa3, 0x59, 0x0e, 0xbc, 0x80, 0x5d, 0x19, 0x1e, 0x8e, 0x09, 0xfe, 0x23, 0xc9, 0x6a,
0x84, 0x96, 0x4f, 0xf9, 0x0e, 0x47, 0xb1, 0x1d, 0x06, 0xd8, 0xdb, 0x31, 0x06, 0x45, 0xfa, 0xfd, 0x96, 0x42, 0xdd, 0x76, 0xe9, 0x09, 0xe7, 0x62, 0xdd, 0x73, 0xb0, 0xb9, 0xa3, 0xf4, 0xb2, 0xf0,
0xbe, 0x38, 0x41, 0xac, 0xc0, 0x45, 0x9f, 0xb2, 0xb9, 0x0c, 0x6c, 0x47, 0xe6, 0xd9, 0x30, 0x28, 0xfb, 0x23, 0x56, 0x41, 0x2c, 0xc3, 0x05, 0xdb, 0x25, 0x33, 0x31, 0xd8, 0xf2, 0xd5, 0xb3, 0x9e,
0xca, 0x3a, 0x91, 0xf9, 0x54, 0x12, 0x64, 0x11, 0x90, 0xe2, 0x6d, 0x20, 0x8f, 0x8a, 0x94, 0x5c, 0x93, 0x96, 0xb5, 0x7d, 0xf5, 0xf1, 0x90, 0x64, 0x1a, 0xe0, 0xf8, 0x56, 0x91, 0xe9, 0xb2, 0x90,
0xb5, 0x56, 0xc8, 0x78, 0xe5, 0x29, 0x2c, 0xf8, 0x79, 0xa1, 0x4c, 0x01, 0x5e, 0x2c, 0x86, 0x55, 0x9c, 0x6f, 0x2d, 0x90, 0xd1, 0xcc, 0x93, 0xb5, 0xa0, 0xf5, 0x42, 0xd6, 0x05, 0x78, 0x31, 0x4d,
0x44, 0xc1, 0xdf, 0x15, 0x11, 0xba, 0xc4, 0x65, 0x2e, 0x3f, 0x47, 0xf0, 0xfd, 0xce, 0xa2, 0xc6, 0x2b, 0x8d, 0x82, 0x7f, 0x0b, 0x18, 0x1a, 0x96, 0x41, 0x0c, 0x5a, 0x47, 0xd0, 0xf3, 0x4e, 0x73,
0x90, 0x98, 0xc5, 0xdf, 0x13, 0xa7, 0x87, 0x15, 0x38, 0x17, 0xa3, 0x33, 0x1c, 0xe4, 0x09, 0xe3, 0x95, 0x3e, 0xb6, 0x8a, 0x7f, 0xc8, 0xaa, 0x87, 0x65, 0x38, 0x13, 0xa0, 0x53, 0x14, 0xa4, 0x01,
0x4c, 0x18, 0x14, 0x44, 0x59, 0xba, 0x28, 0xc9, 0xe5, 0x64, 0x71, 0x73, 0xac, 0x90, 0xc0, 0xcb, 0xe3, 0x8c, 0xe7, 0xa4, 0x44, 0x71, 0xb8, 0xc8, 0xc8, 0xf9, 0x60, 0x71, 0x7b, 0x38, 0x15, 0xc0,
0x1e, 0xaa, 0x22, 0xbe, 0x03, 0x71, 0x2b, 0x7e, 0x60, 0x28, 0x51, 0x80, 0x17, 0x8a, 0x01, 0x16, 0xb3, 0x16, 0xf2, 0x22, 0x7a, 0x02, 0xd1, 0x56, 0xb4, 0x60, 0xc8, 0xb8, 0x00, 0xfb, 0xd3, 0x04,
0x40, 0xf0, 0xae, 0xa6, 0x0f, 0xa1, 0x90, 0xf9, 0x56, 0xd8, 0x5a, 0x0b, 0x90, 0x83, 0xf3, 0xda, 0x53, 0x20, 0x78, 0x5b, 0x92, 0xfb, 0x90, 0x47, 0x6c, 0xcd, 0xab, 0xaf, 0x39, 0xa8, 0x82, 0x93,
0x64, 0xdd, 0x78, 0x5c, 0xc4, 0xb5, 0xc8, 0x4f, 0x40, 0x5c, 0x65, 0x25, 0xd6, 0x48, 0xb7, 0xf5, 0xdc, 0x64, 0x5d, 0x39, 0xcf, 0x78, 0x2d, 0xd0, 0x0a, 0x88, 0xaa, 0x2c, 0x07, 0x1a, 0xd1, 0xb1,
0x57, 0xb3, 0xc3, 0x82, 0x0a, 0x94, 0xa3, 0x99, 0x90, 0x0b, 0xb5, 0xf1, 0x09, 0xa8, 0xf4, 0x06, 0xfe, 0x62, 0x5c, 0x2c, 0x88, 0x40, 0x9e, 0xcd, 0x28, 0x9f, 0xa8, 0x8d, 0x8c, 0x42, 0xa1, 0x35,
0x9a, 0xfa, 0x50, 0xca, 0x81, 0xf9, 0x56, 0x2b, 0xe0, 0x3d, 0x2e, 0xb6, 0x46, 0x6a, 0x9c, 0x17, 0x50, 0x93, 0xfb, 0x22, 0x1f, 0x88, 0xad, 0xd5, 0x1d, 0x3a, 0xe2, 0xec, 0x68, 0x74, 0x95, 0x0b,
0x53, 0xe8, 0x06, 0x27, 0x92, 0xa8, 0x2c, 0xfb, 0x8b, 0x01, 0x86, 0x09, 0xde, 0x89, 0xcc, 0xf3, 0x6c, 0x09, 0xdd, 0xa2, 0x8e, 0x84, 0x2a, 0x4b, 0xf6, 0x82, 0x83, 0x61, 0x88, 0xb7, 0x7d, 0xf5,
0x71, 0x8f, 0x2a, 0xc0, 0x1a, 0x54, 0xda, 0x80, 0x4d, 0x1d, 0x6c, 0x60, 0xdc, 0xb2, 0x18, 0x6e, 0x42, 0x30, 0xa2, 0x02, 0xb0, 0x04, 0x85, 0x6d, 0xc0, 0xa6, 0x0c, 0x36, 0x30, 0xae, 0x6b, 0x04,
0xb6, 0xfc, 0x00, 0x05, 0x2e, 0xa6, 0xd6, 0xba, 0x71, 0x41, 0x84, 0xfc, 0x2a, 0x9f, 0x97, 0x1c, 0xd7, 0xea, 0xb6, 0x83, 0x1c, 0x03, 0xbb, 0xda, 0xba, 0xd2, 0xcf, 0x28, 0xbf, 0x48, 0xd7, 0x25,
0x5d, 0xce, 0x41, 0x1e, 0xee, 0x25, 0xd1, 0x4a, 0x19, 0x90, 0x8f, 0x46, 0xd7, 0xe5, 0x50, 0x27, 0x45, 0x97, 0x12, 0x90, 0xd2, 0xbd, 0xc4, 0x7a, 0xc9, 0x02, 0x7c, 0x69, 0x74, 0x83, 0xa7, 0x3a,
0xae, 0xc3, 0x8a, 0x17, 0xb0, 0xa3, 0xf7, 0xdb, 0xc8, 0x5e, 0xc7, 0x96, 0xbb, 0x46, 0xfc, 0x00, 0x7a, 0x03, 0xe6, 0xac, 0x80, 0x1d, 0xb9, 0x5b, 0x47, 0xfa, 0x3a, 0xd6, 0x8c, 0x35, 0xcb, 0x76,
0x3b, 0x56, 0xc3, 0xf5, 0x30, 0x35, 0x2e, 0x8a, 0x10, 0xe7, 0xf8, 0x06, 0x23, 0xe0, 0xb9, 0x18, 0x70, 0x45, 0xab, 0x1a, 0x26, 0x76, 0x95, 0x8b, 0x8c, 0xe2, 0x0c, 0x3d, 0x60, 0x18, 0x3c, 0x13,
0x9d, 0xe5, 0x60, 0xd6, 0xd1, 0x15, 0xa4, 0xb2, 0x24, 0xb2, 0xa9, 0x0e, 0xab, 0x6e, 0xc0, 0xb7, 0xa0, 0xd3, 0x14, 0x8c, 0x07, 0x3a, 0x87, 0xe4, 0xb6, 0x44, 0xbc, 0xd4, 0x61, 0xde, 0x0c, 0xf8,
0x35, 0xfd, 0x7c, 0x2b, 0xf0, 0xd7, 0xf8, 0xd9, 0xc2, 0x0a, 0x5b, 0x0e, 0x62, 0x58, 0xae, 0xd7, 0xbe, 0x24, 0x5f, 0xa8, 0x3b, 0xf6, 0x1a, 0xad, 0x2d, 0x34, 0xaf, 0x5e, 0x41, 0x04, 0xf3, 0xf9,
0x9f, 0x10, 0xb1, 0x2f, 0xf3, 0x72, 0x33, 0xd5, 0x5a, 0x11, 0x4a, 0x72, 0x6d, 0x1e, 0x9f, 0x79, 0xfa, 0xa3, 0x8c, 0xfb, 0x12, 0x4d, 0x37, 0x23, 0xad, 0x65, 0xa6, 0xc4, 0xe7, 0xe6, 0x41, 0xcd,
0xbb, 0xe0, 0x12, 0x9d, 0x17, 0xa5, 0x8e, 0xd0, 0x5e, 0x84, 0xdd, 0x3c, 0x82, 0x77, 0x34, 0x7d, 0x5b, 0x80, 0x73, 0xee, 0xdc, 0xe4, 0x06, 0x42, 0xba, 0x09, 0x8b, 0x2c, 0x82, 0xb7, 0x24, 0xb9,
0xd0, 0x73, 0x9b, 0x2e, 0xb3, 0x56, 0x11, 0x71, 0xb6, 0x5c, 0x87, 0xad, 0x5b, 0x2e, 0xb1, 0x3c, 0xd7, 0x34, 0x6a, 0x06, 0xd1, 0x56, 0x91, 0x55, 0xd9, 0x32, 0x2a, 0x64, 0x5d, 0x33, 0x2c, 0xcd,
0x44, 0x8c, 0x61, 0xd1, 0x25, 0x0b, 0xe2, 0x2c, 0xc7, 0x35, 0xa6, 0x52, 0x85, 0x39, 0x32, 0x8f, 0x44, 0x96, 0x32, 0xc0, 0x86, 0x64, 0x8e, 0xd5, 0x72, 0x54, 0x63, 0x22, 0x52, 0x98, 0xb1, 0x66,
0x48, 0x7e, 0xfe, 0xae, 0x62, 0xf7, 0xe9, 0x16, 0x95, 0x2b, 0xf0, 0xb6, 0xa6, 0x83, 0xa6, 0x4b, 0x91, 0x95, 0xd4, 0xdf, 0x79, 0xec, 0x80, 0x61, 0x11, 0x99, 0x02, 0x6f, 0x4a, 0x32, 0xa8, 0x19,
0xac, 0x75, 0xbf, 0x89, 0x2d, 0xc7, 0xa5, 0x1b, 0x56, 0x23, 0xc0, 0xd8, 0x30, 0x47, 0xb4, 0xd1, 0x96, 0xb6, 0x6e, 0xd7, 0xb0, 0x56, 0x31, 0xdc, 0x0d, 0xad, 0xea, 0x60, 0xac, 0xa8, 0x83, 0xd2,
0x53, 0x13, 0x3d, 0x57, 0xe2, 0x8b, 0xae, 0x2b, 0x4b, 0xee, 0x9b, 0x78, 0xea, 0x95, 0x8f, 0x23, 0xd0, 0xa9, 0xd1, 0x8e, 0xab, 0xc1, 0x45, 0xd7, 0xd5, 0x45, 0xe3, 0x75, 0x3c, 0xf1, 0xc2, 0x27,
0xf3, 0x08, 0x5f, 0xd5, 0x4d, 0x97, 0xbc, 0xea, 0x37, 0xf1, 0x8c, 0x4b, 0x37, 0x66, 0x03, 0x8c, 0xbe, 0x7a, 0x84, 0xee, 0xea, 0x9a, 0x61, 0xbd, 0x68, 0xd7, 0xf0, 0x94, 0xe1, 0x6e, 0x4c, 0x3b,
0xb3, 0xd9, 0x51, 0x92, 0xcb, 0xeb, 0x60, 0xe4, 0x32, 0x27, 0x72, 0x6c, 0x7c, 0xe4, 0x32, 0x2c, 0x18, 0xc7, 0xab, 0x23, 0x23, 0xe7, 0xf7, 0xc1, 0xe0, 0x65, 0xea, 0xc8, 0xb1, 0x91, 0xc1, 0xcb,
0x9b, 0x83, 0x7b, 0x9a, 0xde, 0x93, 0xce, 0x77, 0xb1, 0x0b, 0x8c, 0x88, 0x5d, 0xe0, 0x0f, 0xa2, 0x30, 0xdb, 0x1c, 0xdc, 0x97, 0xe4, 0x8e, 0x68, 0xbd, 0xb3, 0x53, 0x60, 0x90, 0x9d, 0x02, 0x7f,
0x02, 0x49, 0x27, 0x6d, 0xbc, 0x17, 0x9c, 0x0a, 0xf2, 0xcf, 0x4e, 0x64, 0xce, 0xa4, 0x07, 0x80, 0x66, 0x19, 0x48, 0xb4, 0x68, 0x83, 0xb3, 0xe0, 0x94, 0x93, 0x7c, 0xb6, 0x7d, 0x75, 0x2a, 0x2a,
0x54, 0xa6, 0xd8, 0x17, 0x92, 0x15, 0x40, 0x4b, 0x29, 0xbe, 0x89, 0x19, 0xba, 0xf2, 0x45, 0xea, 0x00, 0x22, 0x99, 0xe0, 0x5c, 0x08, 0x77, 0x80, 0x9b, 0x09, 0xf1, 0x35, 0x4c, 0xd0, 0xd5, 0xd7,
0x13, 0x9e, 0x4a, 0x0b, 0x6e, 0x8b, 0x9f, 0x87, 0x7b, 0xf5, 0xd1, 0x87, 0x75, 0xc5, 0xcb, 0x15, 0x5c, 0xdb, 0xa2, 0xa1, 0x34, 0x65, 0x36, 0xfd, 0xb9, 0xbf, 0x5b, 0x1e, 0x7a, 0x50, 0x53, 0x34,
0x89, 0x2f, 0xcc, 0xfd, 0x04, 0x1e, 0xf8, 0x7f, 0xbd, 0x0f, 0x79, 0x5b, 0xfc, 0x30, 0x14, 0x1f, 0x5d, 0xe1, 0xfc, 0x85, 0x89, 0x1d, 0xc7, 0x04, 0x2b, 0x72, 0x17, 0x32, 0xb7, 0x68, 0x31, 0x14,
0xee, 0x09, 0x66, 0xd4, 0x78, 0x52, 0xdc, 0xa9, 0xf1, 0x33, 0xe8, 0x99, 0x18, 0x14, 0x87, 0xe4, 0x14, 0xf7, 0x16, 0x26, 0xae, 0xf2, 0x18, 0xbb, 0x53, 0xa3, 0x35, 0xe8, 0x99, 0x00, 0x64, 0x45,
0x3b, 0x98, 0xf1, 0x89, 0x3f, 0x10, 0x67, 0x98, 0x82, 0xbc, 0x06, 0xcb, 0x8a, 0xe0, 0xdf, 0x9a, 0xf2, 0x3c, 0x26, 0x74, 0xe1, 0xf7, 0x04, 0x11, 0x26, 0x25, 0x2f, 0xc1, 0xac, 0x22, 0xf8, 0x9f,
0x3e, 0xea, 0x6f, 0xe2, 0x60, 0x2b, 0x70, 0x19, 0x4f, 0x1c, 0x4d, 0x9f, 0x61, 0xcb, 0xc1, 0x9b, 0x24, 0x0f, 0xd9, 0x9b, 0xd8, 0xd9, 0x72, 0x0c, 0x42, 0x03, 0x47, 0xcd, 0x26, 0x58, 0xab, 0xe0,
0xae, 0x8d, 0x2d, 0x82, 0x9a, 0x98, 0x5a, 0x3e, 0xb1, 0x92, 0x73, 0x89, 0x51, 0xcb, 0x6f, 0x7b, 0x4d, 0x43, 0xc7, 0x9a, 0x85, 0x6a, 0xd8, 0xd5, 0x6c, 0x4b, 0x0b, 0xeb, 0x12, 0xa5, 0x94, 0xdc,
0x86, 0xee, 0xa6, 0x46, 0x50, 0xd8, 0xcc, 0xe0, 0xcd, 0x3b, 0x5c, 0xbd, 0x1d, 0x99, 0x97, 0xfc, 0xf6, 0xf4, 0xdd, 0x8d, 0x1a, 0x41, 0xd6, 0x66, 0x0a, 0x6f, 0xce, 0x53, 0xf5, 0x96, 0xaf, 0x5e,
0x0a, 0xe4, 0xda, 0x58, 0xa0, 0x77, 0xc9, 0x74, 0xec, 0xaa, 0x13, 0x99, 0x2f, 0x09, 0x82, 0x0f, 0xb2, 0x73, 0x90, 0xa1, 0x63, 0x86, 0xde, 0xb5, 0x26, 0x03, 0x53, 0x6d, 0x5f, 0x7d, 0x8e, 0x39,
0xa1, 0xdb, 0x7d, 0x52, 0xf2, 0x43, 0x55, 0x17, 0x1e, 0xf0, 0x61, 0x58, 0x80, 0xaf, 0xe8, 0xe7, 0xf8, 0x00, 0xba, 0xc5, 0x8b, 0x92, 0x16, 0x55, 0x05, 0x7e, 0xc0, 0x07, 0xf1, 0x02, 0x7c, 0x53,
0x78, 0x1a, 0xb3, 0x5c, 0xe2, 0xe0, 0x6d, 0x8b, 0xcf, 0xe4, 0x55, 0xcf, 0xb7, 0x37, 0xa8, 0x71, 0x3e, 0x47, 0xc3, 0x98, 0x66, 0x58, 0x15, 0xbc, 0xad, 0xd1, 0x95, 0xbc, 0x6a, 0xda, 0xfa, 0x86,
0x49, 0x2c, 0x69, 0x3e, 0x69, 0x00, 0x57, 0x98, 0xe3, 0xf8, 0x82, 0x4b, 0xa6, 0x04, 0x9a, 0x5d, 0xab, 0x5c, 0x62, 0x5b, 0x9a, 0x2e, 0x1a, 0x40, 0x15, 0x66, 0x28, 0x3e, 0x67, 0x58, 0x13, 0x0c,
0xa2, 0x56, 0x21, 0x65, 0xe1, 0x1a, 0x97, 0xa3, 0x50, 0xe1, 0x09, 0xfc, 0x8d, 0x57, 0x9f, 0x04, 0x8d, 0x2f, 0x51, 0xf3, 0x90, 0x30, 0x71, 0x0d, 0xd2, 0x51, 0x28, 0xb0, 0x04, 0xfe, 0x45, 0xb3,
0xd9, 0x1b, 0xd8, 0xb1, 0x88, 0xcf, 0xdc, 0x86, 0x6b, 0xa3, 0xf8, 0x3a, 0xc0, 0xa1, 0x46, 0x5d, 0x4f, 0x0b, 0xe9, 0x1b, 0xb8, 0xa2, 0x59, 0x36, 0x31, 0xaa, 0x86, 0x8e, 0x82, 0xeb, 0x80, 0x8a,
0x8c, 0xef, 0x7b, 0xbc, 0xbb, 0x07, 0x57, 0x62, 0xa5, 0x3b, 0x92, 0xce, 0xdc, 0x0c, 0xef, 0xed, 0xab, 0x94, 0xd9, 0xfc, 0xbe, 0x4f, 0x87, 0xbb, 0x77, 0x39, 0x50, 0x9a, 0xe7, 0x74, 0x66, 0xa6,
0xc1, 0x50, 0x89, 0x74, 0x22, 0xf3, 0x42, 0x9c, 0xda, 0x55, 0xb0, 0xb8, 0x3a, 0x54, 0x22, 0x9d, 0xe8, 0x68, 0xf7, 0x7a, 0x42, 0xa4, 0xed, 0xab, 0xfd, 0x41, 0x68, 0x17, 0xc1, 0xec, 0xea, 0x50,
0xbd, 0x7a, 0x17, 0x8f, 0xbb, 0xfb, 0xf5, 0x2e, 0x2c, 0xa0, 0xd2, 0xc2, 0xa1, 0x00, 0xea, 0xa7, 0x88, 0xb4, 0x77, 0xcb, 0x05, 0x16, 0x1b, 0xcd, 0x72, 0x81, 0x17, 0x50, 0xd8, 0xa2, 0xe2, 0x02,
0x59, 0x80, 0x1a, 0x0d, 0xd7, 0xb6, 0x6c, 0x0f, 0x51, 0x6a, 0x5c, 0x16, 0xdd, 0xfa, 0x02, 0x3f, 0x28, 0x9f, 0x26, 0x0e, 0xaa, 0x56, 0x0d, 0x5d, 0xd3, 0x4d, 0xe4, 0xba, 0xca, 0x65, 0x36, 0xac,
0xbe, 0x26, 0xc0, 0x34, 0x97, 0x77, 0x22, 0x13, 0xc4, 0x1d, 0x2a, 0x09, 0xb3, 0x7b, 0x93, 0x82, 0xcf, 0xd0, 0xf2, 0x35, 0x04, 0x26, 0xa9, 0xbc, 0xed, 0xab, 0x20, 0x18, 0x50, 0x4e, 0x18, 0xdf,
0x2a, 0x78, 0x4b, 0xef, 0x4f, 0xba, 0xd8, 0x6a, 0xf8, 0x9e, 0x83, 0x03, 0xab, 0x85, 0xd8, 0xba, 0x9b, 0xa4, 0x54, 0xc1, 0x1b, 0x72, 0x77, 0x38, 0xc4, 0x5a, 0xd5, 0x36, 0x2b, 0xd8, 0xd1, 0xea,
0xf1, 0x94, 0x58, 0xf5, 0xb7, 0x0f, 0x22, 0xf3, 0xc2, 0x0c, 0x6e, 0x05, 0xd8, 0x46, 0x0c, 0x3b, 0x88, 0xac, 0x2b, 0x8f, 0xb3, 0x5d, 0x7f, 0x67, 0xcf, 0x57, 0xfb, 0xa7, 0x70, 0xdd, 0xc1, 0x3a,
0x33, 0xb1, 0xe2, 0xac, 0xd0, 0x5b, 0x44, 0x6c, 0xbd, 0x1d, 0x99, 0xda, 0x0b, 0xd9, 0x61, 0xd9, 0x22, 0xb8, 0x32, 0x15, 0x28, 0x4e, 0x33, 0xbd, 0x05, 0x44, 0xd6, 0x5b, 0xbe, 0x2a, 0x3d, 0x13,
0x29, 0xc3, 0xcf, 0xfb, 0x4d, 0x97, 0x0f, 0x12, 0xdb, 0xa9, 0x19, 0x1a, 0xec, 0xab, 0xe0, 0x60, 0x17, 0xcb, 0x95, 0x2c, 0x7c, 0xc5, 0xae, 0x19, 0x74, 0x92, 0xc8, 0x4e, 0x49, 0x91, 0x60, 0x57,
0x43, 0x3f, 0x4b, 0x31, 0xb3, 0x3c, 0x7f, 0xcb, 0x6a, 0x05, 0xae, 0x1f, 0xb8, 0x6c, 0xc7, 0x78, 0x0e, 0x07, 0x1b, 0xf2, 0x59, 0x17, 0x13, 0xcd, 0xb4, 0xb7, 0xb4, 0xba, 0x63, 0xd8, 0x8e, 0x41,
0x5a, 0x2c, 0x8a, 0xc9, 0x76, 0x64, 0xf6, 0x52, 0xcc, 0xe6, 0xfd, 0xad, 0xc5, 0x04, 0xc9, 0x32, 0x76, 0x94, 0x27, 0xd8, 0xa6, 0x18, 0x6f, 0xf9, 0x6a, 0xa7, 0x8b, 0xc9, 0xac, 0xbd, 0xb5, 0x10,
0x5b, 0x51, 0xdc, 0xf5, 0x58, 0x5e, 0x32, 0x07, 0xef, 0x6b, 0xfa, 0x60, 0x13, 0x6d, 0xa7, 0x61, 0x22, 0x71, 0x64, 0x4b, 0x8b, 0x0b, 0xcb, 0xf2, 0x4c, 0x73, 0xf0, 0x81, 0x24, 0xf7, 0xd6, 0xd0,
0xda, 0x3e, 0xb1, 0xc3, 0x20, 0xc0, 0xc4, 0xde, 0x31, 0x46, 0x45, 0x3f, 0x52, 0x71, 0xf7, 0x81, 0x76, 0x44, 0x53, 0xb7, 0x2d, 0xdd, 0x73, 0x1c, 0x6c, 0xe9, 0x3b, 0xca, 0x10, 0x1b, 0x47, 0x97,
0xb6, 0x16, 0xd0, 0x76, 0xcc, 0x71, 0x3a, 0x57, 0xe1, 0x5b, 0x7e, 0x53, 0x21, 0xcf, 0xb6, 0x7c, 0xdd, 0x7d, 0xa0, 0xad, 0x39, 0xb4, 0x1d, 0xf8, 0x38, 0x99, 0xa8, 0xd0, 0x23, 0xbf, 0x26, 0x90,
0x15, 0x98, 0x76, 0xb9, 0xb8, 0xac, 0x50, 0xfb, 0x85, 0x4a, 0xaf, 0xe0, 0x13, 0x4d, 0xef, 0xb7, 0xc7, 0x47, 0xbe, 0x08, 0x8c, 0x86, 0x9c, 0x5d, 0x56, 0x88, 0xed, 0x42, 0xa1, 0x55, 0xf0, 0xa9,
0x03, 0x44, 0xd7, 0x4b, 0x25, 0xf9, 0x33, 0x62, 0x58, 0x3e, 0x10, 0x25, 0xf9, 0x74, 0x5a, 0x92, 0x24, 0x77, 0xeb, 0x0e, 0x72, 0xd7, 0x33, 0x29, 0xf9, 0x93, 0x6c, 0x5a, 0x3e, 0x64, 0x29, 0xf9,
0xdb, 0x49, 0x49, 0x3e, 0x1b, 0xef, 0xcd, 0xdc, 0x2c, 0x2f, 0x8e, 0x95, 0x69, 0x58, 0xe8, 0x54, 0x64, 0x94, 0x92, 0xeb, 0x61, 0x4a, 0x3e, 0x1d, 0x9c, 0xcd, 0xb4, 0x59, 0x92, 0x1c, 0x0b, 0xc3,
0xcb, 0x6c, 0x21, 0xe6, 0x73, 0xb9, 0xaf, 0xe2, 0x84, 0x17, 0xeb, 0x76, 0x52, 0xac, 0xd7, 0x1f, 0x30, 0xd3, 0xc9, 0xa7, 0xd9, 0x4c, 0x4c, 0xd7, 0x72, 0x57, 0xce, 0x08, 0x4d, 0xd6, 0xf5, 0x30,
0xc6, 0x0d, 0x2f, 0xd7, 0xa7, 0xe3, 0x72, 0xbd, 0xe4, 0x2c, 0xf0, 0xc0, 0x8f, 0x35, 0x7d, 0xa8, 0x59, 0x2f, 0x3f, 0x88, 0x19, 0x9a, 0xae, 0x4f, 0x06, 0xe9, 0x7a, 0xc6, 0x98, 0x63, 0x82, 0x9f,
0x1c, 0x5e, 0x7a, 0x4b, 0xf2, 0xac, 0x18, 0x7f, 0xf7, 0x20, 0x32, 0x4f, 0x4e, 0x43, 0xe9, 0x82, 0x4a, 0x72, 0x5f, 0x96, 0x5e, 0x74, 0x4b, 0xf2, 0x14, 0x9b, 0x7f, 0x63, 0xcf, 0x57, 0x4f, 0x4e,
0xbf, 0xe8, 0xa5, 0x7c, 0xc1, 0xaf, 0x44, 0xbb, 0x4d, 0x8d, 0xdd, 0xfd, 0x7a, 0xee, 0x1b, 0xaa, 0x42, 0xee, 0x82, 0x3f, 0x6d, 0x25, 0x7b, 0xc1, 0x2f, 0x44, 0x8b, 0x96, 0x46, 0xa3, 0x59, 0x4e,
0x3d, 0x83, 0xaf, 0x69, 0xfa, 0x20, 0x65, 0x21, 0xb1, 0x78, 0xe5, 0x84, 0x3c, 0x77, 0x13, 0x5b, 0x6c, 0x43, 0xb1, 0x65, 0xf0, 0x6d, 0x49, 0xee, 0x75, 0x89, 0x67, 0x69, 0x34, 0x73, 0x42, 0xa6,
0xf1, 0xdd, 0x11, 0x35, 0x9e, 0xcb, 0xea, 0xd1, 0x7e, 0xae, 0x71, 0x3b, 0x55, 0x58, 0xe2, 0xf8, 0xb1, 0x89, 0xb5, 0xe0, 0xee, 0xc8, 0x55, 0x9e, 0x8e, 0xf3, 0xd1, 0x6e, 0xaa, 0x71, 0x27, 0x52,
0x52, 0x56, 0x25, 0x29, 0xb0, 0x62, 0x6d, 0x2d, 0x25, 0xb4, 0x63, 0xe3, 0x37, 0xc7, 0xa0, 0xca, 0x58, 0xa4, 0xf8, 0x62, 0x9c, 0x25, 0x09, 0xb0, 0x74, 0x6e, 0xcd, 0x05, 0xb4, 0x63, 0x23, 0xb7,
0x1b, 0x3f, 0xb2, 0x96, 0x68, 0xf0, 0xbc, 0x4a, 0x8d, 0xe7, 0x05, 0x89, 0xd7, 0x78, 0xa1, 0x56, 0x87, 0xa1, 0xc8, 0x1a, 0x2d, 0x59, 0x33, 0x6e, 0xd0, 0xb8, 0xea, 0x2a, 0x57, 0x98, 0x13, 0x2f,
0x30, 0x5b, 0x70, 0x49, 0x5e, 0xda, 0x57, 0x10, 0xb9, 0x46, 0x2c, 0x24, 0xd4, 0x89, 0x31, 0x58, 0xd1, 0x44, 0x2d, 0xd5, 0x6c, 0xce, 0xb0, 0x92, 0xd4, 0x3e, 0x87, 0xf0, 0x39, 0x62, 0x2a, 0xa0,
0xf5, 0xc3, 0xab, 0xf2, 0x1e, 0xd1, 0x7a, 0xfa, 0xee, 0xf4, 0x82, 0xc8, 0xa1, 0xce, 0x41, 0x64, 0x8e, 0x0e, 0xc3, 0xbc, 0x1d, 0x9a, 0x95, 0x77, 0xb0, 0xde, 0xa3, 0x77, 0xa7, 0x67, 0x58, 0x0c,
0xf6, 0x42, 0xb4, 0xb5, 0xc4, 0x42, 0xe9, 0xc5, 0xe9, 0x14, 0xcd, 0x3f, 0xb3, 0xbb, 0xa1, 0x5c, 0xad, 0xec, 0xf9, 0x6a, 0x27, 0x44, 0x5b, 0x8b, 0xc4, 0xe3, 0x5e, 0x9c, 0x4e, 0xb9, 0xc9, 0x67,
0xf6, 0xc0, 0x57, 0xb1, 0x92, 0x47, 0x28, 0xfb, 0x03, 0x9b, 0xfa, 0x19, 0x7e, 0x0a, 0x5c, 0x45, 0x7c, 0x37, 0x94, 0xc8, 0x0e, 0x7d, 0x15, 0xcb, 0x58, 0x84, 0xbc, 0x3d, 0xb0, 0x29, 0x9f, 0xa1,
0x14, 0x5b, 0xf1, 0x13, 0xa0, 0x71, 0x65, 0x44, 0x1b, 0xed, 0x9d, 0xe8, 0x4d, 0xcb, 0xa2, 0x65, 0x55, 0xe0, 0x2a, 0x72, 0xb1, 0x16, 0x3c, 0x01, 0x2a, 0x57, 0x07, 0xa5, 0xa1, 0xce, 0xd1, 0xce,
0x21, 0x15, 0x97, 0x79, 0xbd, 0xa9, 0x6a, 0x2c, 0xcb, 0x32, 0x47, 0x51, 0x5c, 0x1b, 0x09, 0xb0, 0x28, 0x2d, 0x5a, 0x62, 0x52, 0x76, 0x99, 0xd7, 0x19, 0xa9, 0x06, 0xb2, 0x38, 0x72, 0xa4, 0xc5,
0x18, 0xd2, 0x64, 0x7a, 0xbc, 0xbd, 0x5f, 0xd7, 0x60, 0xc9, 0x14, 0x7c, 0xe7, 0xa8, 0x7e, 0x89, 0xa5, 0x41, 0x07, 0xb3, 0x29, 0x0d, 0x97, 0xc7, 0x9b, 0xcd, 0xb2, 0x04, 0x33, 0x4d, 0xc1, 0xbb,
0x67, 0x8d, 0x2c, 0x5d, 0xf0, 0x33, 0xa5, 0xed, 0x37, 0xf9, 0x94, 0x0d, 0xf0, 0x1b, 0x21, 0xa6, 0x47, 0xe5, 0x4b, 0x34, 0x6a, 0xc4, 0xe1, 0x82, 0xd6, 0x94, 0xba, 0x5d, 0xa3, 0x4b, 0xd6, 0xc1,
0xcc, 0xda, 0x70, 0x57, 0x8d, 0xab, 0x62, 0x38, 0xfe, 0xa4, 0x25, 0x4f, 0x87, 0x0b, 0x68, 0x7b, 0xf7, 0x3c, 0xec, 0x12, 0x6d, 0xc3, 0x58, 0x55, 0xae, 0xb1, 0xe9, 0xf8, 0xab, 0x14, 0x3e, 0x1d,
0x7a, 0x0e, 0xc6, 0xf8, 0x6d, 0x77, 0xaa, 0x1d, 0x99, 0x66, 0x13, 0x6d, 0x67, 0x4b, 0x9c, 0xcd, 0xce, 0xa1, 0xed, 0xc9, 0x19, 0x18, 0xe0, 0x77, 0x8c, 0x89, 0x96, 0xaf, 0xaa, 0x35, 0xb4, 0x1d,
0x25, 0x3e, 0x72, 0x95, 0x6c, 0x17, 0x7c, 0x80, 0x9e, 0x74, 0x1e, 0x7b, 0xa0, 0xcb, 0x07, 0xab, 0x6f, 0x71, 0x32, 0x13, 0xda, 0x48, 0x54, 0xe2, 0x53, 0xf0, 0x10, 0x3d, 0xae, 0x1e, 0x3b, 0xd4,
0x24, 0x8f, 0x91, 0x25, 0xba, 0xf0, 0x01, 0x66, 0xab, 0xe0, 0x33, 0x4d, 0x1f, 0xcc, 0x5e, 0x44, 0xe4, 0xe1, 0x2a, 0xe1, 0x63, 0x64, 0xc6, 0x5d, 0x78, 0x48, 0xb3, 0x55, 0xf0, 0xb9, 0x24, 0xf7,
0x3c, 0x24, 0xbf, 0xa1, 0x8e, 0x89, 0x05, 0xfc, 0x21, 0xef, 0x89, 0x81, 0xf4, 0x45, 0x61, 0x7e, 0xc6, 0x2f, 0x22, 0x26, 0xe2, 0xdf, 0x50, 0x87, 0xd9, 0x06, 0xfe, 0x88, 0x8e, 0x44, 0x4f, 0xf4,
0xf2, 0x8e, 0xfc, 0x8c, 0x3a, 0x80, 0x14, 0xf2, 0xac, 0x90, 0x56, 0x81, 0xaa, 0x87, 0x2c, 0xa5, 0xa2, 0x30, 0x3b, 0x3e, 0xcf, 0x3f, 0xa3, 0xf6, 0x20, 0x81, 0x3c, 0x4e, 0xa4, 0x45, 0xa0, 0xe8,
0x93, 0x2e, 0x72, 0x69, 0xe9, 0x2b, 0x49, 0xc1, 0xdc, 0x0a, 0x49, 0x6f, 0xb0, 0x9b, 0xfa, 0x79, 0x21, 0x4b, 0x68, 0xa4, 0x40, 0xce, 0x6d, 0x7d, 0xa1, 0x53, 0x30, 0x69, 0x85, 0xb8, 0x37, 0xd8,
0xf1, 0xe8, 0xd1, 0x08, 0x3d, 0x2f, 0xa9, 0x6a, 0x7c, 0x92, 0x1e, 0x51, 0x8d, 0x71, 0x11, 0xe9, 0x4d, 0xf9, 0x02, 0x7b, 0xf4, 0xa8, 0x7a, 0xa6, 0x19, 0x66, 0x35, 0xb6, 0x15, 0x95, 0xa8, 0xca,
0x2d, 0x5e, 0x35, 0x70, 0xad, 0xd9, 0xd0, 0xf3, 0x44, 0x3d, 0x72, 0x97, 0x24, 0x87, 0xca, 0x4e, 0x08, 0x63, 0x3a, 0x46, 0xb3, 0x06, 0xaa, 0x35, 0xed, 0x99, 0x26, 0xcb, 0x47, 0xee, 0x5a, 0x61,
0x64, 0x5e, 0x4c, 0xb6, 0x2c, 0x15, 0x5c, 0x83, 0x5d, 0xec, 0xc0, 0x6b, 0xfa, 0xe9, 0x06, 0x46, 0x51, 0xd9, 0xf6, 0xd5, 0x8b, 0xe1, 0x91, 0x25, 0x82, 0x4b, 0xb0, 0xa0, 0x1d, 0x78, 0x49, 0x3e,
0x2c, 0x0c, 0xb0, 0xd5, 0xf0, 0xd0, 0x1a, 0x35, 0x26, 0xc4, 0xba, 0xbb, 0xcc, 0x77, 0xfa, 0x04, 0x5d, 0xc5, 0x88, 0x78, 0x0e, 0xd6, 0xaa, 0x26, 0x5a, 0x73, 0x95, 0x51, 0xb6, 0xef, 0x2e, 0xd3,
0x98, 0xe5, 0xf2, 0xec, 0x81, 0x44, 0x12, 0xd6, 0x60, 0x41, 0x05, 0x6c, 0xe9, 0x43, 0xd2, 0xbb, 0x93, 0x3e, 0x04, 0xa6, 0xa9, 0x3c, 0x7e, 0x20, 0xe1, 0x84, 0x25, 0x98, 0x52, 0x01, 0x5b, 0x72,
0x48, 0x7c, 0xc6, 0xc1, 0xc4, 0x0f, 0xd7, 0xd6, 0x8d, 0x6b, 0x62, 0xd2, 0xbe, 0x2c, 0xd2, 0x6b, 0x1f, 0xf7, 0x2e, 0x12, 0xd4, 0x38, 0xd8, 0xb2, 0xbd, 0xb5, 0x75, 0xe5, 0x3a, 0x5b, 0xb4, 0xcf,
0xa6, 0x32, 0xcf, 0x35, 0x5e, 0x11, 0x0a, 0x59, 0xd5, 0xa3, 0x44, 0xb3, 0x8a, 0x42, 0x6d, 0x0c, 0xb3, 0xf0, 0x1a, 0xab, 0xcc, 0x52, 0x8d, 0x17, 0x98, 0x42, 0x9c, 0xf5, 0x08, 0xd1, 0x38, 0xa3,
0x36, 0xf4, 0x81, 0x4a, 0xc3, 0x4d, 0xb4, 0x6d, 0x5c, 0x17, 0xad, 0xbe, 0xc4, 0x8b, 0xc1, 0x92, 0x10, 0x37, 0x06, 0x1b, 0x72, 0x4f, 0xae, 0xe3, 0x1a, 0xda, 0x56, 0x6e, 0xb0, 0x5e, 0x9f, 0xa3,
0xe1, 0x02, 0xda, 0xee, 0x44, 0xa6, 0xa1, 0x6a, 0x72, 0x01, 0x6d, 0x67, 0xed, 0x29, 0xcc, 0xc0, 0xc9, 0x60, 0xa6, 0xe1, 0x1c, 0xda, 0x6e, 0xfb, 0xaa, 0x22, 0xea, 0x72, 0x0e, 0x6d, 0xc7, 0xfd,
0xbb, 0x47, 0x75, 0x33, 0xbd, 0xec, 0xb1, 0x90, 0xc7, 0x4b, 0x0a, 0xdf, 0x73, 0x2c, 0xe6, 0x51, 0x09, 0x9a, 0x81, 0xb7, 0x8f, 0xca, 0x6a, 0x74, 0xd9, 0xa3, 0x21, 0x93, 0xa6, 0x14, 0xb6, 0x59,
0x8b, 0xe7, 0x0f, 0xd7, 0x27, 0xd4, 0x78, 0x51, 0x8c, 0xd7, 0x47, 0x7c, 0x66, 0x5e, 0x48, 0xaf, 0xd1, 0x88, 0xe9, 0x6a, 0x34, 0x7e, 0x18, 0xb6, 0xe5, 0x2a, 0x37, 0xd9, 0x7c, 0x7d, 0x4c, 0x57,
0x56, 0x26, 0xb9, 0xea, 0x5d, 0xcf, 0x59, 0x9e, 0x5f, 0xfa, 0xbf, 0x44, 0xaf, 0x1d, 0x99, 0x17, 0x66, 0x7f, 0x74, 0xb5, 0x32, 0x4e, 0x55, 0xef, 0x9a, 0x95, 0xa5, 0xd9, 0xc5, 0x57, 0x42, 0xbd,
0xdc, 0xee, 0x70, 0x56, 0xef, 0xdc, 0x47, 0x87, 0xcf, 0xcf, 0xfb, 0xfa, 0xb8, 0x3f, 0xbc, 0xbb, 0x96, 0xaf, 0xf6, 0x1b, 0xc5, 0x70, 0x9c, 0xef, 0x1c, 0xa0, 0x43, 0xd7, 0xe7, 0x81, 0x36, 0x0e,
0x5f, 0xbf, 0x1f, 0x41, 0x58, 0xb5, 0xf5, 0x68, 0x0a, 0x82, 0x2f, 0xe9, 0x3d, 0x61, 0x8b, 0xb4, 0x86, 0x1b, 0xcd, 0xf2, 0x41, 0x0e, 0xc2, 0x7c, 0x5b, 0xd3, 0x8d, 0x40, 0xd0, 0x94, 0xe4, 0x7e,
0xb2, 0x0d, 0xf5, 0xe7, 0xb3, 0x22, 0xec, 0xcf, 0x1d, 0x44, 0xe6, 0xb9, 0xbc, 0x96, 0x5b, 0x59, 0x6e, 0xdc, 0xa3, 0xc4, 0x4a, 0x23, 0x7a, 0x9d, 0x95, 0xb3, 0xb7, 0xd8, 0xf0, 0xbf, 0x43, 0x47,
0x24, 0x8b, 0xf9, 0xee, 0x2a, 0xaa, 0xb8, 0xa4, 0xc0, 0x6d, 0x91, 0x56, 0x02, 0x48, 0xf5, 0xdb, 0x41, 0x99, 0x8c, 0xf5, 0xa2, 0x34, 0x69, 0x69, 0x72, 0x61, 0x76, 0x7c, 0xbe, 0xe5, 0xab, 0x8a,
0xee, 0x7e, 0x5d, 0x6d, 0x6c, 0x68, 0xf0, 0x94, 0x64, 0x02, 0x7e, 0xaa, 0x25, 0xcd, 0xa7, 0xaf, 0x9e, 0xc7, 0xf4, 0x7a, 0x50, 0xf0, 0x3e, 0x9d, 0x99, 0xa1, 0xb4, 0xc2, 0x01, 0x49, 0x7b, 0xa3,
0x09, 0xef, 0xcf, 0x8a, 0xe1, 0x7e, 0x5b, 0xe4, 0x83, 0xa2, 0x8b, 0xec, 0x65, 0x41, 0x34, 0x3f, 0x59, 0x2e, 0xec, 0x13, 0x16, 0xf6, 0x08, 0xfe, 0x21, 0xc9, 0x17, 0x45, 0x94, 0xee, 0x79, 0x86,
0x92, 0x35, 0x2f, 0xbf, 0x08, 0x48, 0x1c, 0xf2, 0xc4, 0x77, 0xbe, 0xbb, 0x16, 0x5f, 0xe0, 0xaa, 0xce, 0x38, 0x3d, 0xcb, 0x38, 0xbd, 0x4b, 0x39, 0x9d, 0xcf, 0xdb, 0x7f, 0x79, 0x79, 0x66, 0x32,
0x56, 0x0c, 0x0d, 0xea, 0xb9, 0x15, 0xf8, 0xb5, 0xa6, 0xf7, 0x0a, 0x9a, 0xf9, 0xbb, 0xc1, 0x2f, 0x20, 0x75, 0x3e, 0xdf, 0xc5, 0xcb, 0x9e, 0xa1, 0x07, 0xac, 0xae, 0x14, 0xb0, 0x0a, 0x35, 0x0e,
0x62, 0xa2, 0xdf, 0x10, 0xe7, 0x83, 0xa2, 0x0b, 0xe9, 0x0d, 0x41, 0x50, 0xad, 0x65, 0x54, 0x8b, 0x38, 0x3a, 0x1b, 0xcd, 0x72, 0x71, 0xb7, 0xb0, 0xb8, 0xd3, 0x03, 0xe7, 0x6a, 0x0b, 0x59, 0xca,
0xb7, 0xfe, 0x4a, 0xb2, 0x17, 0xef, 0xa7, 0xc7, 0x4f, 0x01, 0xea, 0xb6, 0x0c, 0x0d, 0xf6, 0xc8, 0xed, 0xc3, 0xe6, 0x6a, 0xe5, 0x80, 0xb9, 0x5a, 0x39, 0x6c, 0xae, 0x56, 0x52, 0xa4, 0xae, 0xa7,
0x96, 0x39, 0xe5, 0xfc, 0x75, 0xe0, 0x83, 0xee, 0x94, 0xa5, 0x97, 0x82, 0x12, 0xe5, 0xe2, 0xdd, 0x48, 0x5d, 0x2f, 0x9e, 0xab, 0x95, 0xc2, 0xb9, 0x5a, 0x39, 0x6c, 0xae, 0x28, 0xa7, 0xe7, 0x0e,
0x7e, 0x77, 0xca, 0xdd, 0xf4, 0xaa, 0x94, 0x53, 0xcd, 0x94, 0x72, 0xf6, 0x18, 0xd0, 0xd0, 0xe3, 0x9d, 0xab, 0x95, 0x83, 0xe6, 0x6a, 0xe5, 0xd0, 0xb9, 0x4a, 0xd3, 0xba, 0x91, 0xa2, 0x75, 0xe3,
0x57, 0xc8, 0xac, 0x7c, 0xf8, 0xe5, 0xac, 0xc8, 0x63, 0xff, 0x53, 0xe4, 0x2b, 0x1e, 0xf2, 0xf2, 0x80, 0xb9, 0x5a, 0x29, 0x9e, 0x2b, 0x4a, 0xac, 0x21, 0xc9, 0xe7, 0x45, 0xc4, 0xd8, 0x6b, 0xa3,
0x3a, 0x42, 0x9a, 0x8c, 0x41, 0x8e, 0x14, 0x0f, 0x13, 0x3d, 0x12, 0x42, 0xc5, 0xe5, 0x4d, 0xf5, 0x32, 0xc6, 0x58, 0xbd, 0xd2, 0xf2, 0xd5, 0xbe, 0xbc, 0x09, 0xf6, 0x52, 0x99, 0xe4, 0xaa, 0x62,
0xde, 0xc4, 0x6a, 0xd9, 0xcc, 0xf8, 0x90, 0x77, 0x91, 0x36, 0xb5, 0x70, 0x10, 0x99, 0x17, 0xf3, 0x9c, 0xbf, 0xb4, 0x4a, 0xf9, 0x7c, 0x73, 0x18, 0x16, 0xd9, 0x04, 0x7f, 0x92, 0xe4, 0xcb, 0x22,
0x16, 0x17, 0x8a, 0xb7, 0x1e, 0x8b, 0x36, 0x2b, 0xf6, 0x53, 0xb3, 0x82, 0x17, 0x9b, 0x07, 0x55, 0xa7, 0xe2, 0x1b, 0xcc, 0x75, 0x07, 0xbb, 0xeb, 0xb6, 0x59, 0x51, 0xbe, 0xc0, 0x1c, 0x7c, 0xad,
0x05, 0x5e, 0x2b, 0x0d, 0x94, 0x2a, 0x05, 0x6a, 0x23, 0x42, 0x8d, 0x5f, 0xc5, 0xa3, 0xb4, 0x5c, 0xe5, 0xab, 0x02, 0x07, 0xc2, 0x73, 0x67, 0x29, 0xd2, 0x6e, 0xfb, 0xea, 0x8d, 0x02, 0x5f, 0xb3,
0xa2, 0x20, 0xef, 0xb0, 0x4b, 0x5c, 0xb1, 0x44, 0xa1, 0x82, 0x57, 0x87, 0x4a, 0x30, 0xa9, 0xe8, 0xaa, 0x9c, 0xdb, 0xbc, 0xd7, 0xd2, 0x30, 0x7c, 0x80, 0xc6, 0xe0, 0xeb, 0x72, 0x87, 0x57, 0xb7,
0x4d, 0xdd, 0xfe, 0xf8, 0xd3, 0xe1, 0x23, 0xfb, 0x9f, 0x0e, 0x1f, 0xf9, 0xf8, 0x60, 0x58, 0xdb, 0xea, 0x71, 0xf6, 0xff, 0xcb, 0x69, 0x16, 0xa3, 0xbf, 0xb2, 0xe7, 0xab, 0xe7, 0x92, 0xc2, 0x73,
0x3f, 0x18, 0xd6, 0xbe, 0x75, 0x6f, 0xf8, 0xc8, 0x7b, 0xf7, 0x86, 0xb5, 0xfd, 0x7b, 0xc3, 0x47, 0x79, 0xc1, 0x5a, 0x48, 0x4a, 0x01, 0x56, 0x72, 0x86, 0xd5, 0x78, 0xdd, 0xaa, 0x87, 0x00, 0x57,
0xfe, 0x7a, 0x6f, 0xf8, 0xc8, 0xeb, 0xcf, 0xac, 0xb9, 0x6c, 0x3d, 0x5c, 0xbd, 0x62, 0xfb, 0xcd, 0x6c, 0x36, 0x9a, 0x65, 0x71, 0x63, 0x45, 0x82, 0xa7, 0xb8, 0x26, 0xe0, 0xe7, 0x52, 0xd8, 0x7d,
0xab, 0x59, 0xfd, 0x2e, 0xfd, 0xca, 0xff, 0x56, 0xb5, 0x7a, 0x42, 0xfc, 0x8f, 0xea, 0xda, 0x7f, 0xf4, 0xf4, 0xf9, 0xc1, 0x34, 0x1b, 0xa5, 0x37, 0x59, 0xf2, 0x92, 0x36, 0x11, 0x3f, 0x83, 0xb2,
0x02, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x13, 0xeb, 0x90, 0xb3, 0x25, 0x00, 0x00, 0xee, 0x07, 0xe3, 0xee, 0xf9, 0xe7, 0x4b, 0xce, 0x87, 0x24, 0x4b, 0xbb, 0x50, 0xac, 0x45, 0xb3,
0x11, 0x51, 0x2f, 0x8a, 0x04, 0xe5, 0xa4, 0x15, 0xf8, 0xad, 0x24, 0x77, 0x32, 0x37, 0x93, 0x47,
0xce, 0x5f, 0x05, 0x8e, 0x7e, 0x97, 0x5d, 0x66, 0xa4, 0x4d, 0x70, 0x0f, 0x9e, 0xcc, 0xd5, 0x52,
0xec, 0x6a, 0xfa, 0x89, 0x52, 0xe8, 0xec, 0xc5, 0x83, 0xf4, 0x1a, 0xcd, 0x72, 0x41, 0x5f, 0x8a,
0x04, 0x3b, 0xf8, 0x96, 0x89, 0xcb, 0xc9, 0x53, 0xe6, 0x87, 0xc5, 0x2e, 0x73, 0xcf, 0x9a, 0x19,
0x97, 0xd3, 0x0f, 0x91, 0xc5, 0x2e, 0x17, 0xe9, 0xe5, 0x5d, 0x8e, 0x34, 0x23, 0x97, 0xe3, 0x97,
0xcb, 0xaa, 0x1c, 0xfc, 0x65, 0x22, 0xae, 0x75, 0x7e, 0x3d, 0xcd, 0x92, 0xae, 0x2f, 0xa5, 0xfd,
0x65, 0xfb, 0x2e, 0x29, 0x7a, 0xb8, 0xc5, 0xe8, 0x24, 0x48, 0xfa, 0xe6, 0xa3, 0x83, 0x43, 0x5c,
0x76, 0xd3, 0x9c, 0xbf, 0xe4, 0xd5, 0xea, 0x3a, 0x51, 0x3e, 0xa2, 0x43, 0x24, 0x4d, 0xcc, 0xed,
0xf9, 0xea, 0xc5, 0xa4, 0xc7, 0xb9, 0xf4, 0x15, 0xed, 0x82, 0x4e, 0xd2, 0xe3, 0x54, 0xcb, 0xe1,
0xe9, 0xee, 0x41, 0x5e, 0x81, 0x16, 0x76, 0x3d, 0x99, 0xb2, 0xc6, 0xd5, 0x91, 0xe5, 0x2a, 0xbf,
0x09, 0x66, 0x69, 0x29, 0xe3, 0x02, 0x5f, 0x0e, 0x2c, 0x52, 0xc5, 0x8c, 0x0b, 0x39, 0x3c, 0x3f,
0x55, 0xcc, 0x93, 0x9c, 0xde, 0xc4, 0x9d, 0x4f, 0x3e, 0x1b, 0x38, 0xd2, 0xfc, 0x6c, 0xe0, 0xc8,
0x27, 0x7b, 0x03, 0x52, 0x73, 0x6f, 0x40, 0x7a, 0xe7, 0xfe, 0xc0, 0x91, 0xf7, 0xef, 0x0f, 0x48,
0xcd, 0xfb, 0x03, 0x47, 0xfe, 0x79, 0x7f, 0xe0, 0xc8, 0xab, 0x4f, 0xae, 0x19, 0x64, 0xdd, 0x5b,
0xbd, 0xaa, 0xdb, 0xb5, 0x6b, 0xf1, 0x65, 0x03, 0xf7, 0x2b, 0xf9, 0x0f, 0xe8, 0xea, 0x09, 0xf6,
0xa7, 0xcf, 0xeb, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x24, 0x93, 0x46, 0x60, 0x2a, 0x00,
0x00,
} }
func (m *OptionsConfiguration) Marshal() (dAtA []byte, err error) { func (m *OptionsConfiguration) Marshal() (dAtA []byte, err error) {
@ -435,6 +458,48 @@ func (m *OptionsConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i-- i--
dAtA[i] = 0xc0 dAtA[i] = 0xc0
} }
if m.ConnectionPriorityUpgradeThreshold != 0 {
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(m.ConnectionPriorityUpgradeThreshold))
i--
dAtA[i] = 0x3
i--
dAtA[i] = 0xd8
}
if m.ConnectionPriorityRelay != 0 {
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(m.ConnectionPriorityRelay))
i--
dAtA[i] = 0x3
i--
dAtA[i] = 0xd0
}
if m.ConnectionPriorityQUICWAN != 0 {
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(m.ConnectionPriorityQUICWAN))
i--
dAtA[i] = 0x3
i--
dAtA[i] = 0xc8
}
if m.ConnectionPriorityTCPWAN != 0 {
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(m.ConnectionPriorityTCPWAN))
i--
dAtA[i] = 0x3
i--
dAtA[i] = 0xc0
}
if m.ConnectionPriorityQUICLAN != 0 {
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(m.ConnectionPriorityQUICLAN))
i--
dAtA[i] = 0x3
i--
dAtA[i] = 0xb8
}
if m.ConnectionPriorityTCPLAN != 0 {
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(m.ConnectionPriorityTCPLAN))
i--
dAtA[i] = 0x3
i--
dAtA[i] = 0xb0
}
if m.InsecureAllowOldTLSVersions { if m.InsecureAllowOldTLSVersions {
i-- i--
if m.InsecureAllowOldTLSVersions { if m.InsecureAllowOldTLSVersions {
@ -1076,6 +1141,24 @@ func (m *OptionsConfiguration) ProtoSize() (n int) {
if m.InsecureAllowOldTLSVersions { if m.InsecureAllowOldTLSVersions {
n += 3 n += 3
} }
if m.ConnectionPriorityTCPLAN != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.ConnectionPriorityTCPLAN))
}
if m.ConnectionPriorityQUICLAN != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.ConnectionPriorityQUICLAN))
}
if m.ConnectionPriorityTCPWAN != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.ConnectionPriorityTCPWAN))
}
if m.ConnectionPriorityQUICWAN != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.ConnectionPriorityQUICWAN))
}
if m.ConnectionPriorityRelay != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.ConnectionPriorityRelay))
}
if m.ConnectionPriorityUpgradeThreshold != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.ConnectionPriorityUpgradeThreshold))
}
if m.DeprecatedUPnPEnabled { if m.DeprecatedUPnPEnabled {
n += 4 n += 4
} }
@ -2292,6 +2375,120 @@ func (m *OptionsConfiguration) Unmarshal(dAtA []byte) error {
} }
} }
m.InsecureAllowOldTLSVersions = bool(v != 0) m.InsecureAllowOldTLSVersions = bool(v != 0)
case 54:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ConnectionPriorityTCPLAN", wireType)
}
m.ConnectionPriorityTCPLAN = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOptionsconfiguration
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ConnectionPriorityTCPLAN |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 55:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ConnectionPriorityQUICLAN", wireType)
}
m.ConnectionPriorityQUICLAN = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOptionsconfiguration
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ConnectionPriorityQUICLAN |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 56:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ConnectionPriorityTCPWAN", wireType)
}
m.ConnectionPriorityTCPWAN = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOptionsconfiguration
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ConnectionPriorityTCPWAN |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 57:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ConnectionPriorityQUICWAN", wireType)
}
m.ConnectionPriorityQUICWAN = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOptionsconfiguration
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ConnectionPriorityQUICWAN |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 58:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ConnectionPriorityRelay", wireType)
}
m.ConnectionPriorityRelay = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOptionsconfiguration
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ConnectionPriorityRelay |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 59:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ConnectionPriorityUpgradeThreshold", wireType)
}
m.ConnectionPriorityUpgradeThreshold = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOptionsconfiguration
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ConnectionPriorityUpgradeThreshold |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 9000: case 9000:
if wireType != 0 { if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedUPnPEnabled", wireType) return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedUPnPEnabled", wireType)

View File

@ -45,6 +45,11 @@
<unackedNotificationID>asdfasdf</unackedNotificationID> <unackedNotificationID>asdfasdf</unackedNotificationID>
<announceLANAddresses>false</announceLANAddresses> <announceLANAddresses>false</announceLANAddresses>
<featureFlag>feature</featureFlag> <featureFlag>feature</featureFlag>
<connectionPriorityTcpLan>40</connectionPriorityTcpLan>
<connectionPriorityQuicLan>45</connectionPriorityQuicLan>
<connectionPriorityTcpWan>50</connectionPriorityTcpWan>
<connectionPriorityQuicWan>55</connectionPriorityQuicWan>
<connectionPriorityRelay>9000</connectionPriorityRelay>
</options> </options>
<defaults> <defaults>
<folder id="" label="" path="/media/syncthing" type="sendreceive" rescanIntervalS="3600" fsWatcherEnabled="true" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true"> <folder id="" label="" path="/media/syncthing" type="sendreceive" rescanIntervalS="3600" fsWatcherEnabled="true" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true">

View File

@ -439,7 +439,8 @@ func withConnectionPair(b interface{ Fatal(...interface{}) }, connUri string, h
} }
natSvc := nat.NewService(deviceId, wcfg) natSvc := nat.NewService(deviceId, wcfg)
conns := make(chan internalConn, 1) conns := make(chan internalConn, 1)
listenSvc := lf.New(uri, wcfg, tlsCfg, conns, natSvc, registry.New()) lanChecker := &lanChecker{wcfg}
listenSvc := lf.New(uri, wcfg, tlsCfg, conns, natSvc, registry.New(), lanChecker)
supervisor.Add(listenSvc) supervisor.Add(listenSvc)
var addr *url.URL var addr *url.URL
@ -459,7 +460,7 @@ func withConnectionPair(b interface{ Fatal(...interface{}) }, connUri string, h
b.Fatal(err) b.Fatal(err)
} }
// Purposely using a different registry: Don't want to reuse port between dialer and listener on the same device // Purposely using a different registry: Don't want to reuse port between dialer and listener on the same device
dialer := df.New(cfg.Options, tlsCfg, registry.New()) dialer := df.New(cfg.Options, tlsCfg, registry.New(), lanChecker)
// Relays might take some time to register the device, so dial multiple times // Relays might take some time to register the device, so dial multiple times
clientConn, err := dialer.Dial(ctx, deviceId, addr) clientConn, err := dialer.Dial(ctx, deviceId, addr)

View File

@ -38,7 +38,7 @@ func TestIsLANHost(t *testing.T) {
AlwaysLocalNets: []string{"10.20.30.0/24"}, AlwaysLocalNets: []string{"10.20.30.0/24"},
}, },
}, protocol.LocalDeviceID, events.NoopLogger) }, protocol.LocalDeviceID, events.NoopLogger)
s := &service{cfg: cfg} s := &lanChecker{cfg: cfg}
for _, tc := range cases { for _, tc := range cases {
res := s.isLANHost(tc.addr) res := s.isLANHost(tc.addr)

View File

@ -25,8 +25,6 @@ import (
) )
const ( const (
quicPriority = 100
// The timeout for connecting, accepting and creating the various // The timeout for connecting, accepting and creating the various
// streams. // streams.
quicOperationTimeout = 10 * time.Second quicOperationTimeout = 10 * time.Second
@ -92,12 +90,17 @@ func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL
return internalConn{}, fmt.Errorf("open stream: %w", err) return internalConn{}, fmt.Errorf("open stream: %w", err)
} }
return newInternalConn(&quicTlsConn{session, stream, createdConn}, connTypeQUICClient, quicPriority), nil priority := d.wanPriority
isLocal := d.lanChecker.isLAN(session.RemoteAddr())
if isLocal {
priority = d.lanPriority
}
return newInternalConn(&quicTlsConn{session, stream, createdConn}, connTypeQUICClient, isLocal, priority), nil
} }
type quicDialerFactory struct{} type quicDialerFactory struct{}
func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, registry *registry.Registry) genericDialer { func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, registry *registry.Registry, lanChecker *lanChecker) genericDialer {
// So the idea is that we should probably try dialing every 20 seconds. // So the idea is that we should probably try dialing every 20 seconds.
// However it would still be nice if this was adjustable/proportional to ReconnectIntervalS // However it would still be nice if this was adjustable/proportional to ReconnectIntervalS
// But prevent something silly like 1/3 = 0 etc. // But prevent something silly like 1/3 = 0 etc.
@ -109,15 +112,14 @@ func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Confi
commonDialer: commonDialer{ commonDialer: commonDialer{
reconnectInterval: time.Duration(quicInterval) * time.Second, reconnectInterval: time.Duration(quicInterval) * time.Second,
tlsCfg: tlsCfg, tlsCfg: tlsCfg,
lanPriority: opts.ConnectionPriorityQUICLAN,
wanPriority: opts.ConnectionPriorityQUICWAN,
lanChecker: lanChecker,
}, },
registry: registry, registry: registry,
} }
} }
func (quicDialerFactory) Priority() int {
return quicPriority
}
func (quicDialerFactory) AlwaysWAN() bool { func (quicDialerFactory) AlwaysWAN() bool {
return false return false
} }

View File

@ -40,12 +40,13 @@ type quicListener struct {
onAddressesChangedNotifier onAddressesChangedNotifier
uri *url.URL uri *url.URL
cfg config.Wrapper cfg config.Wrapper
tlsCfg *tls.Config tlsCfg *tls.Config
conns chan internalConn conns chan internalConn
factory listenerFactory factory listenerFactory
registry *registry.Registry registry *registry.Registry
lanChecker *lanChecker
address *url.URL address *url.URL
laddr net.Addr laddr net.Addr
@ -168,7 +169,12 @@ func (t *quicListener) serve(ctx context.Context) error {
continue continue
} }
t.conns <- newInternalConn(&quicTlsConn{session, stream, nil}, connTypeQUICServer, quicPriority) priority := t.cfg.Options().ConnectionPriorityQUICWAN
isLocal := t.lanChecker.isLAN(session.RemoteAddr())
if isLocal {
priority = t.cfg.Options().ConnectionPriorityQUICLAN
}
t.conns <- newInternalConn(&quicTlsConn{session, stream, nil}, connTypeQUICServer, isLocal, priority)
} }
} }
@ -218,14 +224,15 @@ func (*quicListenerFactory) Valid(config.Configuration) error {
return nil return nil
} }
func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, _ *nat.Service, registry *registry.Registry) genericListener { func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, _ *nat.Service, registry *registry.Registry, lanChecker *lanChecker) genericListener {
l := &quicListener{ l := &quicListener{
uri: fixupPort(uri, config.DefaultQUICPort), uri: fixupPort(uri, config.DefaultQUICPort),
cfg: cfg, cfg: cfg,
tlsCfg: tlsCfg, tlsCfg: tlsCfg,
conns: conns, conns: conns,
factory: f, factory: f,
registry: registry, registry: registry,
lanChecker: lanChecker,
} }
l.ServiceWithError = svcutil.AsService(l.serve, l.String()) l.ServiceWithError = svcutil.AsService(l.serve, l.String())
l.nat.Store(uint64(stun.NATUnknown)) l.nat.Store(uint64(stun.NATUnknown))

View File

@ -19,8 +19,6 @@ import (
"github.com/syncthing/syncthing/lib/relay/client" "github.com/syncthing/syncthing/lib/relay/client"
) )
const relayPriority = 200
func init() { func init() {
dialers["relay"] = relayDialerFactory{} dialers["relay"] = relayDialerFactory{}
} }
@ -64,23 +62,21 @@ func (d *relayDialer) Dial(ctx context.Context, id protocol.DeviceID, uri *url.U
return internalConn{}, err return internalConn{}, err
} }
return newInternalConn(tc, connTypeRelayClient, relayPriority), nil return newInternalConn(tc, connTypeRelayClient, false, d.wanPriority), nil
} }
type relayDialerFactory struct{} type relayDialerFactory struct{}
func (relayDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, _ *registry.Registry) genericDialer { func (relayDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, _ *registry.Registry, _ *lanChecker) genericDialer {
return &relayDialer{commonDialer{ return &relayDialer{commonDialer{
trafficClass: opts.TrafficClass, trafficClass: opts.TrafficClass,
reconnectInterval: time.Duration(opts.RelayReconnectIntervalM) * time.Minute, reconnectInterval: time.Duration(opts.RelayReconnectIntervalM) * time.Minute,
tlsCfg: tlsCfg, tlsCfg: tlsCfg,
wanPriority: opts.ConnectionPriorityRelay,
lanPriority: opts.ConnectionPriorityRelay,
}} }}
} }
func (relayDialerFactory) Priority() int {
return relayPriority
}
func (relayDialerFactory) AlwaysWAN() bool { func (relayDialerFactory) AlwaysWAN() bool {
return true return true
} }

View File

@ -106,7 +106,7 @@ func (t *relayListener) handleInvitations(ctx context.Context, clnt client.Relay
continue continue
} }
t.conns <- newInternalConn(tc, connTypeRelayServer, relayPriority) t.conns <- newInternalConn(tc, connTypeRelayServer, false, t.cfg.Options().ConnectionPriorityRelay)
// Poor mans notifier that informs the connection service that the // Poor mans notifier that informs the connection service that the
// relay URI has changed. This can only happen when we connect to a // relay URI has changed. This can only happen when we connect to a
@ -177,7 +177,7 @@ func (*relayListener) NATType() string {
type relayListenerFactory struct{} type relayListenerFactory struct{}
func (f *relayListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, _ *nat.Service, _ *registry.Registry) genericListener { func (f *relayListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, _ *nat.Service, _ *registry.Registry, _ *lanChecker) genericListener {
t := &relayListener{ t := &relayListener{
uri: uri, uri: uri,
cfg: cfg, cfg: cfg,

View File

@ -162,6 +162,7 @@ type service struct {
evLogger events.Logger evLogger events.Logger
registry *registry.Registry registry *registry.Registry
keyGen *protocol.KeyGenerator keyGen *protocol.KeyGenerator
lanChecker *lanChecker
dialNow chan struct{} dialNow chan struct{}
dialNowDevices map[protocol.DeviceID]struct{} dialNowDevices map[protocol.DeviceID]struct{}
@ -192,6 +193,7 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
evLogger: evLogger, evLogger: evLogger,
registry: registry, registry: registry,
keyGen: keyGen, keyGen: keyGen,
lanChecker: &lanChecker{cfg},
dialNowDevicesMut: sync.NewMutex(), dialNowDevicesMut: sync.NewMutex(),
dialNow: make(chan struct{}, 1), dialNow: make(chan struct{}, 1),
@ -405,9 +407,6 @@ func (s *service) handleHellos(ctx context.Context) error {
continue continue
} }
// Determine only once whether a connection is considered local
// according to our configuration, then cache the decision.
c.isLocal = s.isLAN(c.RemoteAddr())
// Wrap the connection in rate limiters. The limiter itself will // Wrap the connection in rate limiters. The limiter itself will
// keep up with config changes to the rate and whether or not LAN // keep up with config changes to the rate and whether or not LAN
// connections are limited. // connections are limited.
@ -496,13 +495,14 @@ func (s *service) connect(ctx context.Context) error {
} }
} }
func (*service) bestDialerPriority(cfg config.Configuration) int { func (s *service) bestDialerPriority(cfg config.Configuration) int {
bestDialerPriority := worstDialerPriority bestDialerPriority := worstDialerPriority
for _, df := range dialers { for _, df := range dialers {
if df.Valid(cfg) != nil { if df.Valid(cfg) != nil {
continue continue
} }
if prio := df.Priority(); prio < bestDialerPriority { prio := df.New(cfg.Options, s.tlsCfg, s.registry, s.lanChecker).Priority("127.0.0.1")
if prio < bestDialerPriority {
bestDialerPriority = prio bestDialerPriority = prio
} }
} }
@ -544,7 +544,14 @@ func (s *service) dialDevices(ctx context.Context, now time.Time, cfg config.Con
priorityCutoff := worstDialerPriority priorityCutoff := worstDialerPriority
connection, connected := s.model.Connection(deviceCfg.DeviceID) connection, connected := s.model.Connection(deviceCfg.DeviceID)
if connected { if connected {
// Set the priority cutoff to the current connection's priority,
// so that we don't attempt any dialers with worse priority.
priorityCutoff = connection.Priority() priorityCutoff = connection.Priority()
// Reduce the priority cutoff by the upgrade threshold, so that
// we don't attempt dialers that aren't considered a worthy upgrade.
priorityCutoff -= cfg.Options.ConnectionPriorityUpgradeThreshold
if bestDialerPriority >= priorityCutoff { if bestDialerPriority >= priorityCutoff {
// Our best dialer is not any better than what we already // Our best dialer is not any better than what we already
// have, so nothing to do here. // have, so nothing to do here.
@ -564,7 +571,7 @@ func (s *service) dialDevices(ctx context.Context, now time.Time, cfg config.Con
} }
// Sort the queue in an order we think will be useful (most recent // Sort the queue in an order we think will be useful (most recent
// first, deprioriting unstable devices, randomizing those we haven't // first, deprioritising unstable devices, randomizing those we haven't
// seen in a long while). If we don't do connection limiting the sorting // seen in a long while). If we don't do connection limiting the sorting
// doesn't have much effect, but it may result in getting up and running // doesn't have much effect, but it may result in getting up and running
// quicker if only a subset of configured devices are actually reachable // quicker if only a subset of configured devices are actually reachable
@ -657,24 +664,15 @@ func (s *service) resolveDialTargets(ctx context.Context, now time.Time, cfg con
continue continue
} }
priority := dialerFactory.Priority() dialer := dialerFactory.New(s.cfg.Options(), s.tlsCfg, s.registry, s.lanChecker)
priority := dialer.Priority(uri.Host)
if priority >= priorityCutoff { if priority >= priorityCutoff {
l.Debugf("Not dialing using %s as priority is not better than current connection (%d >= %d)", dialerFactory, dialerFactory.Priority(), priorityCutoff) l.Debugf("Not dialing using %s as priority is not better than current connection (%d >= %d)", dialerFactory, priority, priorityCutoff)
continue continue
} }
dialer := dialerFactory.New(s.cfg.Options(), s.tlsCfg, s.registry)
nextDialAt.set(deviceID, addr, now.Add(dialer.RedialFrequency())) nextDialAt.set(deviceID, addr, now.Add(dialer.RedialFrequency()))
// For LAN addresses, increase the priority so that we
// try these first.
switch {
case dialerFactory.AlwaysWAN():
// Do nothing.
case s.isLANHost(uri.Host):
priority--
}
dialTargets = append(dialTargets, dialTarget{ dialTargets = append(dialTargets, dialTarget{
addr: addr, addr: addr,
dialer: dialer, dialer: dialer,
@ -703,7 +701,11 @@ func (s *service) resolveDeviceAddrs(ctx context.Context, cfg config.DeviceConfi
return util.UniqueTrimmedStrings(addrs) return util.UniqueTrimmedStrings(addrs)
} }
func (s *service) isLANHost(host string) bool { type lanChecker struct {
cfg config.Wrapper
}
func (s *lanChecker) isLANHost(host string) bool {
// Probably we are called with an ip:port combo which we can resolve as // Probably we are called with an ip:port combo which we can resolve as
// a TCP address. // a TCP address.
if addr, err := net.ResolveTCPAddr("tcp", host); err == nil { if addr, err := net.ResolveTCPAddr("tcp", host); err == nil {
@ -717,7 +719,7 @@ func (s *service) isLANHost(host string) bool {
return false return false
} }
func (s *service) isLAN(addr net.Addr) bool { func (s *lanChecker) isLAN(addr net.Addr) bool {
var ip net.IP var ip net.IP
switch addr := addr.(type) { switch addr := addr.(type) {
@ -763,7 +765,7 @@ func (s *service) createListener(factory listenerFactory, uri *url.URL) bool {
l.Debugln("Starting listener", uri) l.Debugln("Starting listener", uri)
listener := factory.New(uri, s.cfg, s.tlsCfg, s.conns, s.natService, s.registry) listener := factory.New(uri, s.cfg, s.tlsCfg, s.conns, s.natService, s.registry, s.lanChecker)
listener.OnAddressesChanged(s.logListenAddressesChangedEvent) listener.OnAddressesChanged(s.logListenAddressesChangedEvent)
// Retrying a listener many times in rapid succession is unlikely to help, // Retrying a listener many times in rapid succession is unlikely to help,

View File

@ -87,10 +87,11 @@ func (t connType) Transport() string {
} }
} }
func newInternalConn(tc tlsConn, connType connType, priority int) internalConn { func newInternalConn(tc tlsConn, connType connType, isLocal bool, priority int) internalConn {
return internalConn{ return internalConn{
tlsConn: tc, tlsConn: tc,
connType: connType, connType: connType,
isLocal: isLocal,
priority: priority, priority: priority,
establishedAt: time.Now().Truncate(time.Second), establishedAt: time.Now().Truncate(time.Second),
} }
@ -138,12 +139,15 @@ func (c internalConn) EstablishedAt() time.Time {
} }
func (c internalConn) String() string { func (c internalConn) String() string {
return fmt.Sprintf("%s-%s/%s/%s", c.LocalAddr(), c.RemoteAddr(), c.Type(), c.Crypto()) t := "WAN"
if c.isLocal {
t = "LAN"
}
return fmt.Sprintf("%s-%s/%s/%s/%s-P%d", c.LocalAddr(), c.RemoteAddr(), c.Type(), c.Crypto(), t, c.Priority())
} }
type dialerFactory interface { type dialerFactory interface {
New(config.OptionsConfiguration, *tls.Config, *registry.Registry) genericDialer New(config.OptionsConfiguration, *tls.Config, *registry.Registry, *lanChecker) genericDialer
Priority() int
AlwaysWAN() bool AlwaysWAN() bool
Valid(config.Configuration) error Valid(config.Configuration) error
String() string String() string
@ -153,19 +157,30 @@ type commonDialer struct {
trafficClass int trafficClass int
reconnectInterval time.Duration reconnectInterval time.Duration
tlsCfg *tls.Config tlsCfg *tls.Config
lanChecker *lanChecker
lanPriority int
wanPriority int
} }
func (d *commonDialer) RedialFrequency() time.Duration { func (d *commonDialer) RedialFrequency() time.Duration {
return d.reconnectInterval return d.reconnectInterval
} }
func (d *commonDialer) Priority(host string) int {
if d.lanChecker.isLANHost(host) {
return d.lanPriority
}
return d.wanPriority
}
type genericDialer interface { type genericDialer interface {
Dial(context.Context, protocol.DeviceID, *url.URL) (internalConn, error) Dial(context.Context, protocol.DeviceID, *url.URL) (internalConn, error)
RedialFrequency() time.Duration RedialFrequency() time.Duration
Priority(host string) int
} }
type listenerFactory interface { type listenerFactory interface {
New(*url.URL, config.Wrapper, *tls.Config, chan internalConn, *nat.Service, *registry.Registry) genericListener New(*url.URL, config.Wrapper, *tls.Config, chan internalConn, *nat.Service, *registry.Registry, *lanChecker) genericListener
Valid(config.Configuration) error Valid(config.Configuration) error
} }

View File

@ -18,8 +18,6 @@ import (
"github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/protocol"
) )
const tcpPriority = 10
func init() { func init() {
factory := &tcpDialerFactory{} factory := &tcpDialerFactory{}
for _, scheme := range []string{"tcp", "tcp4", "tcp6"} { for _, scheme := range []string{"tcp", "tcp4", "tcp6"} {
@ -59,26 +57,30 @@ func (d *tcpDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL)
return internalConn{}, err return internalConn{}, err
} }
return newInternalConn(tc, connTypeTCPClient, tcpPriority), nil priority := d.wanPriority
isLocal := d.lanChecker.isLAN(conn.RemoteAddr())
if isLocal {
priority = d.lanPriority
}
return newInternalConn(tc, connTypeTCPClient, isLocal, priority), nil
} }
type tcpDialerFactory struct{} type tcpDialerFactory struct{}
func (tcpDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, registry *registry.Registry) genericDialer { func (tcpDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config, registry *registry.Registry, lanChecker *lanChecker) genericDialer {
return &tcpDialer{ return &tcpDialer{
commonDialer: commonDialer{ commonDialer: commonDialer{
trafficClass: opts.TrafficClass, trafficClass: opts.TrafficClass,
reconnectInterval: time.Duration(opts.ReconnectIntervalS) * time.Second, reconnectInterval: time.Duration(opts.ReconnectIntervalS) * time.Second,
tlsCfg: tlsCfg, tlsCfg: tlsCfg,
lanPriority: opts.ConnectionPriorityTCPLAN,
wanPriority: opts.ConnectionPriorityTCPWAN,
lanChecker: lanChecker,
}, },
registry: registry, registry: registry,
} }
} }
func (tcpDialerFactory) Priority() int {
return tcpPriority
}
func (tcpDialerFactory) AlwaysWAN() bool { func (tcpDialerFactory) AlwaysWAN() bool {
return false return false
} }

View File

@ -32,12 +32,13 @@ type tcpListener struct {
svcutil.ServiceWithError svcutil.ServiceWithError
onAddressesChangedNotifier onAddressesChangedNotifier
uri *url.URL uri *url.URL
cfg config.Wrapper cfg config.Wrapper
tlsCfg *tls.Config tlsCfg *tls.Config
conns chan internalConn conns chan internalConn
factory listenerFactory factory listenerFactory
registry *registry.Registry registry *registry.Registry
lanChecker *lanChecker
natService *nat.Service natService *nat.Service
mapping *nat.Mapping mapping *nat.Mapping
@ -148,7 +149,12 @@ func (t *tcpListener) serve(ctx context.Context) error {
continue continue
} }
t.conns <- newInternalConn(tc, connTypeTCPServer, tcpPriority) priority := t.cfg.Options().ConnectionPriorityTCPWAN
isLocal := t.lanChecker.isLAN(conn.RemoteAddr())
if isLocal {
priority = t.cfg.Options().ConnectionPriorityTCPLAN
}
t.conns <- newInternalConn(tc, connTypeTCPServer, isLocal, priority)
} }
} }
@ -214,7 +220,7 @@ func (t *tcpListener) NATType() string {
type tcpListenerFactory struct{} type tcpListenerFactory struct{}
func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service, registry *registry.Registry) genericListener { func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service, registry *registry.Registry, lanChecker *lanChecker) genericListener {
l := &tcpListener{ l := &tcpListener{
uri: fixupPort(uri, config.DefaultTCPPort), uri: fixupPort(uri, config.DefaultTCPPort),
cfg: cfg, cfg: cfg,
@ -223,6 +229,7 @@ func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.C
natService: natService, natService: natService,
factory: f, factory: f,
registry: registry, registry: registry,
lanChecker: lanChecker,
} }
l.ServiceWithError = svcutil.AsService(l.serve, l.String()) l.ServiceWithError = svcutil.AsService(l.serve, l.String())
return l return l

View File

@ -70,6 +70,13 @@ message OptionsConfiguration {
// default to TLS 1.3+ only. // default to TLS 1.3+ only.
bool insecure_allow_old_tls_versions = 53 [(ext.goname)= "InsecureAllowOldTLSVersions", (ext.xml) = "insecureAllowOldTLSVersions", (ext.json) = "insecureAllowOldTLSVersions"]; bool insecure_allow_old_tls_versions = 53 [(ext.goname)= "InsecureAllowOldTLSVersions", (ext.xml) = "insecureAllowOldTLSVersions", (ext.json) = "insecureAllowOldTLSVersions"];
int32 connection_priority_tcp_lan = 54 [(ext.default) = "10", (ext.goname) = "ConnectionPriorityTCPLAN"];
int32 connection_priority_quic_lan = 55 [(ext.default) = "20", (ext.goname) = "ConnectionPriorityQUICLAN"];
int32 connection_priority_tcp_wan = 56 [(ext.default) = "30", (ext.goname) = "ConnectionPriorityTCPWAN"];
int32 connection_priority_quic_wan = 57 [(ext.default) = "40", (ext.goname) = "ConnectionPriorityQUICWAN"];
int32 connection_priority_relay = 58 [(ext.default) = "50"];
int32 connection_priority_upgrade_threshold = 59 [(ext.default) = "0"];
// Legacy deprecated // Legacy deprecated
bool upnp_enabled = 9000 [deprecated = true, (ext.goname) = "DeprecatedUPnPEnabled"]; bool upnp_enabled = 9000 [deprecated = true, (ext.goname) = "DeprecatedUPnPEnabled"];
int32 upnp_lease_m = 9001 [deprecated = true, (ext.goname) = "DeprecatedUPnPLeaseM", (ext.xml) = "upnpLeaseMinutes,omitempty"]; int32 upnp_lease_m = 9001 [deprecated = true, (ext.goname) = "DeprecatedUPnPLeaseM", (ext.xml) = "upnpLeaseMinutes,omitempty"];