From 9b660c1959ef44ee05a55b39dbdf6295ac81f347 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sun, 16 Apr 2023 12:54:28 +0000 Subject: [PATCH] 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. --- .../syncthing/core/syncthingController.js | 3 +- lib/config/config_test.go | 166 ++--- lib/config/optionsconfiguration.go | 9 + lib/config/optionsconfiguration.pb.go | 607 ++++++++++++------ lib/config/testdata/overridenvalues.xml | 5 + lib/connections/connections_test.go | 5 +- lib/connections/lan_test.go | 2 +- lib/connections/quic_dial.go | 18 +- lib/connections/quic_listen.go | 35 +- lib/connections/relay_dial.go | 12 +- lib/connections/relay_listen.go | 4 +- lib/connections/service.go | 44 +- lib/connections/structs.go | 25 +- lib/connections/tcp_dial.go | 18 +- lib/connections/tcp_listen.go | 23 +- proto/lib/config/optionsconfiguration.proto | 7 + 16 files changed, 622 insertions(+), 361 deletions(-) diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js index fac5b43ab..9be6a988b 100755 --- a/gui/default/syncthing/core/syncthingController.js +++ b/gui/default/syncthing/core/syncthingController.js @@ -1256,8 +1256,9 @@ angular.module('syncthing.core') case "relaywan": return $translate.instant('Connections via relays might be rate limited by the relay'); case "quiclan": + return $translate.instant('Using a QUIC connection over LAN'); case "quicwan": - return $translate.instant('QUIC connections are in most cases considered suboptimal'); + return $translate.instant('Using a QUIC connection over WAN'); case "tcpwan": return $translate.instant('Using a direct TCP connection over WAN'); case "tcplan": diff --git a/lib/config/config_test.go b/lib/config/config_test.go index 00e41a012..a0446e644 100644 --- a/lib/config/config_test.go +++ b/lib/config/config_test.go @@ -47,44 +47,49 @@ func TestDefaultValues(t *testing.T) { Version: CurrentVersion, Folders: []FolderConfiguration{}, Options: OptionsConfiguration{ - RawListenAddresses: []string{"default"}, - RawGlobalAnnServers: []string{"default"}, - GlobalAnnEnabled: true, - LocalAnnEnabled: true, - LocalAnnPort: 21027, - LocalAnnMCAddr: "[ff12::8384]:21027", - MaxSendKbps: 0, - MaxRecvKbps: 0, - ReconnectIntervalS: 60, - RelaysEnabled: true, - RelayReconnectIntervalM: 10, - StartBrowser: true, - NATEnabled: true, - NATLeaseM: 60, - NATRenewalM: 30, - NATTimeoutS: 10, - AutoUpgradeIntervalH: 12, - KeepTemporariesH: 24, - CacheIgnoredFiles: false, - ProgressUpdateIntervalS: 5, - LimitBandwidthInLan: false, - MinHomeDiskFree: Size{1, "%"}, - URURL: "https://data.syncthing.net/newdata", - URInitialDelayS: 1800, - URPostInsecurely: false, - ReleasesURL: "https://upgrades.syncthing.net/meta.json", - AlwaysLocalNets: []string{}, - OverwriteRemoteDevNames: false, - TempIndexMinBlocks: 10, - UnackedNotificationIDs: []string{"authenticationUserAndPassword"}, - SetLowPriority: true, - CRURL: "https://crash.syncthing.net/newcrash", - CREnabled: true, - StunKeepaliveStartS: 180, - StunKeepaliveMinS: 20, - RawStunServers: []string{"default"}, - AnnounceLANAddresses: true, - FeatureFlags: []string{}, + RawListenAddresses: []string{"default"}, + RawGlobalAnnServers: []string{"default"}, + GlobalAnnEnabled: true, + LocalAnnEnabled: true, + LocalAnnPort: 21027, + LocalAnnMCAddr: "[ff12::8384]:21027", + MaxSendKbps: 0, + MaxRecvKbps: 0, + ReconnectIntervalS: 60, + RelaysEnabled: true, + RelayReconnectIntervalM: 10, + StartBrowser: true, + NATEnabled: true, + NATLeaseM: 60, + NATRenewalM: 30, + NATTimeoutS: 10, + AutoUpgradeIntervalH: 12, + KeepTemporariesH: 24, + CacheIgnoredFiles: false, + ProgressUpdateIntervalS: 5, + LimitBandwidthInLan: false, + MinHomeDiskFree: Size{1, "%"}, + URURL: "https://data.syncthing.net/newdata", + URInitialDelayS: 1800, + URPostInsecurely: false, + ReleasesURL: "https://upgrades.syncthing.net/meta.json", + AlwaysLocalNets: []string{}, + OverwriteRemoteDevNames: false, + TempIndexMinBlocks: 10, + UnackedNotificationIDs: []string{"authenticationUserAndPassword"}, + SetLowPriority: true, + CRURL: "https://crash.syncthing.net/newcrash", + CREnabled: true, + StunKeepaliveStartS: 180, + StunKeepaliveMinS: 20, + RawStunServers: []string{"default"}, + AnnounceLANAddresses: true, + FeatureFlags: []string{}, + ConnectionPriorityTCPLAN: 10, + ConnectionPriorityQUICLAN: 20, + ConnectionPriorityTCPWAN: 30, + ConnectionPriorityQUICWAN: 40, + ConnectionPriorityRelay: 50, }, Defaults: Defaults{ Folder: FolderConfiguration{ @@ -239,45 +244,50 @@ func TestNoListenAddresses(t *testing.T) { func TestOverriddenValues(t *testing.T) { expected := OptionsConfiguration{ - RawListenAddresses: []string{"tcp://:23000"}, - RawGlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"}, - GlobalAnnEnabled: false, - LocalAnnEnabled: false, - LocalAnnPort: 42123, - LocalAnnMCAddr: "quux:3232", - MaxSendKbps: 1234, - MaxRecvKbps: 2341, - ReconnectIntervalS: 6000, - RelaysEnabled: false, - RelayReconnectIntervalM: 20, - StartBrowser: false, - NATEnabled: false, - NATLeaseM: 90, - NATRenewalM: 15, - NATTimeoutS: 15, - AutoUpgradeIntervalH: 24, - KeepTemporariesH: 48, - CacheIgnoredFiles: true, - ProgressUpdateIntervalS: 10, - LimitBandwidthInLan: true, - MinHomeDiskFree: Size{5.2, "%"}, - URSeen: 8, - URAccepted: 4, - URURL: "https://localhost/newdata", - URInitialDelayS: 800, - URPostInsecurely: true, - ReleasesURL: "https://localhost/releases", - AlwaysLocalNets: []string{}, - OverwriteRemoteDevNames: true, - TempIndexMinBlocks: 100, - UnackedNotificationIDs: []string{"asdfasdf"}, - SetLowPriority: false, - CRURL: "https://localhost/newcrash", - CREnabled: false, - StunKeepaliveStartS: 9000, - StunKeepaliveMinS: 900, - RawStunServers: []string{"foo"}, - FeatureFlags: []string{"feature"}, + RawListenAddresses: []string{"tcp://:23000"}, + RawGlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"}, + GlobalAnnEnabled: false, + LocalAnnEnabled: false, + LocalAnnPort: 42123, + LocalAnnMCAddr: "quux:3232", + MaxSendKbps: 1234, + MaxRecvKbps: 2341, + ReconnectIntervalS: 6000, + RelaysEnabled: false, + RelayReconnectIntervalM: 20, + StartBrowser: false, + NATEnabled: false, + NATLeaseM: 90, + NATRenewalM: 15, + NATTimeoutS: 15, + AutoUpgradeIntervalH: 24, + KeepTemporariesH: 48, + CacheIgnoredFiles: true, + ProgressUpdateIntervalS: 10, + LimitBandwidthInLan: true, + MinHomeDiskFree: Size{5.2, "%"}, + URSeen: 8, + URAccepted: 4, + URURL: "https://localhost/newdata", + URInitialDelayS: 800, + URPostInsecurely: true, + ReleasesURL: "https://localhost/releases", + AlwaysLocalNets: []string{}, + OverwriteRemoteDevNames: true, + TempIndexMinBlocks: 100, + UnackedNotificationIDs: []string{"asdfasdf"}, + SetLowPriority: false, + CRURL: "https://localhost/newcrash", + CREnabled: false, + StunKeepaliveStartS: 9000, + StunKeepaliveMinS: 900, + RawStunServers: []string{"foo"}, + FeatureFlags: []string{"feature"}, + ConnectionPriorityTCPLAN: 40, + ConnectionPriorityQUICLAN: 45, + ConnectionPriorityTCPWAN: 50, + ConnectionPriorityQUICWAN: 55, + ConnectionPriorityRelay: 9000, } expectedPath := "/media/syncthing" @@ -514,7 +524,7 @@ func TestFolderCheckPath(t *testing.T) { n := t.TempDir() 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 { t.Fatal(err) } diff --git a/lib/config/optionsconfiguration.go b/lib/config/optionsconfiguration.go index ea2de8bee..95d75416f 100644 --- a/lib/config/optionsconfiguration.go +++ b/lib/config/optionsconfiguration.go @@ -55,6 +55,15 @@ func (opts *OptionsConfiguration) prepare(guiPWIsSet bool) { if 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 diff --git a/lib/config/optionsconfiguration.pb.go b/lib/config/optionsconfiguration.pb.go index a262593a2..2d9d0360c 100644 --- a/lib/config/optionsconfiguration.pb.go +++ b/lib/config/optionsconfiguration.pb.go @@ -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"` // When set, this allows TLS 1.2 on sync connections, where we otherwise // 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 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. @@ -135,211 +141,228 @@ func init() { } 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, - 0xd9, 0xce, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x1e, 0x3b, 0xf6, 0x36, 0x49, 0xbd, 0xee, 0xc9, - 0x49, 0xeb, 0xfe, 0x25, 0xb6, 0x93, 0xe6, 0x4b, 0x23, 0x7d, 0xea, 0xe7, 0x9f, 0xfa, 0xab, 0x1b, - 0x3b, 0xb1, 0xc6, 0xf6, 0xf7, 0xa1, 0x22, 0xb4, 0x1a, 0xef, 0xce, 0xb1, 0x17, 0xef, 0x99, 0x3d, - 0xdd, 0x99, 0xf5, 0x4f, 0x8b, 0xa0, 0x2a, 0x82, 0x72, 0x07, 0x58, 0xfc, 0x48, 0x20, 0xa1, 0x22, - 0x40, 0xa2, 0x94, 0x22, 0x24, 0x24, 0x24, 0xb8, 0xa1, 0x42, 0x42, 0xaa, 0xe0, 0xc2, 0xbe, 0x44, - 0xa2, 0x2c, 0xaa, 0xd3, 0xab, 0x73, 0x81, 0xc4, 0xb9, 0x34, 0x37, 0x68, 0x66, 0xff, 0x66, 0x77, - 0xe7, 0x24, 0xb9, 0x3b, 0xfb, 0x3e, 0xef, 0xfb, 0xce, 0xf3, 0xce, 0xcf, 0x3b, 0xef, 0xcc, 0x1c, - 0xfd, 0xb2, 0xe7, 0xae, 0x5e, 0xb5, 0x7d, 0xd2, 0x70, 0xd7, 0xae, 0xfa, 0x2d, 0xe6, 0xfa, 0x84, - 0xc6, 0x5f, 0x61, 0x80, 0xf8, 0xd7, 0x95, 0x56, 0xe0, 0x33, 0x1f, 0x9c, 0x88, 0x85, 0xe7, 0x87, - 0x24, 0x75, 0x16, 0x12, 0x97, 0xac, 0xc5, 0x0a, 0xe7, 0xcf, 0x49, 0x00, 0x75, 0xdf, 0xc4, 0x89, - 0xf8, 0x24, 0xde, 0x66, 0xf1, 0xcf, 0xda, 0xbf, 0xe6, 0xf4, 0x81, 0xbb, 0x71, 0x0b, 0xd3, 0x72, - 0x0b, 0xe0, 0x47, 0x9a, 0x7e, 0xd6, 0x73, 0x29, 0xc3, 0xc4, 0x42, 0x8e, 0x13, 0x60, 0x4a, 0x31, - 0x35, 0xb4, 0x91, 0x63, 0xa3, 0x27, 0xa7, 0xe8, 0x41, 0x64, 0x02, 0x88, 0xb6, 0xe6, 0x05, 0x3c, - 0x99, 0xa2, 0xed, 0xc8, 0x3c, 0xe3, 0x15, 0x45, 0x9d, 0xc8, 0xbc, 0xbc, 0xdd, 0xf4, 0x6e, 0xd5, - 0x0a, 0xf2, 0xda, 0x88, 0x83, 0x1b, 0x28, 0xf4, 0xd8, 0xad, 0x5a, 0xf2, 0xa3, 0x76, 0xb8, 0x57, - 0x7f, 0x34, 0xf9, 0xbd, 0xbb, 0x5f, 0x57, 0x38, 0x87, 0x65, 0xd7, 0xe0, 0x9f, 0x9a, 0x6e, 0xac, - 0x79, 0xfe, 0x2a, 0xf2, 0x2c, 0xc7, 0xa5, 0xb6, 0xbf, 0x89, 0x83, 0x1d, 0x8b, 0xe2, 0x60, 0x13, - 0x07, 0xd4, 0x38, 0x2a, 0x88, 0xfe, 0x46, 0x3b, 0x88, 0xcc, 0x7e, 0x88, 0xb6, 0xfe, 0x57, 0xe8, - 0x4d, 0x12, 0xb2, 0x14, 0xe3, 0xed, 0xc8, 0x3c, 0xb7, 0x96, 0xca, 0xfc, 0x90, 0xd8, 0x38, 0x01, - 0x3a, 0x91, 0xf9, 0xbc, 0x20, 0xac, 0x42, 0x15, 0xbc, 0xdb, 0x7b, 0xf5, 0x01, 0x95, 0x6a, 0x67, - 0xaf, 0xae, 0x6e, 0xa0, 0x18, 0xa8, 0x8a, 0x1b, 0x1c, 0x8c, 0x0d, 0x67, 0xd2, 0xa0, 0x12, 0x39, - 0xf8, 0x4c, 0x15, 0x30, 0x26, 0x68, 0xd5, 0xc3, 0x8e, 0x71, 0x6c, 0x44, 0x1b, 0x7d, 0x6c, 0xea, - 0x7d, 0x1e, 0xf0, 0xd9, 0xcc, 0xe3, 0x2b, 0x31, 0x58, 0x8d, 0x36, 0x01, 0x3a, 0x91, 0xf9, 0xac, - 0x22, 0xda, 0x04, 0x95, 0xc2, 0x65, 0x41, 0x88, 0x79, 0xac, 0x5d, 0xdc, 0x74, 0x03, 0x0e, 0xf7, - 0xea, 0x8f, 0x70, 0xd3, 0xdd, 0xfd, 0x7a, 0x85, 0x54, 0x25, 0xcc, 0x44, 0x0e, 0x3e, 0xd1, 0xf4, - 0x21, 0xcf, 0xb7, 0x95, 0x51, 0x3e, 0x22, 0xa2, 0xfc, 0x09, 0x8f, 0xf2, 0xcc, 0x3c, 0xd7, 0x29, - 0x04, 0x39, 0xe0, 0x25, 0xa2, 0x52, 0x8c, 0xcf, 0xc4, 0x53, 0x50, 0x01, 0x2a, 0x42, 0x54, 0x3b, - 0xe9, 0x22, 0x97, 0x02, 0x2c, 0xf3, 0x81, 0xe7, 0x84, 0x41, 0x25, 0xbc, 0xbf, 0x68, 0x7a, 0x7f, - 0x1c, 0x1e, 0x4a, 0x7c, 0x59, 0x2d, 0x3f, 0x60, 0xc6, 0xf1, 0x11, 0x6d, 0xf4, 0xf8, 0xd4, 0x0f, - 0x78, 0x68, 0x3d, 0xa9, 0xab, 0x45, 0x3f, 0x60, 0xed, 0xc8, 0xec, 0x2b, 0x34, 0xcd, 0x85, 0x9d, - 0xc8, 0x7c, 0xba, 0x1a, 0x14, 0x47, 0xa4, 0x88, 0x26, 0xc6, 0xc7, 0x26, 0xfe, 0xab, 0x76, 0x18, - 0x99, 0xc7, 0x5c, 0xc2, 0xda, 0x7b, 0x75, 0x85, 0x1b, 0x95, 0xf0, 0x70, 0xaf, 0x7e, 0x5c, 0x98, - 0xee, 0xee, 0xd7, 0x0b, 0x4c, 0x60, 0x55, 0x17, 0x7c, 0xf5, 0xa8, 0x3e, 0x52, 0x8a, 0xa6, 0x19, - 0x7a, 0xcc, 0xb5, 0x11, 0x65, 0x69, 0xde, 0x30, 0x4e, 0x8c, 0x68, 0xa3, 0x27, 0xa7, 0x7e, 0xc7, - 0x43, 0xeb, 0x4d, 0x1d, 0x2e, 0x4c, 0xf3, 0x95, 0xdc, 0x8e, 0xcc, 0xfe, 0x82, 0xd3, 0x58, 0xdc, - 0x89, 0xcc, 0x1b, 0xd5, 0xf0, 0x62, 0x4c, 0x0a, 0xf0, 0xf3, 0x8d, 0xc6, 0xf8, 0xc4, 0xad, 0x5b, - 0x37, 0xaf, 0xdd, 0xbc, 0xfe, 0x85, 0x5b, 0x71, 0xb4, 0xed, 0xbd, 0xba, 0xd2, 0xa1, 0x5a, 0x7c, - 0xb8, 0x57, 0x07, 0x55, 0x27, 0xbb, 0xfb, 0xf5, 0x12, 0x4d, 0xf8, 0x44, 0xd1, 0x38, 0x8d, 0x30, - 0x49, 0x46, 0xe0, 0xae, 0x7e, 0xba, 0x89, 0xb6, 0x2d, 0x8a, 0x89, 0x63, 0x6d, 0xac, 0xb6, 0xa8, - 0xf1, 0xa8, 0x18, 0xcc, 0xe7, 0xda, 0x91, 0x79, 0xaa, 0x89, 0xb6, 0x97, 0x30, 0x71, 0x6e, 0xaf, - 0xb6, 0x78, 0x72, 0xe9, 0x13, 0x61, 0x49, 0xb2, 0x74, 0x7c, 0xa0, 0xac, 0x98, 0x3a, 0x0c, 0xb0, - 0xbd, 0x19, 0x3b, 0x7c, 0xac, 0xe0, 0x10, 0x62, 0x7b, 0xb3, 0xec, 0x30, 0x95, 0x15, 0x1c, 0xa6, - 0x42, 0xf0, 0x5b, 0x4d, 0x1f, 0x0a, 0xb0, 0xed, 0x13, 0x82, 0x6d, 0x9e, 0xde, 0x2d, 0x97, 0x30, - 0x1c, 0x6c, 0x22, 0xcf, 0xa2, 0xc6, 0x49, 0xe1, 0xfb, 0xcb, 0x22, 0xa9, 0xa7, 0x2a, 0x73, 0x09, - 0xbc, 0xc4, 0x73, 0x87, 0x6c, 0x98, 0x01, 0x9d, 0xc8, 0x1c, 0x15, 0x6d, 0x2b, 0x51, 0x69, 0x94, - 0x6e, 0x8c, 0xa5, 0x94, 0x0e, 0xf7, 0xea, 0x47, 0x6f, 0x8c, 0x89, 0xfc, 0x5e, 0x69, 0x07, 0xaa, - 0x5b, 0x01, 0x0d, 0xbd, 0x37, 0xc0, 0x1e, 0xda, 0xa1, 0x59, 0x0e, 0xd0, 0x45, 0x0e, 0x78, 0xb9, - 0x1d, 0x99, 0xa7, 0x63, 0x24, 0x5f, 0xe8, 0xb5, 0x84, 0x90, 0x24, 0x2d, 0xaf, 0xf0, 0x74, 0xc5, - 0xc2, 0xa2, 0x31, 0x78, 0xe7, 0xa8, 0x7e, 0x21, 0x69, 0x28, 0x23, 0x92, 0x77, 0x52, 0xd3, 0x38, - 0x25, 0x3a, 0xe9, 0x8f, 0x7c, 0x0e, 0x0f, 0x41, 0xae, 0x57, 0x09, 0x61, 0xa1, 0x1d, 0x99, 0x43, - 0x81, 0x1a, 0xca, 0x12, 0x6d, 0x17, 0x5c, 0x62, 0x39, 0x3e, 0x26, 0x2d, 0xd9, 0xae, 0xfe, 0xba, - 0x43, 0xbc, 0x93, 0xc7, 0x79, 0x27, 0x77, 0xa3, 0x09, 0x8d, 0x38, 0xce, 0x2a, 0x02, 0x56, 0xf5, - 0xd3, 0x94, 0xa1, 0x80, 0x59, 0xab, 0x81, 0xbf, 0x45, 0x71, 0x60, 0xf4, 0x88, 0xbe, 0xfe, 0xef, - 0x76, 0x64, 0xf6, 0x08, 0x60, 0x2a, 0x96, 0x77, 0x22, 0xf3, 0x49, 0x11, 0x8e, 0x2c, 0xec, 0xda, - 0xd3, 0x05, 0x53, 0xf0, 0x33, 0x4d, 0x3f, 0x47, 0x10, 0xb3, 0x58, 0x80, 0xf8, 0xae, 0x86, 0xbc, - 0x6c, 0x60, 0x7b, 0x45, 0x63, 0x6f, 0x1c, 0x44, 0xa6, 0x7e, 0x67, 0x72, 0x39, 0x4f, 0xeb, 0x3a, - 0x41, 0x2c, 0x1f, 0x63, 0x53, 0x34, 0x9c, 0x8b, 0x14, 0x29, 0x5c, 0x36, 0x28, 0x7c, 0x49, 0xe9, - 0x5a, 0x6a, 0x02, 0xf6, 0x13, 0xc4, 0x96, 0x53, 0x3a, 0xe9, 0x84, 0xf8, 0x7d, 0x85, 0xa7, 0x87, - 0x11, 0xc5, 0x56, 0xd3, 0x38, 0x23, 0xa6, 0xc2, 0xd7, 0xf9, 0x54, 0x38, 0x79, 0x67, 0x72, 0x79, - 0x9e, 0x8b, 0xf9, 0xe0, 0x9f, 0x21, 0x88, 0xc5, 0x1f, 0x2e, 0x09, 0x99, 0x28, 0x7e, 0x6a, 0x29, - 0x59, 0x59, 0xae, 0x5c, 0x1b, 0xed, 0xbd, 0x7a, 0xc5, 0xbe, 0x2a, 0xca, 0x56, 0x50, 0xde, 0x30, - 0x04, 0x32, 0xfb, 0x58, 0x06, 0xfe, 0xac, 0xe9, 0x43, 0x45, 0xf2, 0x01, 0x26, 0x78, 0x4b, 0xcc, - 0xe4, 0xb3, 0x82, 0xfe, 0x2e, 0xa7, 0x7f, 0xea, 0xce, 0xe4, 0x32, 0x8c, 0x01, 0x1e, 0x40, 0x1f, - 0x41, 0x2c, 0xfd, 0xcc, 0x42, 0xa8, 0xa7, 0x21, 0x14, 0x11, 0x29, 0x88, 0x6b, 0x72, 0x10, 0x0a, - 0x1f, 0x2a, 0x21, 0x0f, 0xe4, 0x1a, 0x0f, 0x44, 0xa6, 0x00, 0x07, 0xe4, 0x50, 0x52, 0xa9, 0x22, - 0x18, 0xe6, 0x36, 0xb1, 0x1f, 0x32, 0x8b, 0x1a, 0x7d, 0xc5, 0x60, 0x96, 0x63, 0x60, 0x29, 0x09, - 0x26, 0xfd, 0xe4, 0x33, 0xdd, 0x29, 0x04, 0x53, 0x44, 0xba, 0x2d, 0x3f, 0x85, 0x0f, 0x95, 0x30, - 0x5b, 0x72, 0x32, 0x85, 0x62, 0x30, 0xa9, 0x14, 0xfc, 0x50, 0xd3, 0x8d, 0x90, 0xa2, 0x35, 0x6c, - 0x05, 0x98, 0xef, 0xfb, 0x2e, 0x59, 0xb3, 0x90, 0x6d, 0xe3, 0x16, 0xc3, 0x8e, 0x01, 0x44, 0x34, - 0x88, 0xaf, 0x80, 0x15, 0x38, 0x99, 0x48, 0xf9, 0x0a, 0x08, 0x83, 0xf4, 0xab, 0x13, 0x99, 0x67, - 0x45, 0x10, 0xb9, 0x48, 0x22, 0x2c, 0x2b, 0x16, 0xbe, 0xf8, 0x8c, 0xcf, 0x5d, 0xc2, 0x41, 0x41, - 0x01, 0xa6, 0x0c, 0x52, 0x39, 0x78, 0x4b, 0x1f, 0x28, 0x93, 0xa3, 0x18, 0x13, 0xa3, 0x5f, 0x10, - 0x9b, 0x3b, 0x88, 0xcc, 0x13, 0x2b, 0x70, 0x09, 0x63, 0xd2, 0x8e, 0xcc, 0x13, 0x61, 0xc0, 0x7f, - 0x75, 0x22, 0xb3, 0x27, 0x21, 0xc4, 0x3f, 0x25, 0x32, 0xa9, 0x42, 0xf6, 0x6b, 0x77, 0xbf, 0x9e, - 0x98, 0x43, 0x50, 0x24, 0xc0, 0x65, 0xe0, 0xbb, 0x9a, 0xfe, 0x78, 0xb9, 0xf5, 0x90, 0xb8, 0x6f, - 0x84, 0xd8, 0x72, 0x1d, 0x63, 0x40, 0x14, 0x11, 0xaf, 0xc7, 0x7d, 0xb3, 0x22, 0xc4, 0x73, 0x33, - 0x71, 0xdf, 0x24, 0x5f, 0x72, 0xdf, 0xa4, 0x0a, 0xb5, 0xb8, 0x53, 0xd2, 0xcf, 0x8e, 0xfc, 0x95, - 0x74, 0x4a, 0x8a, 0x95, 0x3b, 0x25, 0xd5, 0x02, 0x1f, 0x69, 0x7a, 0x7f, 0x85, 0x57, 0xe0, 0x19, - 0xe7, 0x04, 0xa3, 0x6f, 0xf2, 0xb9, 0x77, 0x7c, 0x05, 0xae, 0xc0, 0xf9, 0x76, 0x64, 0x1e, 0x0f, - 0x83, 0x15, 0x38, 0xdf, 0x89, 0xcc, 0x9b, 0x29, 0x11, 0x38, 0x2f, 0xcd, 0xae, 0x75, 0xc6, 0x5a, - 0xf4, 0xd6, 0xd5, 0xab, 0x0e, 0x62, 0xe8, 0x0a, 0xdd, 0x21, 0x36, 0x5b, 0xe7, 0x87, 0x35, 0x82, - 0xd9, 0x55, 0x82, 0xb7, 0xb8, 0x94, 0x13, 0x4e, 0x9c, 0xa4, 0x3f, 0x0e, 0xf7, 0xea, 0x0f, 0x61, - 0xb8, 0xbb, 0x5f, 0x8f, 0x59, 0xc0, 0xbe, 0x52, 0x1c, 0x81, 0x07, 0xfe, 0xa1, 0xe9, 0x66, 0x39, - 0x84, 0x96, 0x4f, 0xf9, 0x0e, 0x47, 0xb1, 0x1d, 0x06, 0xd8, 0xdb, 0x31, 0x06, 0x45, 0xfa, 0xfd, - 0xbe, 0x38, 0x41, 0xac, 0xc0, 0x45, 0x9f, 0xb2, 0xb9, 0x0c, 0x6c, 0x47, 0xe6, 0xd9, 0x30, 0x28, - 0xca, 0x3a, 0x91, 0xf9, 0x54, 0x12, 0x64, 0x11, 0x90, 0xe2, 0x6d, 0x20, 0x8f, 0x8a, 0x94, 0x5c, - 0xb5, 0x56, 0xc8, 0x78, 0xe5, 0x29, 0x2c, 0xf8, 0x79, 0xa1, 0x4c, 0x01, 0x5e, 0x2c, 0x86, 0x55, - 0x44, 0xc1, 0xdf, 0x15, 0x11, 0xba, 0xc4, 0x65, 0x2e, 0x3f, 0x47, 0xf0, 0xfd, 0xce, 0xa2, 0xc6, - 0x90, 0x98, 0xc5, 0xdf, 0x13, 0xa7, 0x87, 0x15, 0x38, 0x17, 0xa3, 0x33, 0x1c, 0xe4, 0x09, 0xe3, - 0x4c, 0x18, 0x14, 0x44, 0x59, 0xba, 0x28, 0xc9, 0xe5, 0x64, 0x71, 0x73, 0xac, 0x90, 0xc0, 0xcb, - 0x1e, 0xaa, 0x22, 0xbe, 0x03, 0x71, 0x2b, 0x7e, 0x60, 0x28, 0x51, 0x80, 0x17, 0x8a, 0x01, 0x16, - 0x40, 0xf0, 0xae, 0xa6, 0x0f, 0xa1, 0x90, 0xf9, 0x56, 0xd8, 0x5a, 0x0b, 0x90, 0x83, 0xf3, 0xda, - 0x64, 0xdd, 0x78, 0x5c, 0xc4, 0xb5, 0xc8, 0x4f, 0x40, 0x5c, 0x65, 0x25, 0xd6, 0x48, 0xb7, 0xf5, - 0x57, 0xb3, 0xc3, 0x82, 0x0a, 0x94, 0xa3, 0x99, 0x90, 0x0b, 0xb5, 0xf1, 0x09, 0xa8, 0xf4, 0x06, - 0x9a, 0xfa, 0x50, 0xca, 0x81, 0xf9, 0x56, 0x2b, 0xe0, 0x3d, 0x2e, 0xb6, 0x46, 0x6a, 0x9c, 0x17, - 0x53, 0xe8, 0x06, 0x27, 0x92, 0xa8, 0x2c, 0xfb, 0x8b, 0x01, 0x86, 0x09, 0xde, 0x89, 0xcc, 0xf3, - 0x71, 0x8f, 0x2a, 0xc0, 0x1a, 0x54, 0xda, 0x80, 0x4d, 0x1d, 0x6c, 0x60, 0xdc, 0xb2, 0x18, 0x6e, - 0xb6, 0xfc, 0x00, 0x05, 0x2e, 0xa6, 0xd6, 0xba, 0x71, 0x41, 0x84, 0xfc, 0x2a, 0x9f, 0x97, 0x1c, - 0x5d, 0xce, 0x41, 0x1e, 0xee, 0x25, 0xd1, 0x4a, 0x19, 0x90, 0x8f, 0x46, 0xd7, 0xe5, 0x50, 0x27, - 0xae, 0xc3, 0x8a, 0x17, 0xb0, 0xa3, 0xf7, 0xdb, 0xc8, 0x5e, 0xc7, 0x96, 0xbb, 0x46, 0xfc, 0x00, - 0x3b, 0x56, 0xc3, 0xf5, 0x30, 0x35, 0x2e, 0x8a, 0x10, 0xe7, 0xf8, 0x06, 0x23, 0xe0, 0xb9, 0x18, - 0x9d, 0xe5, 0x60, 0xd6, 0xd1, 0x15, 0xa4, 0xb2, 0x24, 0xb2, 0xa9, 0x0e, 0xab, 0x6e, 0xc0, 0xb7, - 0x35, 0xfd, 0x7c, 0x2b, 0xf0, 0xd7, 0xf8, 0xd9, 0xc2, 0x0a, 0x5b, 0x0e, 0x62, 0x58, 0xae, 0xd7, - 0x9f, 0x10, 0xb1, 0x2f, 0xf3, 0x72, 0x33, 0xd5, 0x5a, 0x11, 0x4a, 0x72, 0x6d, 0x1e, 0x9f, 0x79, - 0xbb, 0xe0, 0x12, 0x9d, 0x17, 0xa5, 0x8e, 0xd0, 0x5e, 0x84, 0xdd, 0x3c, 0x82, 0x77, 0x34, 0x7d, - 0xd0, 0x73, 0x9b, 0x2e, 0xb3, 0x56, 0x11, 0x71, 0xb6, 0x5c, 0x87, 0xad, 0x5b, 0x2e, 0xb1, 0x3c, - 0x44, 0x8c, 0x61, 0xd1, 0x25, 0x0b, 0xe2, 0x2c, 0xc7, 0x35, 0xa6, 0x52, 0x85, 0x39, 0x32, 0x8f, - 0x48, 0x7e, 0xfe, 0xae, 0x62, 0xf7, 0xe9, 0x16, 0x95, 0x2b, 0xf0, 0xb6, 0xa6, 0x83, 0xa6, 0x4b, - 0xac, 0x75, 0xbf, 0x89, 0x2d, 0xc7, 0xa5, 0x1b, 0x56, 0x23, 0xc0, 0xd8, 0x30, 0x47, 0xb4, 0xd1, - 0x53, 0x13, 0x3d, 0x57, 0xe2, 0x8b, 0xae, 0x2b, 0x4b, 0xee, 0x9b, 0x78, 0xea, 0x95, 0x8f, 0x23, - 0xf3, 0x08, 0x5f, 0xd5, 0x4d, 0x97, 0xbc, 0xea, 0x37, 0xf1, 0x8c, 0x4b, 0x37, 0x66, 0x03, 0x8c, - 0xb3, 0xd9, 0x51, 0x92, 0xcb, 0xeb, 0x60, 0xe4, 0x32, 0x27, 0x72, 0x6c, 0x7c, 0xe4, 0x32, 0x2c, - 0x9b, 0x83, 0x7b, 0x9a, 0xde, 0x93, 0xce, 0x77, 0xb1, 0x0b, 0x8c, 0x88, 0x5d, 0xe0, 0x0f, 0xa2, - 0x02, 0x49, 0x27, 0x6d, 0xbc, 0x17, 0x9c, 0x0a, 0xf2, 0xcf, 0x4e, 0x64, 0xce, 0xa4, 0x07, 0x80, - 0x54, 0xa6, 0xd8, 0x17, 0x92, 0x15, 0x40, 0x4b, 0x29, 0xbe, 0x89, 0x19, 0xba, 0xf2, 0x45, 0xea, - 0x13, 0x9e, 0x4a, 0x0b, 0x6e, 0x8b, 0x9f, 0x87, 0x7b, 0xf5, 0xd1, 0x87, 0x75, 0xc5, 0xcb, 0x15, - 0x89, 0x2f, 0xcc, 0xfd, 0x04, 0x1e, 0xf8, 0x7f, 0xbd, 0x0f, 0x79, 0x5b, 0xfc, 0x30, 0x14, 0x1f, - 0xee, 0x09, 0x66, 0xd4, 0x78, 0x52, 0xdc, 0xa9, 0xf1, 0x33, 0xe8, 0x99, 0x18, 0x14, 0x87, 0xe4, - 0x3b, 0x98, 0xf1, 0x89, 0x3f, 0x10, 0x67, 0x98, 0x82, 0xbc, 0x06, 0xcb, 0x8a, 0xe0, 0xdf, 0x9a, - 0x3e, 0xea, 0x6f, 0xe2, 0x60, 0x2b, 0x70, 0x19, 0x4f, 0x1c, 0x4d, 0x9f, 0x61, 0xcb, 0xc1, 0x9b, - 0xae, 0x8d, 0x2d, 0x82, 0x9a, 0x98, 0x5a, 0x3e, 0xb1, 0x92, 0x73, 0x89, 0x51, 0xcb, 0x6f, 0x7b, - 0x86, 0xee, 0xa6, 0x46, 0x50, 0xd8, 0xcc, 0xe0, 0xcd, 0x3b, 0x5c, 0xbd, 0x1d, 0x99, 0x97, 0xfc, - 0x0a, 0xe4, 0xda, 0x58, 0xa0, 0x77, 0xc9, 0x74, 0xec, 0xaa, 0x13, 0x99, 0x2f, 0x09, 0x82, 0x0f, - 0xa1, 0xdb, 0x7d, 0x52, 0xf2, 0x43, 0x55, 0x17, 0x1e, 0xf0, 0x61, 0x58, 0x80, 0xaf, 0xe8, 0xe7, - 0x78, 0x1a, 0xb3, 0x5c, 0xe2, 0xe0, 0x6d, 0x8b, 0xcf, 0xe4, 0x55, 0xcf, 0xb7, 0x37, 0xa8, 0x71, - 0x49, 0x2c, 0x69, 0x3e, 0x69, 0x00, 0x57, 0x98, 0xe3, 0xf8, 0x82, 0x4b, 0xa6, 0x04, 0x9a, 0x5d, - 0xa2, 0x56, 0x21, 0x65, 0xe1, 0x1a, 0x97, 0xa3, 0x50, 0xe1, 0x09, 0xfc, 0x8d, 0x57, 0x9f, 0x04, - 0xd9, 0x1b, 0xd8, 0xb1, 0x88, 0xcf, 0xdc, 0x86, 0x6b, 0xa3, 0xf8, 0x3a, 0xc0, 0xa1, 0x46, 0x5d, - 0x8c, 0xef, 0x7b, 0xbc, 0xbb, 0x07, 0x57, 0x62, 0xa5, 0x3b, 0x92, 0xce, 0xdc, 0x0c, 0xef, 0xed, - 0xc1, 0x50, 0x89, 0x74, 0x22, 0xf3, 0x42, 0x9c, 0xda, 0x55, 0xb0, 0xb8, 0x3a, 0x54, 0x22, 0x9d, - 0xbd, 0x7a, 0x17, 0x8f, 0xbb, 0xfb, 0xf5, 0x2e, 0x2c, 0xa0, 0xd2, 0xc2, 0xa1, 0x00, 0xea, 0xa7, - 0x59, 0x80, 0x1a, 0x0d, 0xd7, 0xb6, 0x6c, 0x0f, 0x51, 0x6a, 0x5c, 0x16, 0xdd, 0xfa, 0x02, 0x3f, - 0xbe, 0x26, 0xc0, 0x34, 0x97, 0x77, 0x22, 0x13, 0xc4, 0x1d, 0x2a, 0x09, 0xb3, 0x7b, 0x93, 0x82, - 0x2a, 0x78, 0x4b, 0xef, 0x4f, 0xba, 0xd8, 0x6a, 0xf8, 0x9e, 0x83, 0x03, 0xab, 0x85, 0xd8, 0xba, - 0xf1, 0x94, 0x58, 0xf5, 0xb7, 0x0f, 0x22, 0xf3, 0xc2, 0x0c, 0x6e, 0x05, 0xd8, 0x46, 0x0c, 0x3b, - 0x33, 0xb1, 0xe2, 0xac, 0xd0, 0x5b, 0x44, 0x6c, 0xbd, 0x1d, 0x99, 0xda, 0x0b, 0xd9, 0x61, 0xd9, - 0x29, 0xc3, 0xcf, 0xfb, 0x4d, 0x97, 0x0f, 0x12, 0xdb, 0xa9, 0x19, 0x1a, 0xec, 0xab, 0xe0, 0x60, - 0x43, 0x3f, 0x4b, 0x31, 0xb3, 0x3c, 0x7f, 0xcb, 0x6a, 0x05, 0xae, 0x1f, 0xb8, 0x6c, 0xc7, 0x78, - 0x5a, 0x2c, 0x8a, 0xc9, 0x76, 0x64, 0xf6, 0x52, 0xcc, 0xe6, 0xfd, 0xad, 0xc5, 0x04, 0xc9, 0x32, - 0x5b, 0x51, 0xdc, 0xf5, 0x58, 0x5e, 0x32, 0x07, 0xef, 0x6b, 0xfa, 0x60, 0x13, 0x6d, 0xa7, 0x61, - 0xda, 0x3e, 0xb1, 0xc3, 0x20, 0xc0, 0xc4, 0xde, 0x31, 0x46, 0x45, 0x3f, 0x52, 0x71, 0xf7, 0x81, - 0xb6, 0x16, 0xd0, 0x76, 0xcc, 0x71, 0x3a, 0x57, 0xe1, 0x5b, 0x7e, 0x53, 0x21, 0xcf, 0xb6, 0x7c, - 0x15, 0x98, 0x76, 0xb9, 0xb8, 0xac, 0x50, 0xfb, 0x85, 0x4a, 0xaf, 0xe0, 0x13, 0x4d, 0xef, 0xb7, - 0x03, 0x44, 0xd7, 0x4b, 0x25, 0xf9, 0x33, 0x62, 0x58, 0x3e, 0x10, 0x25, 0xf9, 0x74, 0x5a, 0x92, - 0xdb, 0x49, 0x49, 0x3e, 0x1b, 0xef, 0xcd, 0xdc, 0x2c, 0x2f, 0x8e, 0x95, 0x69, 0x58, 0xe8, 0x54, - 0xcb, 0x6c, 0x21, 0xe6, 0x73, 0xb9, 0xaf, 0xe2, 0x84, 0x17, 0xeb, 0x76, 0x52, 0xac, 0xd7, 0x1f, - 0xc6, 0x0d, 0x2f, 0xd7, 0xa7, 0xe3, 0x72, 0xbd, 0xe4, 0x2c, 0xf0, 0xc0, 0x8f, 0x35, 0x7d, 0xa8, - 0x1c, 0x5e, 0x7a, 0x4b, 0xf2, 0xac, 0x18, 0x7f, 0xf7, 0x20, 0x32, 0x4f, 0x4e, 0x43, 0xe9, 0x82, - 0xbf, 0xe8, 0xa5, 0x7c, 0xc1, 0xaf, 0x44, 0xbb, 0x4d, 0x8d, 0xdd, 0xfd, 0x7a, 0xee, 0x1b, 0xaa, - 0x3d, 0x83, 0xaf, 0x69, 0xfa, 0x20, 0x65, 0x21, 0xb1, 0x78, 0xe5, 0x84, 0x3c, 0x77, 0x13, 0x5b, - 0xf1, 0xdd, 0x11, 0x35, 0x9e, 0xcb, 0xea, 0xd1, 0x7e, 0xae, 0x71, 0x3b, 0x55, 0x58, 0xe2, 0xf8, - 0x52, 0x56, 0x25, 0x29, 0xb0, 0x62, 0x6d, 0x2d, 0x25, 0xb4, 0x63, 0xe3, 0x37, 0xc7, 0xa0, 0xca, - 0x1b, 0x3f, 0xb2, 0x96, 0x68, 0xf0, 0xbc, 0x4a, 0x8d, 0xe7, 0x05, 0x89, 0xd7, 0x78, 0xa1, 0x56, - 0x30, 0x5b, 0x70, 0x49, 0x5e, 0xda, 0x57, 0x10, 0xb9, 0x46, 0x2c, 0x24, 0xd4, 0x89, 0x31, 0x58, - 0xf5, 0xc3, 0xab, 0xf2, 0x1e, 0xd1, 0x7a, 0xfa, 0xee, 0xf4, 0x82, 0xc8, 0xa1, 0xce, 0x41, 0x64, - 0xf6, 0x42, 0xb4, 0xb5, 0xc4, 0x42, 0xe9, 0xc5, 0xe9, 0x14, 0xcd, 0x3f, 0xb3, 0xbb, 0xa1, 0x5c, - 0xf6, 0xc0, 0x57, 0xb1, 0x92, 0x47, 0x28, 0xfb, 0x03, 0x9b, 0xfa, 0x19, 0x7e, 0x0a, 0x5c, 0x45, - 0x14, 0x5b, 0xf1, 0x13, 0xa0, 0x71, 0x65, 0x44, 0x1b, 0xed, 0x9d, 0xe8, 0x4d, 0xcb, 0xa2, 0x65, - 0x21, 0x15, 0x97, 0x79, 0xbd, 0xa9, 0x6a, 0x2c, 0xcb, 0x32, 0x47, 0x51, 0x5c, 0x1b, 0x09, 0xb0, - 0x18, 0xd2, 0x64, 0x7a, 0xbc, 0xbd, 0x5f, 0xd7, 0x60, 0xc9, 0x14, 0x7c, 0xe7, 0xa8, 0x7e, 0x89, - 0x67, 0x8d, 0x2c, 0x5d, 0xf0, 0x33, 0xa5, 0xed, 0x37, 0xf9, 0x94, 0x0d, 0xf0, 0x1b, 0x21, 0xa6, - 0xcc, 0xda, 0x70, 0x57, 0x8d, 0xab, 0x62, 0x38, 0xfe, 0xa4, 0x25, 0x4f, 0x87, 0x0b, 0x68, 0x7b, - 0x7a, 0x0e, 0xc6, 0xf8, 0x6d, 0x77, 0xaa, 0x1d, 0x99, 0x66, 0x13, 0x6d, 0x67, 0x4b, 0x9c, 0xcd, - 0x25, 0x3e, 0x72, 0x95, 0x6c, 0x17, 0x7c, 0x80, 0x9e, 0x74, 0x1e, 0x7b, 0xa0, 0xcb, 0x07, 0xab, - 0x24, 0x8f, 0x91, 0x25, 0xba, 0xf0, 0x01, 0x66, 0xab, 0xe0, 0x33, 0x4d, 0x1f, 0xcc, 0x5e, 0x44, - 0x3c, 0x24, 0xbf, 0xa1, 0x8e, 0x89, 0x05, 0xfc, 0x21, 0xef, 0x89, 0x81, 0xf4, 0x45, 0x61, 0x7e, - 0xf2, 0x8e, 0xfc, 0x8c, 0x3a, 0x80, 0x14, 0xf2, 0xac, 0x90, 0x56, 0x81, 0xaa, 0x87, 0x2c, 0xa5, - 0x93, 0x2e, 0x72, 0x69, 0xe9, 0x2b, 0x49, 0xc1, 0xdc, 0x0a, 0x49, 0x6f, 0xb0, 0x9b, 0xfa, 0x79, - 0xf1, 0xe8, 0xd1, 0x08, 0x3d, 0x2f, 0xa9, 0x6a, 0x7c, 0x92, 0x1e, 0x51, 0x8d, 0x71, 0x11, 0xe9, - 0x2d, 0x5e, 0x35, 0x70, 0xad, 0xd9, 0xd0, 0xf3, 0x44, 0x3d, 0x72, 0x97, 0x24, 0x87, 0xca, 0x4e, - 0x64, 0x5e, 0x4c, 0xb6, 0x2c, 0x15, 0x5c, 0x83, 0x5d, 0xec, 0xc0, 0x6b, 0xfa, 0xe9, 0x06, 0x46, - 0x2c, 0x0c, 0xb0, 0xd5, 0xf0, 0xd0, 0x1a, 0x35, 0x26, 0xc4, 0xba, 0xbb, 0xcc, 0x77, 0xfa, 0x04, - 0x98, 0xe5, 0xf2, 0xec, 0x81, 0x44, 0x12, 0xd6, 0x60, 0x41, 0x05, 0x6c, 0xe9, 0x43, 0xd2, 0xbb, - 0x48, 0x7c, 0xc6, 0xc1, 0xc4, 0x0f, 0xd7, 0xd6, 0x8d, 0x6b, 0x62, 0xd2, 0xbe, 0x2c, 0xd2, 0x6b, - 0xa6, 0x32, 0xcf, 0x35, 0x5e, 0x11, 0x0a, 0x59, 0xd5, 0xa3, 0x44, 0xb3, 0x8a, 0x42, 0x6d, 0x0c, - 0x36, 0xf4, 0x81, 0x4a, 0xc3, 0x4d, 0xb4, 0x6d, 0x5c, 0x17, 0xad, 0xbe, 0xc4, 0x8b, 0xc1, 0x92, - 0xe1, 0x02, 0xda, 0xee, 0x44, 0xa6, 0xa1, 0x6a, 0x72, 0x01, 0x6d, 0x67, 0xed, 0x29, 0xcc, 0xc0, - 0xbb, 0x47, 0x75, 0x33, 0xbd, 0xec, 0xb1, 0x90, 0xc7, 0x4b, 0x0a, 0xdf, 0x73, 0x2c, 0xe6, 0x51, - 0x8b, 0xe7, 0x0f, 0xd7, 0x27, 0xd4, 0x78, 0x51, 0x8c, 0xd7, 0x47, 0x7c, 0x66, 0x5e, 0x48, 0xaf, - 0x56, 0x26, 0xb9, 0xea, 0x5d, 0xcf, 0x59, 0x9e, 0x5f, 0xfa, 0xbf, 0x44, 0xaf, 0x1d, 0x99, 0x17, - 0xdc, 0xee, 0x70, 0x56, 0xef, 0xdc, 0x47, 0x87, 0xcf, 0xcf, 0xfb, 0xfa, 0xb8, 0x3f, 0xbc, 0xbb, - 0x5f, 0xbf, 0x1f, 0x41, 0x58, 0xb5, 0xf5, 0x68, 0x0a, 0x82, 0x2f, 0xe9, 0x3d, 0x61, 0x8b, 0xb4, - 0xb2, 0x0d, 0xf5, 0xe7, 0xb3, 0x22, 0xec, 0xcf, 0x1d, 0x44, 0xe6, 0xb9, 0xbc, 0x96, 0x5b, 0x59, - 0x24, 0x8b, 0xf9, 0xee, 0x2a, 0xaa, 0xb8, 0xa4, 0xc0, 0x6d, 0x91, 0x56, 0x02, 0x48, 0xf5, 0xdb, - 0xee, 0x7e, 0x5d, 0x6d, 0x6c, 0x68, 0xf0, 0x94, 0x64, 0x02, 0x7e, 0xaa, 0x25, 0xcd, 0xa7, 0xaf, - 0x09, 0xef, 0xcf, 0x8a, 0xe1, 0x7e, 0x5b, 0xe4, 0x83, 0xa2, 0x8b, 0xec, 0x65, 0x41, 0x34, 0x3f, - 0x92, 0x35, 0x2f, 0xbf, 0x08, 0x48, 0x1c, 0xf2, 0xc4, 0x77, 0xbe, 0xbb, 0x16, 0x5f, 0xe0, 0xaa, - 0x56, 0x0c, 0x0d, 0xea, 0xb9, 0x15, 0xf8, 0xb5, 0xa6, 0xf7, 0x0a, 0x9a, 0xf9, 0xbb, 0xc1, 0x2f, - 0x62, 0xa2, 0xdf, 0x10, 0xe7, 0x83, 0xa2, 0x0b, 0xe9, 0x0d, 0x41, 0x50, 0xad, 0x65, 0x54, 0x8b, - 0xb7, 0xfe, 0x4a, 0xb2, 0x17, 0xef, 0xa7, 0xc7, 0x4f, 0x01, 0xea, 0xb6, 0x0c, 0x0d, 0xf6, 0xc8, - 0x96, 0x39, 0xe5, 0xfc, 0x75, 0xe0, 0x83, 0xee, 0x94, 0xa5, 0x97, 0x82, 0x12, 0xe5, 0xe2, 0xdd, - 0x7e, 0x77, 0xca, 0xdd, 0xf4, 0xaa, 0x94, 0x53, 0xcd, 0x94, 0x72, 0xf6, 0x18, 0xd0, 0xd0, 0xe3, - 0x57, 0xc8, 0xac, 0x7c, 0xf8, 0xe5, 0xac, 0xc8, 0x63, 0xff, 0x53, 0xe4, 0x2b, 0x1e, 0xf2, 0xf2, - 0x3a, 0x42, 0x9a, 0x8c, 0x41, 0x8e, 0x14, 0x0f, 0x13, 0x3d, 0x12, 0x42, 0xc5, 0xe5, 0x4d, 0xf5, - 0xde, 0xc4, 0x6a, 0xd9, 0xcc, 0xf8, 0x90, 0x77, 0x91, 0x36, 0xb5, 0x70, 0x10, 0x99, 0x17, 0xf3, - 0x16, 0x17, 0x8a, 0xb7, 0x1e, 0x8b, 0x36, 0x2b, 0xf6, 0x53, 0xb3, 0x82, 0x17, 0x9b, 0x07, 0x55, - 0x05, 0x5e, 0x2b, 0x0d, 0x94, 0x2a, 0x05, 0x6a, 0x23, 0x42, 0x8d, 0x5f, 0xc5, 0xa3, 0xb4, 0x5c, - 0xa2, 0x20, 0xef, 0xb0, 0x4b, 0x5c, 0xb1, 0x44, 0xa1, 0x82, 0x57, 0x87, 0x4a, 0x30, 0xa9, 0xe8, - 0x4d, 0xdd, 0xfe, 0xf8, 0xd3, 0xe1, 0x23, 0xfb, 0x9f, 0x0e, 0x1f, 0xf9, 0xf8, 0x60, 0x58, 0xdb, - 0x3f, 0x18, 0xd6, 0xbe, 0x75, 0x6f, 0xf8, 0xc8, 0x7b, 0xf7, 0x86, 0xb5, 0xfd, 0x7b, 0xc3, 0x47, - 0xfe, 0x7a, 0x6f, 0xf8, 0xc8, 0xeb, 0xcf, 0xac, 0xb9, 0x6c, 0x3d, 0x5c, 0xbd, 0x62, 0xfb, 0xcd, - 0xab, 0x59, 0xfd, 0x2e, 0xfd, 0xca, 0xff, 0x56, 0xb5, 0x7a, 0x42, 0xfc, 0x8f, 0xea, 0xda, 0x7f, - 0x02, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x13, 0xeb, 0x90, 0xb3, 0x25, 0x00, 0x00, + 0x15, 0xce, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x1e, 0x3b, 0xf6, 0x26, 0x4e, 0xbd, 0xee, 0xcd, + 0x4d, 0xeb, 0xb6, 0x69, 0x62, 0x3b, 0x3f, 0x4d, 0x8d, 0x50, 0xf1, 0x4f, 0x4d, 0xdd, 0xd8, 0x8e, + 0x3b, 0xb6, 0x6b, 0x54, 0x84, 0x56, 0xe3, 0xbd, 0x73, 0xed, 0xad, 0xf7, 0xee, 0xde, 0xec, 0xce, + 0xfa, 0xa7, 0x45, 0x50, 0x15, 0x41, 0x79, 0xa3, 0x5c, 0x15, 0x90, 0x40, 0xaa, 0x8a, 0x00, 0x89, + 0x52, 0x8a, 0x90, 0x90, 0x90, 0x40, 0x42, 0x54, 0x48, 0x48, 0x15, 0x3c, 0xf8, 0x3e, 0x21, 0x24, + 0xca, 0xa2, 0x3a, 0x7d, 0xba, 0x0f, 0x3c, 0xdc, 0x47, 0xf3, 0x82, 0x66, 0xf6, 0x6f, 0x76, 0x77, + 0xd6, 0xce, 0xdb, 0xdd, 0xf3, 0x9d, 0x39, 0x73, 0xbe, 0xf9, 0x39, 0x73, 0xce, 0xcc, 0x95, 0x2f, + 0x9b, 0xc6, 0xea, 0x35, 0xdd, 0xb6, 0xaa, 0xc6, 0xda, 0x35, 0xbb, 0x4e, 0x0c, 0xdb, 0x72, 0x83, + 0x2f, 0xcf, 0x41, 0xf4, 0xeb, 0x6a, 0xdd, 0xb1, 0x89, 0x0d, 0x4e, 0x04, 0xc2, 0x0b, 0x7d, 0x9c, + 0x3a, 0xf1, 0x2c, 0xc3, 0x5a, 0x0b, 0x14, 0x2e, 0x9c, 0xe3, 0x00, 0xd7, 0x78, 0x1d, 0x87, 0xe2, + 0x93, 0x78, 0x9b, 0x04, 0x3f, 0x4b, 0xef, 0x2d, 0xca, 0x3d, 0x77, 0x83, 0x1e, 0x26, 0xf9, 0x1e, + 0xc0, 0x7b, 0x92, 0x7c, 0xd6, 0x34, 0x5c, 0x82, 0x2d, 0x0d, 0x55, 0x2a, 0x0e, 0x76, 0x5d, 0xec, + 0x2a, 0xd2, 0xe0, 0xb1, 0xa1, 0x93, 0x13, 0xee, 0x9e, 0xaf, 0x02, 0x88, 0xb6, 0x66, 0x19, 0x3c, + 0x1e, 0xa1, 0x2d, 0x5f, 0x3d, 0x63, 0xa6, 0x45, 0x6d, 0x5f, 0xbd, 0xbc, 0x5d, 0x33, 0xc7, 0x4a, + 0x29, 0x79, 0x69, 0xb0, 0x82, 0xab, 0xc8, 0x33, 0xc9, 0x58, 0x29, 0xfc, 0x51, 0xda, 0xdf, 0x2d, + 0x3f, 0x1c, 0xfe, 0x6e, 0x34, 0xcb, 0x02, 0xe3, 0x30, 0x6b, 0x1a, 0xfc, 0x57, 0x92, 0x95, 0x35, + 0xd3, 0x5e, 0x45, 0xa6, 0x56, 0x31, 0x5c, 0xdd, 0xde, 0xc4, 0xce, 0x8e, 0xe6, 0x62, 0x67, 0x13, + 0x3b, 0xae, 0x72, 0x94, 0x39, 0xfa, 0x3b, 0x69, 0xcf, 0x57, 0xbb, 0x21, 0xda, 0xfa, 0x32, 0xd3, + 0x1b, 0xb7, 0xac, 0xc5, 0x00, 0x6f, 0xf9, 0xea, 0xb9, 0xb5, 0x48, 0x66, 0x7b, 0x96, 0x8e, 0x43, + 0xa0, 0xed, 0xab, 0x57, 0x98, 0xc3, 0x22, 0x54, 0xe0, 0x77, 0x6b, 0xb7, 0xdc, 0x23, 0x52, 0x6d, + 0xef, 0x96, 0xc5, 0x1d, 0xa4, 0x89, 0x8a, 0x7c, 0x83, 0xbd, 0x41, 0xc3, 0xa9, 0x88, 0x54, 0x28, + 0x07, 0x9f, 0x8b, 0x08, 0x63, 0x0b, 0xad, 0x9a, 0xb8, 0xa2, 0x1c, 0x1b, 0x94, 0x86, 0x1e, 0x99, + 0xf8, 0x80, 0x12, 0x3e, 0x1b, 0x5b, 0x7c, 0x21, 0x00, 0xf3, 0x6c, 0x43, 0xa0, 0xed, 0xab, 0x4f, + 0x09, 0xd8, 0x86, 0x28, 0x47, 0x97, 0x38, 0x1e, 0xa6, 0x5c, 0x0b, 0xcc, 0x14, 0x01, 0xfb, 0xbb, + 0xe5, 0x87, 0x68, 0xd3, 0x46, 0xb3, 0x9c, 0x73, 0x2a, 0x47, 0x33, 0x94, 0x83, 0x4f, 0x25, 0xb9, + 0xcf, 0xb4, 0x75, 0x21, 0xcb, 0x87, 0x18, 0xcb, 0x9f, 0x51, 0x96, 0x67, 0x66, 0xa9, 0x4e, 0x8a, + 0x64, 0x8f, 0x19, 0x8a, 0x32, 0x1c, 0x9f, 0x0c, 0x96, 0xa0, 0x00, 0x14, 0x50, 0x14, 0x1b, 0x29, + 0x90, 0x73, 0x04, 0xb3, 0xfe, 0xc0, 0x73, 0xac, 0x41, 0x8e, 0xde, 0xdf, 0x25, 0xb9, 0x3b, 0xa0, + 0x87, 0x42, 0x5b, 0x5a, 0xdd, 0x76, 0x88, 0x72, 0x7c, 0x50, 0x1a, 0x3a, 0x3e, 0xf1, 0x63, 0x4a, + 0xad, 0x23, 0x32, 0xb5, 0x60, 0x3b, 0xa4, 0xe5, 0xab, 0x5d, 0xa9, 0xae, 0xa9, 0xb0, 0xed, 0xab, + 0x4f, 0xe4, 0x49, 0x51, 0x84, 0x63, 0x34, 0x3a, 0x32, 0x3c, 0xfa, 0x6c, 0x69, 0xdf, 0x57, 0x8f, + 0x19, 0x16, 0x69, 0xed, 0x96, 0x05, 0x66, 0x44, 0xc2, 0xfd, 0xdd, 0xf2, 0x71, 0xd6, 0xb4, 0xd1, + 0x2c, 0xa7, 0x3c, 0x81, 0x79, 0x5d, 0xf0, 0xad, 0xa3, 0xf2, 0x60, 0x86, 0x4d, 0xcd, 0x33, 0x89, + 0xa1, 0x23, 0x97, 0x44, 0x71, 0x43, 0x39, 0x31, 0x28, 0x0d, 0x9d, 0x9c, 0xf8, 0x03, 0xa5, 0xd6, + 0x19, 0x19, 0x9c, 0x9b, 0xa4, 0x3b, 0xb9, 0xe5, 0xab, 0xdd, 0x29, 0xa3, 0x81, 0xb8, 0xed, 0xab, + 0xb7, 0xf2, 0xf4, 0x02, 0x8c, 0x23, 0xf8, 0xd5, 0x6a, 0x75, 0x64, 0x74, 0x6c, 0xec, 0xf6, 0xf5, + 0xdb, 0x37, 0xbe, 0x36, 0x16, 0xb0, 0x6d, 0xed, 0x96, 0x85, 0x06, 0xc5, 0xe2, 0xfd, 0xdd, 0x32, + 0xc8, 0x1b, 0x69, 0x34, 0xcb, 0x19, 0x37, 0xe1, 0xa3, 0xe9, 0xc6, 0x11, 0xc3, 0x30, 0x18, 0x81, + 0xbb, 0xf2, 0xe9, 0x1a, 0xda, 0xd6, 0x5c, 0x6c, 0x55, 0xb4, 0x8d, 0xd5, 0xba, 0xab, 0x3c, 0xcc, + 0x26, 0xf3, 0xe9, 0x96, 0xaf, 0x9e, 0xaa, 0xa1, 0xed, 0x45, 0x6c, 0x55, 0xee, 0xac, 0xd6, 0x69, + 0x70, 0xe9, 0x62, 0xb4, 0x38, 0x59, 0x34, 0x3f, 0x90, 0x57, 0x8c, 0x0c, 0x3a, 0x58, 0xdf, 0x0c, + 0x0c, 0x3e, 0x92, 0x32, 0x08, 0xb1, 0xbe, 0x99, 0x35, 0x18, 0xc9, 0x52, 0x06, 0x23, 0x21, 0xf8, + 0xbd, 0x24, 0xf7, 0x39, 0x58, 0xb7, 0x2d, 0x0b, 0xeb, 0x34, 0xbc, 0x6b, 0x86, 0x45, 0xb0, 0xb3, + 0x89, 0x4c, 0xcd, 0x55, 0x4e, 0x32, 0xdb, 0xdf, 0x60, 0x41, 0x3d, 0x52, 0x99, 0x09, 0xe1, 0x45, + 0x1a, 0x3b, 0xf8, 0x86, 0x31, 0xd0, 0xf6, 0xd5, 0x21, 0xd6, 0xb7, 0x10, 0xe5, 0x66, 0xe9, 0xd6, + 0x70, 0xe4, 0xd2, 0xfe, 0x6e, 0xf9, 0xe8, 0xad, 0x61, 0x16, 0xdf, 0x73, 0xfd, 0x40, 0x71, 0x2f, + 0xa0, 0x2a, 0x77, 0x3a, 0xd8, 0x44, 0x3b, 0x6e, 0x1c, 0x03, 0x64, 0x16, 0x03, 0x9e, 0x6f, 0xf9, + 0xea, 0xe9, 0x00, 0x49, 0x36, 0x7a, 0x29, 0x74, 0x88, 0x93, 0x66, 0x77, 0x78, 0xb4, 0x63, 0x61, + 0xba, 0x31, 0x78, 0xeb, 0xa8, 0xdc, 0x1f, 0x76, 0x14, 0x3b, 0x92, 0x0c, 0x52, 0x4d, 0x39, 0xc5, + 0x06, 0xe9, 0x2f, 0x74, 0x0d, 0xf7, 0x41, 0xaa, 0x97, 0xa3, 0x30, 0xd7, 0xf2, 0xd5, 0x3e, 0x47, + 0x0c, 0xc5, 0x81, 0xb6, 0x00, 0xe7, 0xbc, 0x1c, 0x19, 0xe6, 0xb6, 0x6c, 0xa1, 0xbd, 0x62, 0x88, + 0x0e, 0xf2, 0x08, 0x1d, 0xe4, 0x22, 0x37, 0xa1, 0x12, 0xf0, 0xcc, 0x23, 0x60, 0x55, 0x3e, 0xed, + 0x12, 0xe4, 0x10, 0x6d, 0xd5, 0xb1, 0xb7, 0x5c, 0xec, 0x28, 0x1d, 0x6c, 0xac, 0xbf, 0xd8, 0xf2, + 0xd5, 0x0e, 0x06, 0x4c, 0x04, 0xf2, 0xb6, 0xaf, 0x3e, 0xc6, 0xe8, 0xf0, 0xc2, 0xc2, 0x91, 0x4e, + 0x35, 0x05, 0xbf, 0x90, 0xe4, 0x73, 0x16, 0x22, 0x1a, 0x71, 0x10, 0x3d, 0xd5, 0x90, 0x19, 0x4f, + 0x6c, 0x27, 0xeb, 0xec, 0xde, 0x9e, 0xaf, 0xca, 0xf3, 0xe3, 0x4b, 0x49, 0x58, 0x97, 0x2d, 0x44, + 0x92, 0x39, 0x56, 0x59, 0xc7, 0x89, 0x48, 0x10, 0xc2, 0xf9, 0x06, 0xa9, 0x2f, 0x2e, 0x5c, 0x73, + 0x5d, 0xc0, 0x6e, 0x0b, 0x91, 0xa5, 0xc8, 0x9d, 0x68, 0x41, 0xfc, 0x31, 0xe7, 0xa7, 0x89, 0x91, + 0x8b, 0xb5, 0x9a, 0x72, 0x86, 0x2d, 0x85, 0xef, 0xd0, 0xa5, 0x70, 0x72, 0x7e, 0x7c, 0x69, 0x96, + 0x8a, 0xe9, 0xe4, 0x9f, 0xb1, 0x10, 0x09, 0x3e, 0x0c, 0xcb, 0x23, 0x2c, 0xf9, 0x29, 0x45, 0xce, + 0xf2, 0x72, 0xe1, 0xde, 0x68, 0xed, 0x96, 0x73, 0xed, 0xf3, 0xa2, 0x78, 0x07, 0x25, 0x1d, 0x43, + 0xc0, 0x7b, 0x1f, 0xc8, 0xc0, 0xdf, 0x24, 0xb9, 0x2f, 0xed, 0xbc, 0x83, 0x2d, 0xbc, 0xc5, 0x56, + 0xf2, 0x59, 0xe6, 0x7e, 0x83, 0xba, 0x7f, 0x6a, 0x7e, 0x7c, 0x09, 0x06, 0x00, 0x25, 0xd0, 0x65, + 0x21, 0x12, 0x7d, 0xc6, 0x14, 0xca, 0x11, 0x85, 0x34, 0xc2, 0x91, 0xb8, 0xce, 0x93, 0x10, 0xd8, + 0x10, 0x09, 0x29, 0x91, 0xeb, 0x94, 0x08, 0xef, 0x02, 0xec, 0xe1, 0xa9, 0x44, 0x52, 0x01, 0x19, + 0x62, 0xd4, 0xb0, 0xed, 0x11, 0xcd, 0x55, 0xba, 0xd2, 0x64, 0x96, 0x02, 0x60, 0x31, 0x24, 0x13, + 0x7d, 0xd2, 0x95, 0x5e, 0x49, 0x91, 0x49, 0x23, 0x45, 0xdb, 0x4f, 0x60, 0x43, 0x24, 0x8c, 0xb7, + 0x1c, 0xef, 0x42, 0x9a, 0x4c, 0x24, 0x05, 0x3f, 0x91, 0x64, 0xc5, 0x73, 0xd1, 0x1a, 0xd6, 0x1c, + 0x4c, 0xcf, 0x7d, 0xc3, 0x5a, 0xd3, 0x90, 0xae, 0xe3, 0x3a, 0xc1, 0x15, 0x05, 0x30, 0x36, 0x88, + 0xee, 0x80, 0x65, 0x38, 0x1e, 0x4a, 0xe9, 0x0e, 0xf0, 0x9c, 0xe8, 0xab, 0xed, 0xab, 0x67, 0x19, + 0x89, 0x44, 0xc4, 0x39, 0xcc, 0x2b, 0xa6, 0xbe, 0xe8, 0x8a, 0x4f, 0x4c, 0xc2, 0x5e, 0xe6, 0x02, + 0x8c, 0x3c, 0x88, 0xe4, 0xe0, 0x0d, 0xb9, 0x27, 0xeb, 0x9c, 0x8b, 0xb1, 0xa5, 0x74, 0x33, 0xc7, + 0x66, 0xf6, 0x7c, 0xf5, 0xc4, 0x32, 0x5c, 0xc4, 0xd8, 0x6a, 0xf9, 0xea, 0x09, 0xcf, 0xa1, 0xbf, + 0xda, 0xbe, 0xda, 0x11, 0x3a, 0x44, 0x3f, 0x39, 0x67, 0x22, 0x85, 0xf8, 0x57, 0xa3, 0x59, 0x0e, + 0x9b, 0x43, 0x90, 0x76, 0x80, 0xca, 0xc0, 0x0f, 0x24, 0xf9, 0x7c, 0xb6, 0x77, 0xcf, 0x32, 0xee, + 0x79, 0x58, 0x33, 0x2a, 0x4a, 0x0f, 0x4b, 0x22, 0x5e, 0x0d, 0xc6, 0x66, 0x99, 0x89, 0x67, 0xa6, + 0x82, 0xb1, 0x09, 0xbf, 0xf8, 0xb1, 0x89, 0x14, 0x4a, 0xc1, 0xa0, 0x44, 0x9f, 0x6d, 0xfe, 0x2b, + 0x1c, 0x94, 0x08, 0xcb, 0x0e, 0x4a, 0xa4, 0x05, 0x3e, 0x96, 0xe4, 0xee, 0x9c, 0x5f, 0x8e, 0xa9, + 0x9c, 0x63, 0x1e, 0x7d, 0x8f, 0xae, 0xbd, 0xe3, 0xcb, 0x70, 0x19, 0xce, 0xb6, 0x7c, 0xf5, 0xb8, + 0xe7, 0x2c, 0xc3, 0xd9, 0xb6, 0xaf, 0xde, 0x8e, 0x1c, 0x81, 0xb3, 0xdc, 0xea, 0x5a, 0x27, 0xa4, + 0xee, 0x8e, 0x5d, 0xbb, 0x56, 0x41, 0x04, 0x5d, 0x75, 0x77, 0x2c, 0x9d, 0xac, 0xd3, 0x62, 0xcd, + 0xc2, 0xe4, 0x9a, 0x85, 0xb7, 0xa8, 0x94, 0x3a, 0x1c, 0x1a, 0x89, 0x7e, 0xec, 0xef, 0x96, 0x1f, + 0xa0, 0x61, 0xa3, 0x59, 0x0e, 0xbc, 0x80, 0x5d, 0x19, 0x1e, 0x8e, 0x09, 0xfe, 0x23, 0xc9, 0x6a, + 0x96, 0x42, 0xdd, 0x76, 0xe9, 0x09, 0xe7, 0x62, 0xdd, 0x73, 0xb0, 0xb9, 0xa3, 0xf4, 0xb2, 0xf0, + 0xfb, 0x23, 0x56, 0x41, 0x2c, 0xc3, 0x05, 0xdb, 0x25, 0x33, 0x31, 0xd8, 0xf2, 0xd5, 0xb3, 0x9e, + 0x93, 0x96, 0xb5, 0x7d, 0xf5, 0xf1, 0x90, 0x64, 0x1a, 0xe0, 0xf8, 0x56, 0x91, 0xe9, 0xb2, 0x90, + 0x9c, 0x6f, 0x2d, 0x90, 0xd1, 0xcc, 0x93, 0xb5, 0xa0, 0xf5, 0x42, 0xd6, 0x05, 0x78, 0x31, 0x4d, + 0x2b, 0x8d, 0x82, 0x7f, 0x0b, 0x18, 0x1a, 0x96, 0x41, 0x0c, 0x5a, 0x47, 0xd0, 0xf3, 0x4e, 0x73, + 0x95, 0x3e, 0xb6, 0x8a, 0x7f, 0xc8, 0xaa, 0x87, 0x65, 0x38, 0x13, 0xa0, 0x53, 0x14, 0xa4, 0x01, + 0xe3, 0x8c, 0xe7, 0xa4, 0x44, 0x71, 0xb8, 0xc8, 0xc8, 0xf9, 0x60, 0x71, 0x7b, 0x38, 0x15, 0xc0, + 0xb3, 0x16, 0xf2, 0x22, 0x7a, 0x02, 0xd1, 0x56, 0xb4, 0x60, 0xc8, 0xb8, 0x00, 0xfb, 0xd3, 0x04, + 0x53, 0x20, 0x78, 0x5b, 0x92, 0xfb, 0x90, 0x47, 0x6c, 0xcd, 0xab, 0xaf, 0x39, 0xa8, 0x82, 0x93, + 0xdc, 0x64, 0x5d, 0x39, 0xcf, 0x78, 0x2d, 0xd0, 0x0a, 0x88, 0xaa, 0x2c, 0x07, 0x1a, 0xd1, 0xb1, + 0xfe, 0x62, 0x5c, 0x2c, 0x88, 0x40, 0x9e, 0xcd, 0x28, 0x9f, 0xa8, 0x8d, 0x8c, 0x42, 0xa1, 0x35, + 0x50, 0x93, 0xfb, 0x22, 0x1f, 0x88, 0xad, 0xd5, 0x1d, 0x3a, 0xe2, 0xec, 0x68, 0x74, 0x95, 0x0b, + 0x6c, 0x09, 0xdd, 0xa2, 0x8e, 0x84, 0x2a, 0x4b, 0xf6, 0x82, 0x83, 0x61, 0x88, 0xb7, 0x7d, 0xf5, + 0x42, 0x30, 0xa2, 0x02, 0xb0, 0x04, 0x85, 0x6d, 0xc0, 0xa6, 0x0c, 0x36, 0x30, 0xae, 0x6b, 0x04, + 0xd7, 0xea, 0xb6, 0x83, 0x1c, 0x03, 0xbb, 0xda, 0xba, 0xd2, 0xcf, 0x28, 0xbf, 0x48, 0xd7, 0x25, + 0x45, 0x97, 0x12, 0x90, 0xd2, 0xbd, 0xc4, 0x7a, 0xc9, 0x02, 0x7c, 0x69, 0x74, 0x83, 0xa7, 0x3a, + 0x7a, 0x03, 0xe6, 0xac, 0x80, 0x1d, 0xb9, 0x5b, 0x47, 0xfa, 0x3a, 0xd6, 0x8c, 0x35, 0xcb, 0x76, + 0x70, 0x45, 0xab, 0x1a, 0x26, 0x76, 0x95, 0x8b, 0x8c, 0xe2, 0x0c, 0x3d, 0x60, 0x18, 0x3c, 0x13, + 0xa0, 0xd3, 0x14, 0x8c, 0x07, 0x3a, 0x87, 0xe4, 0xb6, 0x44, 0xbc, 0xd4, 0x61, 0xde, 0x0c, 0xf8, + 0xbe, 0x24, 0x5f, 0xa8, 0x3b, 0xf6, 0x1a, 0xad, 0x2d, 0x34, 0xaf, 0x5e, 0x41, 0x04, 0xf3, 0xf9, + 0xfa, 0xa3, 0x8c, 0xfb, 0x12, 0x4d, 0x37, 0x23, 0xad, 0x65, 0xa6, 0xc4, 0xe7, 0xe6, 0x41, 0xcd, + 0x5b, 0x80, 0x73, 0xee, 0xdc, 0xe4, 0x06, 0x42, 0xba, 0x09, 0x8b, 0x2c, 0x82, 0xb7, 0x24, 0xb9, + 0xd7, 0x34, 0x6a, 0x06, 0xd1, 0x56, 0x91, 0x55, 0xd9, 0x32, 0x2a, 0x64, 0x5d, 0x33, 0x2c, 0xcd, + 0x44, 0x96, 0x32, 0xc0, 0x86, 0x64, 0x8e, 0xd5, 0x72, 0x54, 0x63, 0x22, 0x52, 0x98, 0xb1, 0x66, + 0x91, 0x95, 0xd4, 0xdf, 0x79, 0xec, 0x80, 0x61, 0x11, 0x99, 0x02, 0x6f, 0x4a, 0x32, 0xa8, 0x19, + 0x96, 0xb6, 0x6e, 0xd7, 0xb0, 0x56, 0x31, 0xdc, 0x0d, 0xad, 0xea, 0x60, 0xac, 0xa8, 0x83, 0xd2, + 0xd0, 0xa9, 0xd1, 0x8e, 0xab, 0xc1, 0x45, 0xd7, 0xd5, 0x45, 0xe3, 0x75, 0x3c, 0xf1, 0xc2, 0x27, + 0xbe, 0x7a, 0x84, 0xee, 0xea, 0x9a, 0x61, 0xbd, 0x68, 0xd7, 0xf0, 0x94, 0xe1, 0x6e, 0x4c, 0x3b, + 0x18, 0xc7, 0xab, 0x23, 0x23, 0xe7, 0xf7, 0xc1, 0xe0, 0x65, 0xea, 0xc8, 0xb1, 0x91, 0xc1, 0xcb, + 0x30, 0xdb, 0x1c, 0xdc, 0x97, 0xe4, 0x8e, 0x68, 0xbd, 0xb3, 0x53, 0x60, 0x90, 0x9d, 0x02, 0x7f, + 0x66, 0x19, 0x48, 0xb4, 0x68, 0x83, 0xb3, 0xe0, 0x94, 0x93, 0x7c, 0xb6, 0x7d, 0x75, 0x2a, 0x2a, + 0x00, 0x22, 0x99, 0xe0, 0x5c, 0x08, 0x77, 0x80, 0x9b, 0x09, 0xf1, 0x35, 0x4c, 0xd0, 0xd5, 0xd7, + 0x5c, 0xdb, 0xa2, 0xa1, 0x34, 0x65, 0x36, 0xfd, 0xb9, 0xbf, 0x5b, 0x1e, 0x7a, 0x50, 0x53, 0x34, + 0x5d, 0xe1, 0xfc, 0x85, 0x89, 0x1d, 0xc7, 0x04, 0x2b, 0x72, 0x17, 0x32, 0xb7, 0x68, 0x31, 0x14, + 0x14, 0xf7, 0x16, 0x26, 0xae, 0xf2, 0x18, 0xbb, 0x53, 0xa3, 0x35, 0xe8, 0x99, 0x00, 0x64, 0x45, + 0xf2, 0x3c, 0x26, 0x74, 0xe1, 0xf7, 0x04, 0x11, 0x26, 0x25, 0x2f, 0xc1, 0xac, 0x22, 0xf8, 0x9f, + 0x24, 0x0f, 0xd9, 0x9b, 0xd8, 0xd9, 0x72, 0x0c, 0x42, 0x03, 0x47, 0xcd, 0x26, 0x58, 0xab, 0xe0, + 0x4d, 0x43, 0xc7, 0x9a, 0x85, 0x6a, 0xd8, 0xd5, 0x6c, 0x4b, 0x0b, 0xeb, 0x12, 0xa5, 0x94, 0xdc, + 0xf6, 0xf4, 0xdd, 0x8d, 0x1a, 0x41, 0xd6, 0x66, 0x0a, 0x6f, 0xce, 0x53, 0xf5, 0x96, 0xaf, 0x5e, + 0xb2, 0x73, 0x90, 0xa1, 0x63, 0x86, 0xde, 0xb5, 0x26, 0x03, 0x53, 0x6d, 0x5f, 0x7d, 0x8e, 0x39, + 0xf8, 0x00, 0xba, 0xc5, 0x8b, 0x92, 0x16, 0x55, 0x05, 0x7e, 0xc0, 0x07, 0xf1, 0x02, 0x7c, 0x53, + 0x3e, 0x47, 0xc3, 0x98, 0x66, 0x58, 0x15, 0xbc, 0xad, 0xd1, 0x95, 0xbc, 0x6a, 0xda, 0xfa, 0x86, + 0xab, 0x5c, 0x62, 0x5b, 0x9a, 0x2e, 0x1a, 0x40, 0x15, 0x66, 0x28, 0x3e, 0x67, 0x58, 0x13, 0x0c, + 0x8d, 0x2f, 0x51, 0xf3, 0x90, 0x30, 0x71, 0x0d, 0xd2, 0x51, 0x28, 0xb0, 0x04, 0xfe, 0x45, 0xb3, + 0x4f, 0x0b, 0xe9, 0x1b, 0xb8, 0xa2, 0x59, 0x36, 0x31, 0xaa, 0x86, 0x8e, 0x82, 0xeb, 0x80, 0x8a, + 0xab, 0x94, 0xd9, 0xfc, 0xbe, 0x4f, 0x87, 0xbb, 0x77, 0x39, 0x50, 0x9a, 0xe7, 0x74, 0x66, 0xa6, + 0xe8, 0x68, 0xf7, 0x7a, 0x42, 0xa4, 0xed, 0xab, 0xfd, 0x41, 0x68, 0x17, 0xc1, 0xec, 0xea, 0x50, + 0x88, 0xb4, 0x77, 0xcb, 0x05, 0x16, 0x1b, 0xcd, 0x72, 0x81, 0x17, 0x50, 0xd8, 0xa2, 0xe2, 0x02, + 0x28, 0x9f, 0x26, 0x0e, 0xaa, 0x56, 0x0d, 0x5d, 0xd3, 0x4d, 0xe4, 0xba, 0xca, 0x65, 0x36, 0xac, + 0xcf, 0xd0, 0xf2, 0x35, 0x04, 0x26, 0xa9, 0xbc, 0xed, 0xab, 0x20, 0x18, 0x50, 0x4e, 0x18, 0xdf, + 0x9b, 0xa4, 0x54, 0xc1, 0x1b, 0x72, 0x77, 0x38, 0xc4, 0x5a, 0xd5, 0x36, 0x2b, 0xd8, 0xd1, 0xea, + 0x88, 0xac, 0x2b, 0x8f, 0xb3, 0x5d, 0x7f, 0x67, 0xcf, 0x57, 0xfb, 0xa7, 0x70, 0xdd, 0xc1, 0x3a, + 0x22, 0xb8, 0x32, 0x15, 0x28, 0x4e, 0x33, 0xbd, 0x05, 0x44, 0xd6, 0x5b, 0xbe, 0x2a, 0x3d, 0x13, + 0x17, 0xcb, 0x95, 0x2c, 0x7c, 0xc5, 0xae, 0x19, 0x74, 0x92, 0xc8, 0x4e, 0x49, 0x91, 0x60, 0x57, + 0x0e, 0x07, 0x1b, 0xf2, 0x59, 0x17, 0x13, 0xcd, 0xb4, 0xb7, 0xb4, 0xba, 0x63, 0xd8, 0x8e, 0x41, + 0x76, 0x94, 0x27, 0xd8, 0xa6, 0x18, 0x6f, 0xf9, 0x6a, 0xa7, 0x8b, 0xc9, 0xac, 0xbd, 0xb5, 0x10, + 0x22, 0x71, 0x64, 0x4b, 0x8b, 0x0b, 0xcb, 0xf2, 0x4c, 0x73, 0xf0, 0x81, 0x24, 0xf7, 0xd6, 0xd0, + 0x76, 0x44, 0x53, 0xb7, 0x2d, 0xdd, 0x73, 0x1c, 0x6c, 0xe9, 0x3b, 0xca, 0x10, 0x1b, 0x47, 0x97, + 0xdd, 0x7d, 0xa0, 0xad, 0x39, 0xb4, 0x1d, 0xf8, 0x38, 0x99, 0xa8, 0xd0, 0x23, 0xbf, 0x26, 0x90, + 0xc7, 0x47, 0xbe, 0x08, 0x8c, 0x86, 0x9c, 0x5d, 0x56, 0x88, 0xed, 0x42, 0xa1, 0x55, 0xf0, 0xa9, + 0x24, 0x77, 0xeb, 0x0e, 0x72, 0xd7, 0x33, 0x29, 0xf9, 0x93, 0x6c, 0x5a, 0x3e, 0x64, 0x29, 0xf9, + 0x64, 0x94, 0x92, 0xeb, 0x61, 0x4a, 0x3e, 0x1d, 0x9c, 0xcd, 0xb4, 0x59, 0x92, 0x1c, 0x0b, 0xc3, + 0x30, 0xd3, 0xc9, 0xa7, 0xd9, 0x4c, 0x4c, 0xd7, 0x72, 0x57, 0xce, 0x08, 0x4d, 0xd6, 0xf5, 0x30, + 0x59, 0x2f, 0x3f, 0x88, 0x19, 0x9a, 0xae, 0x4f, 0x06, 0xe9, 0x7a, 0xc6, 0x98, 0x63, 0x82, 0x9f, + 0x4a, 0x72, 0x5f, 0x96, 0x5e, 0x74, 0x4b, 0xf2, 0x14, 0x9b, 0x7f, 0x63, 0xcf, 0x57, 0x4f, 0x4e, + 0x42, 0xee, 0x82, 0x3f, 0x6d, 0x25, 0x7b, 0xc1, 0x2f, 0x44, 0x8b, 0x96, 0x46, 0xa3, 0x59, 0x4e, + 0x6c, 0x43, 0xb1, 0x65, 0xf0, 0x6d, 0x49, 0xee, 0x75, 0x89, 0x67, 0x69, 0x34, 0x73, 0x42, 0xa6, + 0xb1, 0x89, 0xb5, 0xe0, 0xee, 0xc8, 0x55, 0x9e, 0x8e, 0xf3, 0xd1, 0x6e, 0xaa, 0x71, 0x27, 0x52, + 0x58, 0xa4, 0xf8, 0x62, 0x9c, 0x25, 0x09, 0xb0, 0x74, 0x6e, 0xcd, 0x05, 0xb4, 0x63, 0x23, 0xb7, + 0x87, 0xa1, 0xc8, 0x1a, 0x2d, 0x59, 0x33, 0x6e, 0xd0, 0xb8, 0xea, 0x2a, 0x57, 0x98, 0x13, 0x2f, + 0xd1, 0x44, 0x2d, 0xd5, 0x6c, 0xce, 0xb0, 0x92, 0xd4, 0x3e, 0x87, 0xf0, 0x39, 0x62, 0x2a, 0xa0, + 0x8e, 0x0e, 0xc3, 0xbc, 0x1d, 0x9a, 0x95, 0x77, 0xb0, 0xde, 0xa3, 0x77, 0xa7, 0x67, 0x58, 0x0c, + 0xad, 0xec, 0xf9, 0x6a, 0x27, 0x44, 0x5b, 0x8b, 0xc4, 0xe3, 0x5e, 0x9c, 0x4e, 0xb9, 0xc9, 0x67, + 0x7c, 0x37, 0x94, 0xc8, 0x0e, 0x7d, 0x15, 0xcb, 0x58, 0x84, 0xbc, 0x3d, 0xb0, 0x29, 0x9f, 0xa1, + 0x55, 0xe0, 0x2a, 0x72, 0xb1, 0x16, 0x3c, 0x01, 0x2a, 0x57, 0x07, 0xa5, 0xa1, 0xce, 0xd1, 0xce, + 0x28, 0x2d, 0x5a, 0x62, 0x52, 0x76, 0x99, 0xd7, 0x19, 0xa9, 0x06, 0xb2, 0x38, 0x72, 0xa4, 0xc5, + 0xa5, 0x41, 0x07, 0xb3, 0x29, 0x0d, 0x97, 0xc7, 0x9b, 0xcd, 0xb2, 0x04, 0x33, 0x4d, 0xc1, 0xbb, + 0x47, 0xe5, 0x4b, 0x34, 0x6a, 0xc4, 0xe1, 0x82, 0xd6, 0x94, 0xba, 0x5d, 0xa3, 0x4b, 0xd6, 0xc1, + 0xf7, 0x3c, 0xec, 0x12, 0x6d, 0xc3, 0x58, 0x55, 0xae, 0xb1, 0xe9, 0xf8, 0xab, 0x14, 0x3e, 0x1d, + 0xce, 0xa1, 0xed, 0xc9, 0x19, 0x18, 0xe0, 0x77, 0x8c, 0x89, 0x96, 0xaf, 0xaa, 0x35, 0xb4, 0x1d, + 0x6f, 0x71, 0x32, 0x13, 0xda, 0x48, 0x54, 0xe2, 0x53, 0xf0, 0x10, 0x3d, 0xae, 0x1e, 0x3b, 0xd4, + 0xe4, 0xe1, 0x2a, 0xe1, 0x63, 0x64, 0xc6, 0x5d, 0x78, 0x48, 0xb3, 0x55, 0xf0, 0xb9, 0x24, 0xf7, + 0xc6, 0x2f, 0x22, 0x26, 0xe2, 0xdf, 0x50, 0x87, 0xd9, 0x06, 0xfe, 0x88, 0x8e, 0x44, 0x4f, 0xf4, + 0xa2, 0x30, 0x3b, 0x3e, 0xcf, 0x3f, 0xa3, 0xf6, 0x20, 0x81, 0x3c, 0x4e, 0xa4, 0x45, 0xa0, 0xe8, + 0x21, 0x4b, 0x68, 0xa4, 0x40, 0xce, 0x6d, 0x7d, 0xa1, 0x53, 0x30, 0x69, 0x85, 0xb8, 0x37, 0xd8, + 0x4d, 0xf9, 0x02, 0x7b, 0xf4, 0xa8, 0x7a, 0xa6, 0x19, 0x66, 0x35, 0xb6, 0x15, 0x95, 0xa8, 0xca, + 0x08, 0x63, 0x3a, 0x46, 0xb3, 0x06, 0xaa, 0x35, 0xed, 0x99, 0x26, 0xcb, 0x47, 0xee, 0x5a, 0x61, + 0x51, 0xd9, 0xf6, 0xd5, 0x8b, 0xe1, 0x91, 0x25, 0x82, 0x4b, 0xb0, 0xa0, 0x1d, 0x78, 0x49, 0x3e, + 0x5d, 0xc5, 0x88, 0x78, 0x0e, 0xd6, 0xaa, 0x26, 0x5a, 0x73, 0x95, 0x51, 0xb6, 0xef, 0x2e, 0xd3, + 0x93, 0x3e, 0x04, 0xa6, 0xa9, 0x3c, 0x7e, 0x20, 0xe1, 0x84, 0x25, 0x98, 0x52, 0x01, 0x5b, 0x72, + 0x1f, 0xf7, 0x2e, 0x12, 0xd4, 0x38, 0xd8, 0xb2, 0xbd, 0xb5, 0x75, 0xe5, 0x3a, 0x5b, 0xb4, 0xcf, + 0xb3, 0xf0, 0x1a, 0xab, 0xcc, 0x52, 0x8d, 0x17, 0x98, 0x42, 0x9c, 0xf5, 0x08, 0xd1, 0x38, 0xa3, + 0x10, 0x37, 0x06, 0x1b, 0x72, 0x4f, 0xae, 0xe3, 0x1a, 0xda, 0x56, 0x6e, 0xb0, 0x5e, 0x9f, 0xa3, + 0xc9, 0x60, 0xa6, 0xe1, 0x1c, 0xda, 0x6e, 0xfb, 0xaa, 0x22, 0xea, 0x72, 0x0e, 0x6d, 0xc7, 0xfd, + 0x09, 0x9a, 0x81, 0xb7, 0x8f, 0xca, 0x6a, 0x74, 0xd9, 0xa3, 0x21, 0x93, 0xa6, 0x14, 0xb6, 0x59, + 0xd1, 0x88, 0xe9, 0x6a, 0x34, 0x7e, 0x18, 0xb6, 0xe5, 0x2a, 0x37, 0xd9, 0x7c, 0x7d, 0x4c, 0x57, + 0x66, 0x7f, 0x74, 0xb5, 0x32, 0x4e, 0x55, 0xef, 0x9a, 0x95, 0xa5, 0xd9, 0xc5, 0x57, 0x42, 0xbd, + 0x96, 0xaf, 0xf6, 0x1b, 0xc5, 0x70, 0x9c, 0xef, 0x1c, 0xa0, 0x43, 0xd7, 0xe7, 0x81, 0x36, 0x0e, + 0x86, 0x1b, 0xcd, 0xf2, 0x41, 0x0e, 0xc2, 0x7c, 0x5b, 0xd3, 0x8d, 0x40, 0xd0, 0x94, 0xe4, 0x7e, + 0x6e, 0xdc, 0xa3, 0xc4, 0x4a, 0x23, 0x7a, 0x9d, 0x95, 0xb3, 0xb7, 0xd8, 0xf0, 0xbf, 0x43, 0x47, + 0x41, 0x99, 0x8c, 0xf5, 0xa2, 0x34, 0x69, 0x69, 0x72, 0x61, 0x76, 0x7c, 0xbe, 0xe5, 0xab, 0x8a, + 0x9e, 0xc7, 0xf4, 0x7a, 0x50, 0xf0, 0x3e, 0x9d, 0x99, 0xa1, 0xb4, 0xc2, 0x01, 0x49, 0x7b, 0xa3, + 0x59, 0x2e, 0xec, 0x13, 0x16, 0xf6, 0x08, 0xfe, 0x21, 0xc9, 0x17, 0x45, 0x94, 0xee, 0x79, 0x86, + 0xce, 0x38, 0x3d, 0xcb, 0x38, 0xbd, 0x4b, 0x39, 0x9d, 0xcf, 0xdb, 0x7f, 0x79, 0x79, 0x66, 0x32, + 0x20, 0x75, 0x3e, 0xdf, 0xc5, 0xcb, 0x9e, 0xa1, 0x07, 0xac, 0xae, 0x14, 0xb0, 0x0a, 0x35, 0x0e, + 0x38, 0x3a, 0x1b, 0xcd, 0x72, 0x71, 0xb7, 0xb0, 0xb8, 0xd3, 0x03, 0xe7, 0x6a, 0x0b, 0x59, 0xca, + 0xed, 0xc3, 0xe6, 0x6a, 0xe5, 0x80, 0xb9, 0x5a, 0x39, 0x6c, 0xae, 0x56, 0x52, 0xa4, 0xae, 0xa7, + 0x48, 0x5d, 0x2f, 0x9e, 0xab, 0x95, 0xc2, 0xb9, 0x5a, 0x39, 0x6c, 0xae, 0x28, 0xa7, 0xe7, 0x0e, + 0x9d, 0xab, 0x95, 0x83, 0xe6, 0x6a, 0xe5, 0xd0, 0xb9, 0x4a, 0xd3, 0xba, 0x91, 0xa2, 0x75, 0xe3, + 0x80, 0xb9, 0x5a, 0x29, 0x9e, 0x2b, 0x4a, 0xac, 0x21, 0xc9, 0xe7, 0x45, 0xc4, 0xd8, 0x6b, 0xa3, + 0x32, 0xc6, 0x58, 0xbd, 0xd2, 0xf2, 0xd5, 0xbe, 0xbc, 0x09, 0xf6, 0x52, 0x99, 0xe4, 0xaa, 0x62, + 0x9c, 0xbf, 0xb4, 0x4a, 0xf9, 0x7c, 0x73, 0x18, 0x16, 0xd9, 0x04, 0x7f, 0x92, 0xe4, 0xcb, 0x22, + 0xa7, 0xe2, 0x1b, 0xcc, 0x75, 0x07, 0xbb, 0xeb, 0xb6, 0x59, 0x51, 0xbe, 0xc0, 0x1c, 0x7c, 0xad, + 0xe5, 0xab, 0x02, 0x07, 0xc2, 0x73, 0x67, 0x29, 0xd2, 0x6e, 0xfb, 0xea, 0x8d, 0x02, 0x5f, 0xb3, + 0xaa, 0x9c, 0xdb, 0xbc, 0xd7, 0xd2, 0x30, 0x7c, 0x80, 0xc6, 0xe0, 0xeb, 0x72, 0x87, 0x57, 0xb7, + 0xea, 0x71, 0xf6, 0xff, 0xcb, 0x69, 0x16, 0xa3, 0xbf, 0xb2, 0xe7, 0xab, 0xe7, 0x92, 0xc2, 0x73, + 0x79, 0xc1, 0x5a, 0x48, 0x4a, 0x01, 0x56, 0x72, 0x86, 0xd5, 0x78, 0xdd, 0xaa, 0x87, 0x00, 0x57, + 0x6c, 0x36, 0x9a, 0x65, 0x71, 0x63, 0x45, 0x82, 0xa7, 0xb8, 0x26, 0xe0, 0xe7, 0x52, 0xd8, 0x7d, + 0xf4, 0xf4, 0xf9, 0xc1, 0x34, 0x1b, 0xa5, 0x37, 0x59, 0xf2, 0x92, 0x36, 0x11, 0x3f, 0x83, 0xb2, + 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) { @@ -435,6 +458,48 @@ func (m *OptionsConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- 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 { i-- if m.InsecureAllowOldTLSVersions { @@ -1076,6 +1141,24 @@ func (m *OptionsConfiguration) ProtoSize() (n int) { if m.InsecureAllowOldTLSVersions { 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 { n += 4 } @@ -2292,6 +2375,120 @@ func (m *OptionsConfiguration) Unmarshal(dAtA []byte) error { } } 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: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedUPnPEnabled", wireType) diff --git a/lib/config/testdata/overridenvalues.xml b/lib/config/testdata/overridenvalues.xml index aa0868372..9503607e2 100644 --- a/lib/config/testdata/overridenvalues.xml +++ b/lib/config/testdata/overridenvalues.xml @@ -45,6 +45,11 @@ asdfasdf false feature + 40 + 45 + 50 + 55 + 9000 diff --git a/lib/connections/connections_test.go b/lib/connections/connections_test.go index 92d9f2180..ad30f82d0 100644 --- a/lib/connections/connections_test.go +++ b/lib/connections/connections_test.go @@ -439,7 +439,8 @@ func withConnectionPair(b interface{ Fatal(...interface{}) }, connUri string, h } natSvc := nat.NewService(deviceId, wcfg) 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) var addr *url.URL @@ -459,7 +460,7 @@ func withConnectionPair(b interface{ Fatal(...interface{}) }, connUri string, h b.Fatal(err) } // 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 clientConn, err := dialer.Dial(ctx, deviceId, addr) diff --git a/lib/connections/lan_test.go b/lib/connections/lan_test.go index ec2301dee..61017b1e2 100644 --- a/lib/connections/lan_test.go +++ b/lib/connections/lan_test.go @@ -38,7 +38,7 @@ func TestIsLANHost(t *testing.T) { AlwaysLocalNets: []string{"10.20.30.0/24"}, }, }, protocol.LocalDeviceID, events.NoopLogger) - s := &service{cfg: cfg} + s := &lanChecker{cfg: cfg} for _, tc := range cases { res := s.isLANHost(tc.addr) diff --git a/lib/connections/quic_dial.go b/lib/connections/quic_dial.go index f828c14cb..6c9a03670 100644 --- a/lib/connections/quic_dial.go +++ b/lib/connections/quic_dial.go @@ -25,8 +25,6 @@ import ( ) const ( - quicPriority = 100 - // The timeout for connecting, accepting and creating the various // streams. 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 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{} -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. // However it would still be nice if this was adjustable/proportional to ReconnectIntervalS // But prevent something silly like 1/3 = 0 etc. @@ -109,15 +112,14 @@ func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Confi commonDialer: commonDialer{ reconnectInterval: time.Duration(quicInterval) * time.Second, tlsCfg: tlsCfg, + lanPriority: opts.ConnectionPriorityQUICLAN, + wanPriority: opts.ConnectionPriorityQUICWAN, + lanChecker: lanChecker, }, registry: registry, } } -func (quicDialerFactory) Priority() int { - return quicPriority -} - func (quicDialerFactory) AlwaysWAN() bool { return false } diff --git a/lib/connections/quic_listen.go b/lib/connections/quic_listen.go index 4d10d7e7a..9eab87026 100644 --- a/lib/connections/quic_listen.go +++ b/lib/connections/quic_listen.go @@ -40,12 +40,13 @@ type quicListener struct { onAddressesChangedNotifier - uri *url.URL - cfg config.Wrapper - tlsCfg *tls.Config - conns chan internalConn - factory listenerFactory - registry *registry.Registry + uri *url.URL + cfg config.Wrapper + tlsCfg *tls.Config + conns chan internalConn + factory listenerFactory + registry *registry.Registry + lanChecker *lanChecker address *url.URL laddr net.Addr @@ -168,7 +169,12 @@ func (t *quicListener) serve(ctx context.Context) error { 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 } -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{ - uri: fixupPort(uri, config.DefaultQUICPort), - cfg: cfg, - tlsCfg: tlsCfg, - conns: conns, - factory: f, - registry: registry, + uri: fixupPort(uri, config.DefaultQUICPort), + cfg: cfg, + tlsCfg: tlsCfg, + conns: conns, + factory: f, + registry: registry, + lanChecker: lanChecker, } l.ServiceWithError = svcutil.AsService(l.serve, l.String()) l.nat.Store(uint64(stun.NATUnknown)) diff --git a/lib/connections/relay_dial.go b/lib/connections/relay_dial.go index 969229582..5cb29a8cf 100644 --- a/lib/connections/relay_dial.go +++ b/lib/connections/relay_dial.go @@ -19,8 +19,6 @@ import ( "github.com/syncthing/syncthing/lib/relay/client" ) -const relayPriority = 200 - func init() { dialers["relay"] = relayDialerFactory{} } @@ -64,23 +62,21 @@ func (d *relayDialer) Dial(ctx context.Context, id protocol.DeviceID, uri *url.U return internalConn{}, err } - return newInternalConn(tc, connTypeRelayClient, relayPriority), nil + return newInternalConn(tc, connTypeRelayClient, false, d.wanPriority), nil } 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{ trafficClass: opts.TrafficClass, reconnectInterval: time.Duration(opts.RelayReconnectIntervalM) * time.Minute, tlsCfg: tlsCfg, + wanPriority: opts.ConnectionPriorityRelay, + lanPriority: opts.ConnectionPriorityRelay, }} } -func (relayDialerFactory) Priority() int { - return relayPriority -} - func (relayDialerFactory) AlwaysWAN() bool { return true } diff --git a/lib/connections/relay_listen.go b/lib/connections/relay_listen.go index 90c3e25d8..b6e89c813 100644 --- a/lib/connections/relay_listen.go +++ b/lib/connections/relay_listen.go @@ -106,7 +106,7 @@ func (t *relayListener) handleInvitations(ctx context.Context, clnt client.Relay 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 // relay URI has changed. This can only happen when we connect to a @@ -177,7 +177,7 @@ func (*relayListener) NATType() string { 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{ uri: uri, cfg: cfg, diff --git a/lib/connections/service.go b/lib/connections/service.go index 44ff0f03f..32859553f 100644 --- a/lib/connections/service.go +++ b/lib/connections/service.go @@ -162,6 +162,7 @@ type service struct { evLogger events.Logger registry *registry.Registry keyGen *protocol.KeyGenerator + lanChecker *lanChecker dialNow chan struct{} dialNowDevices map[protocol.DeviceID]struct{} @@ -192,6 +193,7 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t evLogger: evLogger, registry: registry, keyGen: keyGen, + lanChecker: &lanChecker{cfg}, dialNowDevicesMut: sync.NewMutex(), dialNow: make(chan struct{}, 1), @@ -405,9 +407,6 @@ func (s *service) handleHellos(ctx context.Context) error { 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 // keep up with config changes to the rate and whether or not LAN // 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 for _, df := range dialers { if df.Valid(cfg) != nil { 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 } } @@ -544,7 +544,14 @@ func (s *service) dialDevices(ctx context.Context, now time.Time, cfg config.Con priorityCutoff := worstDialerPriority connection, connected := s.model.Connection(deviceCfg.DeviceID) 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() + + // 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 { // Our best dialer is not any better than what we already // 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 - // 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 // 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 @@ -657,24 +664,15 @@ func (s *service) resolveDialTargets(ctx context.Context, now time.Time, cfg con continue } - priority := dialerFactory.Priority() + dialer := dialerFactory.New(s.cfg.Options(), s.tlsCfg, s.registry, s.lanChecker) + priority := dialer.Priority(uri.Host) 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 } - dialer := dialerFactory.New(s.cfg.Options(), s.tlsCfg, s.registry) 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{ addr: addr, dialer: dialer, @@ -703,7 +701,11 @@ func (s *service) resolveDeviceAddrs(ctx context.Context, cfg config.DeviceConfi 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 // a TCP address. if addr, err := net.ResolveTCPAddr("tcp", host); err == nil { @@ -717,7 +719,7 @@ func (s *service) isLANHost(host string) bool { return false } -func (s *service) isLAN(addr net.Addr) bool { +func (s *lanChecker) isLAN(addr net.Addr) bool { var ip net.IP switch addr := addr.(type) { @@ -763,7 +765,7 @@ func (s *service) createListener(factory listenerFactory, uri *url.URL) bool { 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) // Retrying a listener many times in rapid succession is unlikely to help, diff --git a/lib/connections/structs.go b/lib/connections/structs.go index 1a98fc720..1f5bf376b 100644 --- a/lib/connections/structs.go +++ b/lib/connections/structs.go @@ -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{ tlsConn: tc, connType: connType, + isLocal: isLocal, priority: priority, establishedAt: time.Now().Truncate(time.Second), } @@ -138,12 +139,15 @@ func (c internalConn) EstablishedAt() time.Time { } 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 { - New(config.OptionsConfiguration, *tls.Config, *registry.Registry) genericDialer - Priority() int + New(config.OptionsConfiguration, *tls.Config, *registry.Registry, *lanChecker) genericDialer AlwaysWAN() bool Valid(config.Configuration) error String() string @@ -153,19 +157,30 @@ type commonDialer struct { trafficClass int reconnectInterval time.Duration tlsCfg *tls.Config + lanChecker *lanChecker + lanPriority int + wanPriority int } func (d *commonDialer) RedialFrequency() time.Duration { return d.reconnectInterval } +func (d *commonDialer) Priority(host string) int { + if d.lanChecker.isLANHost(host) { + return d.lanPriority + } + return d.wanPriority +} + type genericDialer interface { Dial(context.Context, protocol.DeviceID, *url.URL) (internalConn, error) RedialFrequency() time.Duration + Priority(host string) int } 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 } diff --git a/lib/connections/tcp_dial.go b/lib/connections/tcp_dial.go index 9f87f4117..04a551e46 100644 --- a/lib/connections/tcp_dial.go +++ b/lib/connections/tcp_dial.go @@ -18,8 +18,6 @@ import ( "github.com/syncthing/syncthing/lib/protocol" ) -const tcpPriority = 10 - func init() { factory := &tcpDialerFactory{} 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 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{} -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{ commonDialer: commonDialer{ trafficClass: opts.TrafficClass, reconnectInterval: time.Duration(opts.ReconnectIntervalS) * time.Second, tlsCfg: tlsCfg, + lanPriority: opts.ConnectionPriorityTCPLAN, + wanPriority: opts.ConnectionPriorityTCPWAN, + lanChecker: lanChecker, }, registry: registry, } } -func (tcpDialerFactory) Priority() int { - return tcpPriority -} - func (tcpDialerFactory) AlwaysWAN() bool { return false } diff --git a/lib/connections/tcp_listen.go b/lib/connections/tcp_listen.go index c2b4bb57f..c932fc13b 100644 --- a/lib/connections/tcp_listen.go +++ b/lib/connections/tcp_listen.go @@ -32,12 +32,13 @@ type tcpListener struct { svcutil.ServiceWithError onAddressesChangedNotifier - uri *url.URL - cfg config.Wrapper - tlsCfg *tls.Config - conns chan internalConn - factory listenerFactory - registry *registry.Registry + uri *url.URL + cfg config.Wrapper + tlsCfg *tls.Config + conns chan internalConn + factory listenerFactory + registry *registry.Registry + lanChecker *lanChecker natService *nat.Service mapping *nat.Mapping @@ -148,7 +149,12 @@ func (t *tcpListener) serve(ctx context.Context) error { 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{} -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{ uri: fixupPort(uri, config.DefaultTCPPort), cfg: cfg, @@ -223,6 +229,7 @@ func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.C natService: natService, factory: f, registry: registry, + lanChecker: lanChecker, } l.ServiceWithError = svcutil.AsService(l.serve, l.String()) return l diff --git a/proto/lib/config/optionsconfiguration.proto b/proto/lib/config/optionsconfiguration.proto index 9981191f6..0e2474695 100644 --- a/proto/lib/config/optionsconfiguration.proto +++ b/proto/lib/config/optionsconfiguration.proto @@ -70,6 +70,13 @@ message OptionsConfiguration { // default to TLS 1.3+ only. 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 bool upnp_enabled = 9000 [deprecated = true, (ext.goname) = "DeprecatedUPnPEnabled"]; int32 upnp_lease_m = 9001 [deprecated = true, (ext.goname) = "DeprecatedUPnPLeaseM", (ext.xml) = "upnpLeaseMinutes,omitempty"];