Repository: syncthing/syncthing (language: go)

Issue:
Sync extended file attributes on supported file systems
For now, Syncthing is not preserve extended file attributes (xattrs) when sync, as says in FAQ. But some tagging engines for Linux (such as Baloo, former Nepomuk from KDE) stores metainformation (tags, comments, ratings etc.) exactly in xattrs, therefore this metainfo are not synchronized across the cluster. Maybe is possible to add optional feature to sync xattrs across nodes, if file system supports it?

Some (possibly) related articles:
https://en.wikipedia.org/wiki/Extended_file_attributes#Linux
https://community.kde.org/Baloo/Architecture

P.S. I apologise for my very bad english. Hope that you can understand me.



Discussion / hints:
I am pretty sure it's a duplicate, but I can't find the original ticket.

Maybe not an exact dupe of this, but at least related: https://github.com/syncthing/syncthing/issues/1329

If this got implemented/merged, can it be coded as optional? In many cases, xattrs / EAs propagation are not needed.

I think it will work based on include/exclude lists.

I'm KDE user. It's very important feature. I vote for it. Without I only can just play with syncthing without serios use because i'm going lose information.BtSync help currently out but OP Syncthing would be my favorit after the freature is implemented. I think this will be important also for OSx Users.


Fix patch:
diff --git a/gui/default/syncthing/folder/editFolderModalView.html b/gui/default/syncthing/folder/editFolderModalView.html
index 98644df3f6e..ceb36e22d11 100644
--- a/gui/default/syncthing/folder/editFolderModalView.html
+++ b/gui/default/syncthing/folder/editFolderModalView.html
@@ -284,6 +284,45 @@
               </p>
             </div>
           </div>
+
+          <div class="row">
+            <div class="col-md-6 form-group">
+              <p>
+                <label translate>Ownership</label>
+                &nbsp;<a href="{{docsURL('advanced/folder-sync-ownership')}}" target="_blank"><span class="fas fa-question-circle"></span>&nbsp;<span translate>Help</span></a>
+              </p>
+              <label>
+                <input type="checkbox" ng-disabled="currentFolder.type == 'sendonly' || currentFolder.type == 'receiveencrypted'" ng-model="currentFolder.syncOwnership" /> <span translate>Sync Ownership</span>
+              </label>
+              <p translate class="help-block">
+                Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.
+              </p>
+              <label>
+                <input type="checkbox" ng-disabled="currentFolder.type == 'receiveonly' || currentFolder.type == 'receiveencrypted' || currentFolder.syncOwnership" ng-checked="currentFolder.sendOwnership || currentFolder.syncOwnership" ng-model="currentFolder.sendOwnership" /> <span translate>Send Ownership</span>
+              </label>
+              <p translate class="help-block">
+                Enables sending ownership to other devices, but not applying incoming ownership information. This can have a significant performance impact. Always enabled when "Sync Ownership" is enabled.
+              </p>
+            </div>
+            <div class="col-md-6 form-group">
+              <p>
+                <label translate>Extended Attributes</label>
+                &nbsp;<a href="{{docsURL('advanced/folder-sync-xattrs')}}" target="_blank"><span class="fas fa-question-circle"></span>&nbsp;<span translate>Help</span></a>
+              </p>
+              <label>
+                <input type="checkbox" ng-disabled="currentFolder.type == 'sendonly' || currentFolder.type == 'receiveencrypted'" ng-model="currentFolder.syncXattrs" /> <span translate>Sync Extended Attributes</span>
+              </label>
+              <p translate class="help-block">
+                Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.
+              </p>
+              <label>
+                <input type="checkbox" ng-disabled="currentFolder.type == 'receiveonly' || currentFolder.type == 'receiveencrypted' || currentFolder.syncXattrs" ng-checked="currentFolder.sendXattrs || currentFolder.syncXattrs" ng-model="currentFolder.sendXattrs" /> <span translate>Send Extended Attributes</span>
+              </label>
+              <p translate class="help-block">
+                Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when "Sync Extended Attributes" is enabled.
+              </p>
+            </div>
+          </div>
         </div>
       </div>
     </form>
diff --git a/lib/api/api.go b/lib/api/api.go
index fe7ae36effa..f24a974112d 100644
--- a/lib/api/api.go
+++ b/lib/api/api.go
@@ -1820,6 +1820,8 @@ func fileIntfJSONMap(f protocol.FileIntf) map[string]interface{} {
 		"sequence":      f.SequenceNo(),
 		"version":       jsonVersionVector(f.FileVersion()),
 		"localFlags":    f.FileLocalFlags(),
+		"platform":      f.PlatformData(),
+		"inodeChange":   f.InodeChangeTime(),
 	}
 	if f.HasPermissionBits() {
 		out["permissions"] = fmt.Sprintf("%#o", f.FilePermissions())
diff --git a/lib/config/config.go b/lib/config/config.go
index a39229cc148..ede59bc6d46 100644
--- a/lib/config/config.go
+++ b/lib/config/config.go
@@ -28,7 +28,7 @@ import (
 
 const (
 	OldestHandledVersion = 10
-	CurrentVersion       = 36
+	CurrentVersion       = 37
 	MaxRescanIntervalS   = 365 * 24 * 60 * 60
 )
 
diff --git a/lib/config/folderconfiguration.go b/lib/config/folderconfiguration.go
index 700be195823..defeab4c554 100644
--- a/lib/config/folderconfiguration.go
+++ b/lib/config/folderconfiguration.go
@@ -9,6 +9,7 @@ package config
 import (
 	"errors"
 	"fmt"
+	"path"
 	"sort"
 	"strings"
 	"time"
@@ -272,3 +273,24 @@ func (f *FolderConfiguration) CheckAvailableSpace(req uint64) error {
 	}
 	return nil
 }
+
+func (f XattrFilter) Permit(s string) bool {
+	if len(f.Entries) == 0 {
+		return true
+	}
+
+	for _, entry := range f.Entries {
+		if ok, _ := path.Match(entry.Match, s); ok {
+			return entry.Permit
+		}
+	}
+	return false
+}
+
+func (f XattrFilter) GetMaxSingleEntrySize() int {
+	return f.MaxSingleEntrySize
+}
+
+func (f XattrFilter) GetMaxTotalSize() int {
+	return f.MaxTotalSize
+}
diff --git a/lib/config/folderconfiguration.pb.go b/lib/config/folderconfiguration.pb.go
index bedd8983a4d..b854448001b 100644
--- a/lib/config/folderconfiguration.pb.go
+++ b/lib/config/folderconfiguration.pb.go
@@ -101,11 +101,15 @@ type FolderConfiguration struct {
 	CaseSensitiveFS         bool                        `protobuf:"varint,33,opt,name=case_sensitive_fs,json=caseSensitiveFs,proto3" json:"caseSensitiveFS" xml:"caseSensitiveFS"`
 	JunctionsAsDirs         bool                        `protobuf:"varint,34,opt,name=follow_junctions,json=followJunctions,proto3" json:"junctionsAsDirs" xml:"junctionsAsDirs"`
 	SyncOwnership           bool                        `protobuf:"varint,35,opt,name=sync_ownership,json=syncOwnership,proto3" json:"syncOwnership" xml:"syncOwnership"`
-	ScanOwnership           bool                        `protobuf:"varint,36,opt,name=scan_ownership,json=scanOwnership,proto3" json:"scanOwnership" xml:"scanOwnership"`
+	SendOwnership           bool                        `protobuf:"varint,36,opt,name=send_ownership,json=sendOwnership,proto3" json:"sendOwnership" xml:"sendOwnership"`
+	SyncXattrs              bool                        `protobuf:"varint,37,opt,name=sync_xattrs,json=syncXattrs,proto3" json:"syncXattrs" xml:"syncXattrs"`
+	SendXattrs              bool                        `protobuf:"varint,38,opt,name=send_xattrs,json=sendXattrs,proto3" json:"sendXattrs" xml:"sendXattrs"`
+	XattrFilter             XattrFilter                 `protobuf:"bytes,39,opt,name=xattr_filter,json=xattrFilter,proto3" json:"xattrFilter" xml:"xattrFilter"`
 	// Legacy deprecated
 	DeprecatedReadOnly       bool    `protobuf:"varint,9000,opt,name=read_only,json=readOnly,proto3" json:"-" xml:"ro,attr,omitempty"`                       // Deprecated: Do not use.
 	DeprecatedMinDiskFreePct float64 `protobuf:"fixed64,9001,opt,name=min_disk_free_pct,json=minDiskFreePct,proto3" json:"-" xml:"minDiskFreePct,omitempty"` // Deprecated: Do not use.
 	DeprecatedPullers        int     `protobuf:"varint,9002,opt,name=pullers,proto3,casttype=int" json:"-" xml:"pullers,omitempty"`                          // Deprecated: Do not use.
+	DeprecatedScanOwnership  bool    `protobuf:"varint,9003,opt,name=scan_ownership,json=scanOwnership,proto3" json:"-" xml:"scanOwnership,omitempty"`       // Deprecated: Do not use.
 }
 
 func (m *FolderConfiguration) Reset()         { *m = FolderConfiguration{} }
@@ -141,9 +145,94 @@ func (m *FolderConfiguration) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_FolderConfiguration proto.InternalMessageInfo
 
+// Extended attribute filter. This is a list of patterns to match (glob
+// style), each with an action (permit or deny). First match is used. If the
+// filter is empty, all strings are permitted. If the filter is non-empty,
+// the default action becomes deny. To counter this, you can use the "*"
+// pattern to match all strings at the end of the filter. There are also
+// limits on the size of accepted attributes.
+type XattrFilter struct {
+	Entries            []XattrFilterEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries" xml:"entry"`
+	MaxSingleEntrySize int                `protobuf:"varint,2,opt,name=max_single_entry_size,json=maxSingleEntrySize,proto3,casttype=int" json:"maxSingleEntrySize" xml:"maxSingleEntrySize" default:"1024"`
+	MaxTotalSize       int                `protobuf:"varint,3,opt,name=max_total_size,json=maxTotalSize,proto3,casttype=int" json:"maxTotalSize" xml:"maxTotalSize" default:"4096"`
+}
+
+func (m *XattrFilter) Reset()         { *m = XattrFilter{} }
+func (m *XattrFilter) String() string { return proto.CompactTextString(m) }
+func (*XattrFilter) ProtoMessage()    {}
+func (*XattrFilter) Descriptor() ([]byte, []int) {
+	return fileDescriptor_44a9785876ed3afa, []int{2}
+}
+func (m *XattrFilter) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *XattrFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_XattrFilter.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *XattrFilter) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_XattrFilter.Merge(m, src)
+}
+func (m *XattrFilter) XXX_Size() int {
+	return m.ProtoSize()
+}
+func (m *XattrFilter) XXX_DiscardUnknown() {
+	xxx_messageInfo_XattrFilter.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_XattrFilter proto.InternalMessageInfo
+
+type XattrFilterEntry struct {
+	Match  string `protobuf:"bytes,1,opt,name=match,proto3" json:"match" xml:"match,attr"`
+	Permit bool   `protobuf:"varint,2,opt,name=permit,proto3" json:"permit" xml:"permit,attr"`
+}
+
+func (m *XattrFilterEntry) Reset()         { *m = XattrFilterEntry{} }
+func (m *XattrFilterEntry) String() string { return proto.CompactTextString(m) }
+func (*XattrFilterEntry) ProtoMessage()    {}
+func (*XattrFilterEntry) Descriptor() ([]byte, []int) {
+	return fileDescriptor_44a9785876ed3afa, []int{3}
+}
+func (m *XattrFilterEntry) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *XattrFilterEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_XattrFilterEntry.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *XattrFilterEntry) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_XattrFilterEntry.Merge(m, src)
+}
+func (m *XattrFilterEntry) XXX_Size() int {
+	return m.ProtoSize()
+}
+func (m *XattrFilterEntry) XXX_DiscardUnknown() {
+	xxx_messageInfo_XattrFilterEntry.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_XattrFilterEntry proto.InternalMessageInfo
+
 func init() {
 	proto.RegisterType((*FolderDeviceConfiguration)(nil), "config.FolderDeviceConfiguration")
 	proto.RegisterType((*FolderConfiguration)(nil), "config.FolderConfiguration")
+	proto.RegisterType((*XattrFilter)(nil), "config.XattrFilter")
+	proto.RegisterType((*XattrFilterEntry)(nil), "config.XattrFilterEntry")
 }
 
 func init() {
@@ -151,138 +240,158 @@ func init() {
 }
 
 var fileDescriptor_44a9785876ed3afa = []byte{
-	// 2093 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcf, 0x6f, 0xdc, 0xc6,
-	0xf5, 0x17, 0xe5, 0x5f, 0xd2, 0xe8, 0xf7, 0xc8, 0xb2, 0xc7, 0x72, 0xb2, 0xb3, 0x66, 0xd6, 0xf9,
-	0x2a, 0x41, 0x22, 0xdb, 0xca, 0x17, 0x05, 0x6a, 0xd4, 0x6d, 0xb3, 0x52, 0x84, 0xba, 0xae, 0xe2,
-	0x05, 0xe5, 0xd6, 0x68, 0x5a, 0x80, 0xe5, 0x92, 0xb3, 0xbb, 0x8c, 0xf8, 0xab, 0x33, 0x5c, 0x4b,
-	0xeb, 0x43, 0xe0, 0x5e, 0x8a, 0x16, 0xcd, 0xa1, 0x50, 0x0f, 0xbd, 0x06, 0x68, 0x51, 0xb4, 0xf9,
-	0x07, 0x0a, 0xf4, 0xd4, 0xa3, 0x2f, 0x85, 0xf6, 0x54, 0x14, 0x3d, 0x0c, 0x10, 0xf9, 0xb6, 0x47,
-	0x1e, 0x7d, 0x2a, 0x66, 0x86, 0xe4, 0x92, 0xdc, 0x0d, 0x50, 0xa0, 0x37, 0xce, 0xe7, 0xf3, 0xe6,
-	0xbd, 0x0f, 0xdf, 0xcc, 0xbc, 0x79, 0x24, 0x68, 0x78, 0x6e, 0xfb, 0x8e, 0x1d, 0x06, 0x1d, 0xb7,
-	0x7b, 0xa7, 0x13, 0x7a, 0x0e, 0xa1, 0x6a, 0xd0, 0xa7, 0x56, 0xec, 0x86, 0xc1, 0x76, 0x44, 0xc3,
-	0x38, 0x84, 0x97, 0x15, 0xb8, 0x79, 0x73, 0xc2, 0x3a, 0x1e, 0x44, 0x44, 0x19, 0x6d, 0x6e, 0x14,
-	0x48, 0xe6, 0x3e, 0xcf, 0xe0, 0xcd, 0x02, 0x1c, 0xf5, 0x3d, 0x2f, 0xa4, 0x0e, 0xa1, 0x29, 0xb7,
-	0x55, 0xe0, 0x9e, 0x11, 0xca, 0xdc, 0x30, 0x70, 0x83, 0xee, 0x14, 0x05, 0x9b, 0xb8, 0x60, 0xd9,
-	0xf6, 0x42, 0xfb, 0xa8, 0xea, 0x0a, 0x0a, 0x83, 0x0e, 0xbb, 0x23, 0x04, 0xb1, 0x14, 0x7b, 0x23,
-	0xc5, 0xec, 0x30, 0x1a, 0x50, 0x2b, 0xe8, 0x12, 0x9f, 0xc4, 0xbd, 0xd0, 0x49, 0xd9, 0x79, 0x72,
-	0x12, 0xab, 0x47, 0xfd, 0x9f, 0x17, 0xc0, 0x8d, 0x7d, 0xf9, 0x3e, 0x7b, 0xe4, 0x99, 0x6b, 0x93,
-	0xdd, 0xa2, 0x02, 0xf8, 0xa5, 0x06, 0xe6, 0x1d, 0x89, 0x9b, 0xae, 0x83, 0xb4, 0xba, 0xb6, 0xb5,
-	0xd8, 0xfc, 0x5c, 0x7b, 0xc9, 0xf1, 0xcc, 0xbf, 0x39, 0xfe, 0xff, 0xae, 0x1b, 0xf7, 0xfa, 0xed,
-	0x6d, 0x3b, 0xf4, 0xef, 0xb0, 0x41, 0x60, 0xc7, 0x3d, 0x37, 0xe8, 0x16, 0x9e, 0x84, 0x04, 0x19,
-	0xc4, 0x0e, 0xbd, 0x6d, 0xe5, 0xfd, 0xe1, 0xde, 0x39, 0xc7, 0x73, 0xd9, 0xf3, 0x88, 0xe3, 0x39,
-	0x27, 0x7d, 0x4e, 0x38, 0x5e, 0x3a, 0xf1, 0xbd, 0xfb, 0xba, 0xeb, 0xbc, 0x67, 0xc5, 0x31, 0xd5,
-	0x47, 0x67, 0x8d, 0x2b, 0xe9, 0x73, 0x72, 0xd6, 0xc8, 0xed, 0x7e, 0x35, 0x6c, 0x68, 0xa7, 0xc3,
-	0x46, 0xee, 0xc3, 0xc8, 0x18, 0x07, 0xfe, 0x49, 0x03, 0x4b, 0x6e, 0x10, 0xd3, 0xd0, 0xe9, 0xdb,
-	0xc4, 0x31, 0xdb, 0x03, 0x34, 0x2b, 0x05, 0xbf, 0xf8, 0x9f, 0x04, 0x8f, 0x38, 0x5e, 0x1c, 0x7b,
-	0x6d, 0x0e, 0x12, 0x8e, 0xaf, 0x2b, 0xa1, 0x05, 0x30, 0x97, 0xbc, 0x36, 0x81, 0x0a, 0xc1, 0x46,
-	0xc9, 0x03, 0xb4, 0xc1, 0x3a, 0x09, 0x6c, 0x3a, 0x88, 0x44, 0x8e, 0xcd, 0xc8, 0x62, 0xec, 0x38,
-	0xa4, 0x0e, 0xba, 0x50, 0xd7, 0xb6, 0xe6, 0x9b, 0x3b, 0x23, 0x8e, 0xe1, 0x98, 0x6e, 0xa5, 0x6c,
-	0xc2, 0x31, 0x92, 0x61, 0x27, 0x29, 0xdd, 0x98, 0x62, 0xaf, 0xff, 0xfd, 0x16, 0x58, 0x57, 0x0b,
-	0x5b, 0x5e, 0xd2, 0x43, 0x30, 0x9b, 0x2e, 0xe5, 0x7c, 0x73, 0xf7, 0x9c, 0xe3, 0x59, 0xf9, 0x8a,
-	0xb3, 0xae, 0x88, 0x50, 0x2b, 0xad, 0x40, 0x3d, 0x08, 0x1d, 0xd2, 0xb1, 0xfa, 0x5e, 0x7c, 0x5f,
-	0x8f, 0x69, 0x9f, 0x14, 0x97, 0xe4, 0x74, 0xd8, 0x98, 0x7d, 0xb8, 0xf7, 0x85, 0x78, 0xb7, 0x59,
-	0xd7, 0x81, 0x3f, 0x04, 0x97, 0x3c, 0xab, 0x4d, 0x3c, 0x99, 0xf1, 0xf9, 0xe6, 0x77, 0x46, 0x1c,
-	0x2b, 0x20, 0xe1, 0xb8, 0x2e, 0x9d, 0xca, 0x51, 0xea, 0x97, 0x12, 0x16, 0x5b, 0x34, 0xbe, 0xaf,
-	0x77, 0x2c, 0x8f, 0x49, 0xb7, 0x60, 0x4c, 0xbf, 0x18, 0x36, 0x66, 0x0c, 0x35, 0x19, 0x76, 0xc1,
-	0x4a, 0xc7, 0xf5, 0x08, 0x1b, 0xb0, 0x98, 0xf8, 0xa6, 0xd8, 0xdf, 0x32, 0x49, 0xcb, 0x3b, 0x70,
-	0xbb, 0xc3, 0xb6, 0xf7, 0x73, 0xea, 0xc9, 0x20, 0x22, 0xcd, 0x77, 0x47, 0x1c, 0x2f, 0x77, 0x4a,
-	0x58, 0xc2, 0xf1, 0x55, 0x19, 0xbd, 0x0c, 0xeb, 0x46, 0xc5, 0x0e, 0x1e, 0x80, 0x8b, 0x91, 0x15,
-	0xf7, 0xd0, 0x45, 0x29, 0xff, 0x9b, 0x23, 0x8e, 0xe5, 0x38, 0xe1, 0xf8, 0xa6, 0x9c, 0x2f, 0x06,
-	0xa9, 0xf8, 0x3c, 0x25, 0x9f, 0x09, 0xe1, 0xf3, 0x39, 0xf3, 0xfa, 0xac, 0xa1, 0x7d, 0x66, 0xc8,
-	0x69, 0xb0, 0x05, 0x2e, 0x4a, 0xb1, 0x97, 0x52, 0xb1, 0xea, 0xf4, 0x6e, 0xab, 0xe5, 0x90, 0x62,
-	0xb7, 0x44, 0x88, 0x58, 0x49, 0x5c, 0x91, 0x21, 0xc4, 0x20, 0xdf, 0x46, 0xf3, 0xf9, 0xc8, 0x90,
-	0x56, 0xf0, 0xa7, 0xe0, 0x8a, 0xda, 0xe7, 0x0c, 0x5d, 0xae, 0x5f, 0xd8, 0x5a, 0xd8, 0xb9, 0x55,
-	0x76, 0x3a, 0xe5, 0xf0, 0x36, 0xb1, 0xd8, 0xf6, 0x23, 0x8e, 0xb3, 0x99, 0x09, 0xc7, 0x8b, 0x32,
-	0x94, 0x1a, 0xeb, 0x46, 0x46, 0xc0, 0xdf, 0x69, 0x60, 0x8d, 0x12, 0x66, 0x5b, 0x81, 0xe9, 0x06,
-	0x31, 0xa1, 0xcf, 0x2c, 0xcf, 0x64, 0xe8, 0x4a, 0x5d, 0xdb, 0xba, 0xd4, 0xec, 0x8e, 0x38, 0x5e,
-	0x51, 0xe4, 0xc3, 0x94, 0x3b, 0x4c, 0x38, 0x7e, 0x47, 0x7a, 0xaa, 0xe0, 0xd5, 0x14, 0x7d, 0xf0,
-	0x8d, 0xbb, 0x77, 0xf5, 0xd7, 0x1c, 0x5f, 0x70, 0x83, 0x78, 0x74, 0xd6, 0xb8, 0x3a, 0xcd, 0xfc,
-	0xf5, 0x59, 0xe3, 0xa2, 0xb0, 0x33, 0xaa, 0x41, 0xe0, 0xdf, 0x34, 0x00, 0x3b, 0xcc, 0x3c, 0xb6,
-	0x62, 0xbb, 0x47, 0xa8, 0x49, 0x02, 0xab, 0xed, 0x11, 0x07, 0xcd, 0xd5, 0xb5, 0xad, 0xb9, 0xe6,
-	0x6f, 0xb4, 0x73, 0x8e, 0x57, 0xf7, 0x0f, 0x9f, 0x2a, 0xf6, 0x23, 0x45, 0x8e, 0x38, 0x5e, 0xed,
-	0xb0, 0x32, 0x96, 0x70, 0xfc, 0xae, 0xda, 0x04, 0x15, 0xa2, 0xaa, 0x36, 0xdb, 0xe3, 0x1b, 0x53,
-	0x0d, 0x85, 0x4e, 0x61, 0x71, 0x3a, 0x6c, 0x4c, 0x84, 0x35, 0x26, 0x82, 0xc2, 0xbf, 0x96, 0xc5,
-	0x3b, 0xc4, 0xb3, 0x06, 0x26, 0x43, 0xf3, 0x32, 0xa7, 0xbf, 0x16, 0xe2, 0x57, 0x72, 0x2f, 0x7b,
-	0x82, 0x3c, 0x14, 0x79, 0xce, 0xdd, 0x28, 0x28, 0xe1, 0xf8, 0xff, 0xca, 0xd2, 0x15, 0x5e, 0x55,
-	0x7e, 0xaf, 0x94, 0xe5, 0x69, 0xc6, 0xaf, 0xcf, 0x1a, 0xb3, 0xf7, 0xee, 0x9e, 0x0e, 0x1b, 0xd5,
-	0xa8, 0x46, 0x35, 0x26, 0xfc, 0x19, 0x58, 0x74, 0xbb, 0x41, 0x48, 0x89, 0x19, 0x11, 0xea, 0x33,
-	0x04, 0x64, 0xbe, 0x1f, 0x8c, 0x38, 0x5e, 0x50, 0x78, 0x4b, 0xc0, 0x09, 0xc7, 0xd7, 0x54, 0xb5,
-	0x18, 0x63, 0xf9, 0xf6, 0x5d, 0xad, 0x82, 0x46, 0x71, 0x2a, 0xfc, 0x85, 0x06, 0x96, 0xad, 0x7e,
-	0x1c, 0x9a, 0x41, 0x48, 0x7d, 0xcb, 0x73, 0x9f, 0x13, 0xb4, 0x20, 0x83, 0x7c, 0x32, 0xe2, 0x78,
-	0x49, 0x30, 0x1f, 0x67, 0x44, 0x9e, 0x81, 0x12, 0xfa, 0x75, 0x2b, 0x07, 0x27, 0xad, 0xb2, 0x65,
-	0x33, 0xca, 0x7e, 0x61, 0x08, 0x96, 0x7c, 0x37, 0x30, 0x1d, 0x97, 0x1d, 0x99, 0x1d, 0x4a, 0x08,
-	0x5a, 0xac, 0x6b, 0x5b, 0x0b, 0x3b, 0x8b, 0xd9, 0xb1, 0x3a, 0x74, 0x9f, 0x93, 0xe6, 0x83, 0xf4,
-	0x04, 0x2d, 0xf8, 0x6e, 0xb0, 0xe7, 0xb2, 0xa3, 0x7d, 0x4a, 0x84, 0x22, 0x2c, 0x15, 0x15, 0xb0,
-	0xe2, 0x52, 0xd4, 0x6f, 0xeb, 0xaf, 0xcf, 0x1a, 0x17, 0xee, 0xd5, 0x6f, 0x1b, 0xc5, 0x69, 0xb0,
-	0x0b, 0xc0, 0xf8, 0x9e, 0x47, 0x4b, 0x32, 0x1a, 0xce, 0xa2, 0xfd, 0x28, 0x67, 0xca, 0x47, 0xf8,
-	0xed, 0x54, 0x40, 0x61, 0x6a, 0xc2, 0xf1, 0xaa, 0x8c, 0x3f, 0x86, 0x74, 0xa3, 0xc0, 0xc3, 0x07,
-	0xe0, 0x8a, 0x1d, 0x46, 0x2e, 0xa1, 0x0c, 0x2d, 0xcb, 0xdd, 0xf6, 0x96, 0xa8, 0x01, 0x29, 0x94,
-	0x5f, 0xb3, 0xe9, 0x38, 0xdb, 0x37, 0x46, 0x66, 0x00, 0xff, 0xa1, 0x81, 0x6b, 0xa2, 0xc3, 0x20,
-	0xd4, 0xf4, 0xad, 0x13, 0x33, 0x22, 0x81, 0xe3, 0x06, 0x5d, 0xf3, 0xc8, 0x6d, 0xa3, 0x15, 0xe9,
-	0xee, 0xf7, 0x62, 0xf3, 0xae, 0xb7, 0xa4, 0xc9, 0x81, 0x75, 0xd2, 0x52, 0x06, 0x8f, 0xdc, 0xe6,
-	0x88, 0xe3, 0xf5, 0x68, 0x12, 0x4e, 0x38, 0xbe, 0xa1, 0x8a, 0xe8, 0x24, 0x57, 0xd8, 0xb6, 0x53,
-	0xa7, 0x4e, 0x87, 0x4f, 0x87, 0x8d, 0x69, 0xf1, 0x8d, 0x29, 0xb6, 0x6d, 0x91, 0x8e, 0x9e, 0xc5,
-	0x7a, 0x22, 0x1d, 0xab, 0xe3, 0x74, 0xa4, 0x50, 0x9e, 0x8e, 0x74, 0x3c, 0x4e, 0x47, 0x0a, 0xc0,
-	0x0f, 0xc1, 0x25, 0xd9, 0x6b, 0xa1, 0x35, 0x59, 0xcb, 0xd7, 0xb2, 0x15, 0x13, 0xf1, 0x1f, 0x0b,
-	0xa2, 0x89, 0xc4, 0x65, 0x27, 0x6d, 0x12, 0x8e, 0x17, 0xa4, 0x37, 0x39, 0xd2, 0x0d, 0x85, 0xc2,
-	0x47, 0x60, 0x29, 0x3d, 0x50, 0x0e, 0xf1, 0x48, 0x4c, 0x10, 0x94, 0x9b, 0xfd, 0x6d, 0xd9, 0x59,
-	0x48, 0x62, 0x4f, 0xe2, 0x09, 0xc7, 0xb0, 0x70, 0xa4, 0x14, 0xa8, 0x1b, 0x25, 0x1b, 0x78, 0x02,
-	0x90, 0xac, 0xd3, 0x11, 0x0d, 0xbb, 0x94, 0x30, 0x56, 0x2c, 0xd8, 0xeb, 0xf2, 0xfd, 0xc4, 0xe5,
-	0xbb, 0x21, 0x6c, 0x5a, 0xa9, 0x49, 0xb1, 0x6c, 0xab, 0xeb, 0x6c, 0x2a, 0x9b, 0xbf, 0xfb, 0xf4,
-	0xc9, 0xf0, 0x10, 0x2c, 0xa7, 0xfb, 0x22, 0xb2, 0xfa, 0x8c, 0x98, 0x0c, 0x5d, 0x95, 0xf1, 0xde,
-	0x17, 0xef, 0xa1, 0x98, 0x96, 0x20, 0x0e, 0xf3, 0xf7, 0x28, 0x82, 0xb9, 0xf7, 0x92, 0x29, 0x24,
-	0x60, 0x49, 0xec, 0x32, 0x91, 0x54, 0xcf, 0xb5, 0x63, 0x86, 0x36, 0xa4, 0xcf, 0xef, 0x0a, 0x9f,
-	0xbe, 0x75, 0xb2, 0x9b, 0xe1, 0xe3, 0x53, 0x57, 0x00, 0xa7, 0x56, 0x40, 0x55, 0xe9, 0x8c, 0xd2,
-	0x6c, 0xe8, 0x80, 0xab, 0x8e, 0xcb, 0x44, 0x65, 0x36, 0x59, 0x64, 0x51, 0x46, 0x4c, 0xd9, 0x00,
-	0xa0, 0x6b, 0x72, 0x25, 0x64, 0xcb, 0x95, 0xf2, 0x87, 0x92, 0x96, 0xad, 0x45, 0xde, 0x72, 0x4d,
-	0x52, 0xba, 0x31, 0xc5, 0xbe, 0x18, 0x25, 0x26, 0x7e, 0x64, 0xba, 0x81, 0x43, 0x4e, 0x08, 0x43,
-	0xd7, 0x27, 0xa2, 0x3c, 0x21, 0x7e, 0xf4, 0x50, 0xb1, 0xd5, 0x28, 0x05, 0x6a, 0x1c, 0xa5, 0x00,
-	0xc2, 0x1d, 0x70, 0x59, 0x2e, 0x80, 0x83, 0x90, 0xf4, 0xbb, 0x39, 0xe2, 0x38, 0x45, 0xf2, 0x1b,
-	0x5e, 0x0d, 0x75, 0x23, 0xc5, 0x61, 0x0c, 0xae, 0x1f, 0x13, 0xeb, 0xc8, 0x14, 0xbb, 0xda, 0x8c,
-	0x7b, 0x94, 0xb0, 0x5e, 0xe8, 0x39, 0x66, 0x64, 0xc7, 0xe8, 0x86, 0x4c, 0xb8, 0x28, 0xef, 0x57,
-	0x85, 0xc9, 0xf7, 0x2c, 0xd6, 0x7b, 0x92, 0x19, 0xb4, 0xec, 0x38, 0xe1, 0x78, 0x53, 0xba, 0x9c,
-	0x46, 0xe6, 0x8b, 0x3a, 0x75, 0x2a, 0xdc, 0x05, 0x0b, 0xbe, 0x45, 0x8f, 0x08, 0x35, 0x03, 0xcb,
-	0x27, 0x68, 0x53, 0x36, 0x57, 0xba, 0x28, 0x67, 0x0a, 0xfe, 0xd8, 0xf2, 0x49, 0x5e, 0xce, 0xc6,
-	0x90, 0x6e, 0x14, 0x78, 0x38, 0x00, 0x9b, 0xe2, 0x23, 0xc6, 0x0c, 0x8f, 0x03, 0x42, 0x59, 0xcf,
-	0x8d, 0xcc, 0x0e, 0x0d, 0x7d, 0x33, 0xb2, 0x28, 0x09, 0x62, 0x74, 0x53, 0xa6, 0xe0, 0x5b, 0x23,
-	0x8e, 0xaf, 0x0b, 0xab, 0xc7, 0x99, 0xd1, 0x3e, 0x0d, 0xfd, 0x96, 0x34, 0x49, 0x38, 0x7e, 0x33,
-	0xab, 0x78, 0xd3, 0x78, 0xdd, 0xf8, 0xba, 0x99, 0xf0, 0x97, 0x1a, 0x58, 0xf3, 0x43, 0xc7, 0x8c,
-	0x5d, 0x9f, 0x98, 0xc7, 0x6e, 0xe0, 0x84, 0xc7, 0x26, 0x43, 0x6f, 0xc8, 0x84, 0xfd, 0xe4, 0x9c,
-	0xe3, 0x35, 0xc3, 0x3a, 0x3e, 0x08, 0x9d, 0x27, 0xae, 0x4f, 0x9e, 0x4a, 0x56, 0xdc, 0xe1, 0xcb,
-	0x7e, 0x09, 0xc9, 0x5b, 0xd0, 0x32, 0x9c, 0x65, 0xee, 0x74, 0xd8, 0x98, 0xf4, 0x62, 0x54, 0x7c,
-	0xc0, 0x17, 0x1a, 0xd8, 0x48, 0x8f, 0x89, 0xdd, 0xa7, 0x42, 0x9b, 0x79, 0x4c, 0xdd, 0x98, 0x30,
-	0xf4, 0xa6, 0x14, 0xf3, 0x03, 0x51, 0x7a, 0xd5, 0x86, 0x4f, 0xf9, 0xa7, 0x92, 0x4e, 0x38, 0xbe,
-	0x5d, 0x38, 0x35, 0x25, 0xae, 0x70, 0x78, 0x76, 0x0a, 0x67, 0x47, 0xdb, 0x31, 0xa6, 0x79, 0x12,
-	0x45, 0x2c, 0xdb, 0xdb, 0x1d, 0xf1, 0xc5, 0x84, 0x6a, 0xe3, 0x22, 0x96, 0x12, 0xfb, 0x02, 0xcf,
-	0x0f, 0x7f, 0x11, 0xd4, 0x8d, 0x92, 0x0d, 0xf4, 0xc0, 0xaa, 0xfc, 0x92, 0x35, 0x45, 0x2d, 0x30,
-	0x55, 0x7d, 0xc5, 0xb2, 0xbe, 0x5e, 0xcb, 0xea, 0x6b, 0x53, 0xf0, 0xe3, 0x22, 0x2b, 0x9b, 0xfb,
-	0x76, 0x09, 0xcb, 0x33, 0x5b, 0x86, 0x75, 0xa3, 0x62, 0x07, 0x3f, 0xd7, 0xc0, 0x9a, 0xdc, 0x42,
-	0xf2, 0x43, 0xd8, 0x54, 0x5f, 0xc2, 0xa8, 0x2e, 0xe3, 0xad, 0x8b, 0x0f, 0x89, 0xdd, 0x30, 0x1a,
-	0x18, 0x82, 0x3b, 0x90, 0x54, 0xf3, 0x91, 0x68, 0xc5, 0xec, 0x32, 0x98, 0x70, 0xbc, 0x95, 0x6f,
-	0xa3, 0x02, 0x5e, 0x48, 0x23, 0x8b, 0xad, 0xc0, 0xb1, 0xa8, 0x23, 0xee, 0xff, 0xb9, 0x6c, 0x60,
-	0x54, 0x1d, 0xc1, 0x3f, 0x0a, 0x39, 0x96, 0x28, 0xa0, 0x24, 0x60, 0x6e, 0xec, 0x3e, 0x13, 0x19,
-	0x45, 0xb7, 0x64, 0x3a, 0x4f, 0x44, 0x5f, 0xb8, 0x6b, 0x31, 0x72, 0x98, 0x71, 0xfb, 0xb2, 0x2f,
-	0xb4, 0xcb, 0x50, 0xc2, 0xf1, 0x86, 0x12, 0x53, 0xc6, 0x45, 0x0f, 0x34, 0x61, 0x3b, 0x09, 0x89,
-	0x36, 0xb0, 0x12, 0xc4, 0xa8, 0xd8, 0x30, 0xf8, 0x07, 0x0d, 0xac, 0x76, 0x42, 0xcf, 0x0b, 0x8f,
-	0xcd, 0x4f, 0xfb, 0x81, 0x2d, 0xda, 0x11, 0x86, 0xf4, 0xb1, 0xca, 0xef, 0x67, 0xe0, 0x87, 0x6c,
-	0xcf, 0xa5, 0x4c, 0xa8, 0xfc, 0xb4, 0x0c, 0xe5, 0x2a, 0x2b, 0xb8, 0x54, 0x59, 0xb5, 0x9d, 0x84,
-	0x84, 0xca, 0x4a, 0x10, 0x63, 0x45, 0x29, 0xca, 0x61, 0xf8, 0x18, 0x2c, 0x8b, 0x1d, 0x35, 0xae,
-	0x0e, 0xe8, 0x2d, 0x29, 0x51, 0x7c, 0x5f, 0x2d, 0x09, 0x26, 0x3f, 0xd7, 0x09, 0xc7, 0xeb, 0xea,
-	0xf2, 0x2b, 0xa2, 0xba, 0x51, 0xb6, 0x92, 0x0e, 0xc5, 0xfd, 0x3a, 0x76, 0xd8, 0x28, 0x38, 0xb4,
-	0xad, 0x60, 0x8a, 0xc3, 0x22, 0x2a, 0x1c, 0x16, 0xc7, 0xf0, 0x08, 0xcc, 0x53, 0x62, 0x39, 0x66,
-	0x18, 0x78, 0x03, 0xf4, 0xe7, 0x7d, 0xe9, 0xec, 0xe0, 0x9c, 0x63, 0xb8, 0x47, 0x22, 0x4a, 0x6c,
-	0x2b, 0x26, 0x8e, 0x41, 0x2c, 0xe7, 0x71, 0xe0, 0x0d, 0x46, 0x1c, 0x6b, 0xef, 0xe7, 0xff, 0x17,
-	0x68, 0x28, 0x1b, 0xd8, 0xf7, 0x42, 0xdf, 0x15, 0xb7, 0x49, 0x3c, 0x90, 0xff, 0x17, 0x26, 0x50,
-	0xa4, 0x19, 0x73, 0x34, 0x75, 0x00, 0x7f, 0x0e, 0xd6, 0x4a, 0x5d, 0xad, 0xac, 0xf0, 0x7f, 0x11,
-	0x41, 0xb5, 0xe6, 0x47, 0xe7, 0x1c, 0xa3, 0x71, 0xd0, 0x83, 0x71, 0x6f, 0xda, 0xb2, 0xe3, 0x2c,
-	0x74, 0xad, 0xda, 0xda, 0xb6, 0xec, 0xb8, 0xa0, 0x00, 0x69, 0xc6, 0x72, 0x99, 0x84, 0x3f, 0x06,
-	0x57, 0xd4, 0x8d, 0xce, 0xd0, 0x97, 0xfb, 0xb2, 0x1a, 0x7d, 0x5b, 0x94, 0xc6, 0x71, 0x20, 0xd5,
-	0xa9, 0xb1, 0xf2, 0xcb, 0xa5, 0x53, 0x0a, 0xae, 0xd3, 0x12, 0x84, 0x34, 0x23, 0xf3, 0xd7, 0x7c,
-	0xf4, 0xf2, 0xab, 0xda, 0xcc, 0xf0, 0xab, 0xda, 0xcc, 0xcb, 0xf3, 0x9a, 0x36, 0x3c, 0xaf, 0x69,
-	0xbf, 0x7d, 0x55, 0x9b, 0xf9, 0xe2, 0x55, 0x4d, 0x1b, 0xbe, 0xaa, 0xcd, 0xfc, 0xeb, 0x55, 0x6d,
-	0xe6, 0x93, 0x77, 0xfe, 0x8b, 0x3f, 0x3a, 0xaa, 0xa0, 0xb4, 0x2f, 0xcb, 0x3f, 0x3b, 0x1f, 0xfc,
-	0x27, 0x00, 0x00, 0xff, 0xff, 0xd1, 0xc6, 0xcc, 0xd3, 0xf7, 0x13, 0x00, 0x00,
+	// 2407 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcd, 0x6f, 0x1b, 0xc7,
+	0x15, 0xd7, 0x4a, 0xb6, 0x25, 0x8d, 0xbe, 0x47, 0x96, 0xbd, 0x51, 0x12, 0x8d, 0xb2, 0xa1, 0x63,
+	0x25, 0x4d, 0x64, 0x5b, 0x31, 0x02, 0xc4, 0xa8, 0xdb, 0x86, 0x92, 0x85, 0xba, 0xae, 0x62, 0x61,
+	0xa9, 0xd6, 0x6d, 0x52, 0x60, 0xbb, 0xda, 0x1d, 0x92, 0x1b, 0xed, 0x07, 0xbb, 0xb3, 0xb2, 0x44,
+	0x1f, 0x02, 0xb7, 0x87, 0xa2, 0x45, 0x73, 0x28, 0xd4, 0x43, 0x91, 0x43, 0x81, 0x00, 0x2d, 0x8a,
+	0x36, 0xfd, 0x03, 0x0a, 0xf4, 0x2f, 0xf0, 0xa5, 0x90, 0x4e, 0x45, 0xd1, 0xc3, 0x00, 0x91, 0x6f,
+	0x3c, 0xf2, 0xe8, 0x53, 0xf1, 0xde, 0x7e, 0x70, 0x96, 0x64, 0x80, 0x02, 0xbd, 0x71, 0x7e, 0xbf,
+	0x37, 0xef, 0xfd, 0xf6, 0xcd, 0xcc, 0x9b, 0x37, 0x24, 0x15, 0xdf, 0xdb, 0xbf, 0xe1, 0x44, 0x61,
+	0xdd, 0x6b, 0xdc, 0xa8, 0x47, 0xbe, 0xcb, 0xe3, 0x74, 0x70, 0x18, 0xdb, 0x89, 0x17, 0x85, 0xeb,
+	0xad, 0x38, 0x4a, 0x22, 0x7a, 0x29, 0x05, 0x97, 0x5f, 0x1e, 0xb0, 0x4e, 0xda, 0x2d, 0x9e, 0x1a,
+	0x2d, 0x2f, 0x29, 0xa4, 0xf0, 0x9e, 0xe4, 0xf0, 0xb2, 0x02, 0xb7, 0x0e, 0x7d, 0x3f, 0x8a, 0x5d,
+	0x1e, 0x67, 0xdc, 0x9a, 0xc2, 0x3d, 0xe6, 0xb1, 0xf0, 0xa2, 0xd0, 0x0b, 0x1b, 0x43, 0x14, 0x2c,
+	0x33, 0xc5, 0x72, 0xdf, 0x8f, 0x9c, 0x83, 0x7e, 0x57, 0x14, 0x0c, 0xea, 0xe2, 0x06, 0x08, 0x12,
+	0x19, 0xf6, 0x4a, 0x86, 0x39, 0x51, 0xab, 0x1d, 0xdb, 0x61, 0x83, 0x07, 0x3c, 0x69, 0x46, 0x6e,
+	0xc6, 0x4e, 0xf2, 0xe3, 0x24, 0xfd, 0x69, 0xfc, 0x6b, 0x8c, 0xbc, 0xb4, 0x8d, 0xdf, 0xb3, 0xc5,
+	0x1f, 0x7b, 0x0e, 0xdf, 0x54, 0x15, 0xd0, 0x2f, 0x35, 0x32, 0xe9, 0x22, 0x6e, 0x79, 0xae, 0xae,
+	0xad, 0x6a, 0x6b, 0xd3, 0xd5, 0xcf, 0xb4, 0x67, 0x92, 0x8d, 0xfc, 0x47, 0xb2, 0xdb, 0x0d, 0x2f,
+	0x69, 0x1e, 0xee, 0xaf, 0x3b, 0x51, 0x70, 0x43, 0xb4, 0x43, 0x27, 0x69, 0x7a, 0x61, 0x43, 0xf9,
+	0x05, 0x12, 0x30, 0x88, 0x13, 0xf9, 0xeb, 0xa9, 0xf7, 0xfb, 0x5b, 0xe7, 0x92, 0x4d, 0xe4, 0xbf,
+	0x3b, 0x92, 0x4d, 0xb8, 0xd9, 0xef, 0xae, 0x64, 0x33, 0xc7, 0x81, 0x7f, 0xc7, 0xf0, 0xdc, 0xb7,
+	0xed, 0x24, 0x89, 0x8d, 0xce, 0x69, 0x65, 0x3c, 0xfb, 0xdd, 0x3d, 0xad, 0x14, 0x76, 0xbf, 0x3a,
+	0xab, 0x68, 0x27, 0x67, 0x95, 0xc2, 0x87, 0x99, 0x33, 0x2e, 0xfd, 0xb3, 0x46, 0x66, 0xbc, 0x30,
+	0x89, 0x23, 0xf7, 0xd0, 0xe1, 0xae, 0xb5, 0xdf, 0xd6, 0x47, 0x51, 0xf0, 0xd3, 0xff, 0x4b, 0x70,
+	0x47, 0xb2, 0xe9, 0x9e, 0xd7, 0x6a, 0xbb, 0x2b, 0xd9, 0xd5, 0x54, 0xa8, 0x02, 0x16, 0x92, 0x17,
+	0x06, 0x50, 0x10, 0x6c, 0x96, 0x3c, 0x50, 0x87, 0x2c, 0xf2, 0xd0, 0x89, 0xdb, 0x2d, 0xc8, 0xb1,
+	0xd5, 0xb2, 0x85, 0x38, 0x8a, 0x62, 0x57, 0x1f, 0x5b, 0xd5, 0xd6, 0x26, 0xab, 0x1b, 0x1d, 0xc9,
+	0x68, 0x8f, 0xde, 0xcd, 0xd8, 0xae, 0x64, 0x3a, 0x86, 0x1d, 0xa4, 0x0c, 0x73, 0x88, 0xbd, 0xf1,
+	0x79, 0x85, 0x2c, 0xa6, 0x0b, 0x5b, 0x5e, 0xd2, 0x1a, 0x19, 0xcd, 0x96, 0x72, 0xb2, 0xba, 0x79,
+	0x2e, 0xd9, 0x28, 0x7e, 0xe2, 0xa8, 0x07, 0x11, 0x56, 0x4a, 0x2b, 0xb0, 0x1a, 0x46, 0x2e, 0xaf,
+	0xdb, 0x87, 0x7e, 0x72, 0xc7, 0x48, 0xe2, 0x43, 0xae, 0x2e, 0xc9, 0xc9, 0x59, 0x65, 0xf4, 0xfe,
+	0xd6, 0x17, 0xf0, 0x6d, 0xa3, 0x9e, 0x4b, 0x7f, 0x40, 0x2e, 0xfa, 0xf6, 0x3e, 0xf7, 0x31, 0xe3,
+	0x93, 0xd5, 0x6f, 0x77, 0x24, 0x4b, 0x81, 0xae, 0x64, 0xab, 0xe8, 0x14, 0x47, 0x99, 0xdf, 0x98,
+	0x8b, 0xc4, 0x8e, 0x93, 0x3b, 0x46, 0xdd, 0xf6, 0x05, 0xba, 0x25, 0x3d, 0xfa, 0xe9, 0x59, 0x65,
+	0xc4, 0x4c, 0x27, 0xd3, 0x06, 0x99, 0xab, 0x7b, 0x3e, 0x17, 0x6d, 0x91, 0xf0, 0xc0, 0x82, 0xfd,
+	0x8d, 0x49, 0x9a, 0xdd, 0xa0, 0xeb, 0x75, 0xb1, 0xbe, 0x5d, 0x50, 0x7b, 0xed, 0x16, 0xaf, 0xbe,
+	0xd5, 0x91, 0x6c, 0xb6, 0x5e, 0xc2, 0xba, 0x92, 0x5d, 0xc6, 0xe8, 0x65, 0xd8, 0x30, 0xfb, 0xec,
+	0xe8, 0x0e, 0xb9, 0xd0, 0xb2, 0x93, 0xa6, 0x7e, 0x01, 0xe5, 0xbf, 0xdf, 0x91, 0x0c, 0xc7, 0x5d,
+	0xc9, 0x5e, 0xc6, 0xf9, 0x30, 0xc8, 0xc4, 0x17, 0x29, 0xf9, 0x14, 0x84, 0x4f, 0x16, 0xcc, 0x8b,
+	0xd3, 0x8a, 0xf6, 0xa9, 0x89, 0xd3, 0xe8, 0x2e, 0xb9, 0x80, 0x62, 0x2f, 0x66, 0x62, 0xd3, 0xd3,
+	0xbb, 0x9e, 0x2e, 0x07, 0x8a, 0x5d, 0x83, 0x10, 0x49, 0x2a, 0x71, 0x0e, 0x43, 0xc0, 0xa0, 0xd8,
+	0x46, 0x93, 0xc5, 0xc8, 0x44, 0x2b, 0xfa, 0x13, 0x32, 0x9e, 0xee, 0x73, 0xa1, 0x5f, 0x5a, 0x1d,
+	0x5b, 0x9b, 0xda, 0x78, 0xad, 0xec, 0x74, 0xc8, 0xe1, 0xad, 0x32, 0xd8, 0xf6, 0x1d, 0xc9, 0xf2,
+	0x99, 0x5d, 0xc9, 0xa6, 0x31, 0x54, 0x3a, 0x36, 0xcc, 0x9c, 0xa0, 0xbf, 0xd3, 0xc8, 0x42, 0xcc,
+	0x85, 0x63, 0x87, 0x96, 0x17, 0x26, 0x3c, 0x7e, 0x6c, 0xfb, 0x96, 0xd0, 0xc7, 0x57, 0xb5, 0xb5,
+	0x8b, 0xd5, 0x46, 0x47, 0xb2, 0xb9, 0x94, 0xbc, 0x9f, 0x71, 0xb5, 0xae, 0x64, 0x6f, 0xa2, 0xa7,
+	0x3e, 0xbc, 0x3f, 0x45, 0xef, 0xbe, 0x77, 0xf3, 0xa6, 0xf1, 0x42, 0xb2, 0x31, 0x2f, 0x4c, 0x3a,
+	0xa7, 0x95, 0xcb, 0xc3, 0xcc, 0x5f, 0x9c, 0x56, 0x2e, 0x80, 0x9d, 0xd9, 0x1f, 0x84, 0xfe, 0x43,
+	0x23, 0xb4, 0x2e, 0xac, 0x23, 0x3b, 0x71, 0x9a, 0x3c, 0xb6, 0x78, 0x68, 0xef, 0xfb, 0xdc, 0xd5,
+	0x27, 0x56, 0xb5, 0xb5, 0x89, 0xea, 0x6f, 0xb4, 0x73, 0xc9, 0xe6, 0xb7, 0x6b, 0x8f, 0x52, 0xf6,
+	0x5e, 0x4a, 0x76, 0x24, 0x9b, 0xaf, 0x8b, 0x32, 0xd6, 0x95, 0xec, 0xad, 0x74, 0x13, 0xf4, 0x11,
+	0xfd, 0x6a, 0xf3, 0x3d, 0xbe, 0x34, 0xd4, 0x10, 0x74, 0x82, 0xc5, 0xc9, 0x59, 0x65, 0x20, 0xac,
+	0x39, 0x10, 0x94, 0xfe, 0xbd, 0x2c, 0xde, 0xe5, 0xbe, 0xdd, 0xb6, 0x84, 0x3e, 0x89, 0x39, 0xfd,
+	0x35, 0x88, 0x9f, 0x2b, 0xbc, 0x6c, 0x01, 0x59, 0x83, 0x3c, 0x17, 0x6e, 0x52, 0xa8, 0x2b, 0xd9,
+	0xf5, 0xb2, 0xf4, 0x14, 0xef, 0x57, 0x7e, 0xab, 0x94, 0xe5, 0x61, 0xc6, 0x2f, 0x4e, 0x2b, 0xa3,
+	0xb7, 0x6e, 0x9e, 0x9c, 0x55, 0xfa, 0xa3, 0x9a, 0xfd, 0x31, 0xe9, 0x4f, 0xc9, 0xb4, 0xd7, 0x08,
+	0xa3, 0x98, 0x5b, 0x2d, 0x1e, 0x07, 0x42, 0x27, 0x98, 0xef, 0xbb, 0x1d, 0xc9, 0xa6, 0x52, 0x7c,
+	0x17, 0xe0, 0xae, 0x64, 0x57, 0xd2, 0x6a, 0xd1, 0xc3, 0x8a, 0xed, 0x3b, 0xdf, 0x0f, 0x9a, 0xea,
+	0x54, 0xfa, 0x73, 0x8d, 0xcc, 0xda, 0x87, 0x49, 0x64, 0x85, 0x51, 0x1c, 0xd8, 0xbe, 0xf7, 0x84,
+	0xeb, 0x53, 0x18, 0xe4, 0xa3, 0x8e, 0x64, 0x33, 0xc0, 0x7c, 0x98, 0x13, 0x45, 0x06, 0x4a, 0xe8,
+	0xd7, 0xad, 0x1c, 0x1d, 0xb4, 0xca, 0x97, 0xcd, 0x2c, 0xfb, 0xa5, 0x11, 0x99, 0x09, 0xbc, 0xd0,
+	0x72, 0x3d, 0x71, 0x60, 0xd5, 0x63, 0xce, 0xf5, 0xe9, 0x55, 0x6d, 0x6d, 0x6a, 0x63, 0x3a, 0x3f,
+	0x56, 0x35, 0xef, 0x09, 0xaf, 0xde, 0xcd, 0x4e, 0xd0, 0x54, 0xe0, 0x85, 0x5b, 0x9e, 0x38, 0xd8,
+	0x8e, 0x39, 0x28, 0x62, 0xa8, 0x48, 0xc1, 0xd4, 0xa5, 0x58, 0xbd, 0x66, 0xbc, 0x38, 0xad, 0x8c,
+	0xdd, 0x5a, 0xbd, 0x66, 0xaa, 0xd3, 0x68, 0x83, 0x90, 0xde, 0x3d, 0xaf, 0xcf, 0x60, 0x34, 0x96,
+	0x47, 0xfb, 0x61, 0xc1, 0x94, 0x8f, 0xf0, 0x1b, 0x99, 0x00, 0x65, 0x6a, 0x57, 0xb2, 0x79, 0x8c,
+	0xdf, 0x83, 0x0c, 0x53, 0xe1, 0xe9, 0x5d, 0x32, 0xee, 0x44, 0x2d, 0x8f, 0xc7, 0x42, 0x9f, 0xc5,
+	0xdd, 0xf6, 0x3a, 0xd4, 0x80, 0x0c, 0x2a, 0xae, 0xd9, 0x6c, 0x9c, 0xef, 0x1b, 0x33, 0x37, 0xa0,
+	0xff, 0xd4, 0xc8, 0x15, 0xe8, 0x30, 0x78, 0x6c, 0x05, 0xf6, 0xb1, 0xd5, 0xe2, 0xa1, 0xeb, 0x85,
+	0x0d, 0xeb, 0xc0, 0xdb, 0xd7, 0xe7, 0xd0, 0xdd, 0xef, 0x61, 0xf3, 0x2e, 0xee, 0xa2, 0xc9, 0x8e,
+	0x7d, 0xbc, 0x9b, 0x1a, 0x3c, 0xf0, 0xaa, 0x1d, 0xc9, 0x16, 0x5b, 0x83, 0x70, 0x57, 0xb2, 0x97,
+	0xd2, 0x22, 0x3a, 0xc8, 0x29, 0xdb, 0x76, 0xe8, 0xd4, 0xe1, 0xf0, 0xc9, 0x59, 0x65, 0x58, 0x7c,
+	0x73, 0x88, 0xed, 0x3e, 0xa4, 0xa3, 0x69, 0x8b, 0x26, 0xa4, 0x63, 0xbe, 0x97, 0x8e, 0x0c, 0x2a,
+	0xd2, 0x91, 0x8d, 0x7b, 0xe9, 0xc8, 0x00, 0xfa, 0x01, 0xb9, 0x88, 0xbd, 0x96, 0xbe, 0x80, 0xb5,
+	0x7c, 0x21, 0x5f, 0x31, 0x88, 0xff, 0x10, 0x88, 0xaa, 0x0e, 0x97, 0x1d, 0xda, 0x74, 0x25, 0x9b,
+	0x42, 0x6f, 0x38, 0x32, 0xcc, 0x14, 0xa5, 0x0f, 0xc8, 0x4c, 0x76, 0xa0, 0x5c, 0xee, 0xf3, 0x84,
+	0xeb, 0x14, 0x37, 0xfb, 0x1b, 0xd8, 0x59, 0x20, 0xb1, 0x85, 0x78, 0x57, 0x32, 0xaa, 0x1c, 0xa9,
+	0x14, 0x34, 0xcc, 0x92, 0x0d, 0x3d, 0x26, 0x3a, 0xd6, 0xe9, 0x56, 0x1c, 0x35, 0x62, 0x2e, 0x84,
+	0x5a, 0xb0, 0x17, 0xf1, 0xfb, 0xe0, 0xf2, 0x5d, 0x02, 0x9b, 0xdd, 0xcc, 0x44, 0x2d, 0xdb, 0xe9,
+	0x75, 0x36, 0x94, 0x2d, 0xbe, 0x7d, 0xf8, 0x64, 0x5a, 0x23, 0xb3, 0xd9, 0xbe, 0x68, 0xd9, 0x87,
+	0x82, 0x5b, 0x42, 0xbf, 0x8c, 0xf1, 0xde, 0x81, 0xef, 0x48, 0x99, 0x5d, 0x20, 0x6a, 0xc5, 0x77,
+	0xa8, 0x60, 0xe1, 0xbd, 0x64, 0x4a, 0x39, 0x99, 0x81, 0x5d, 0x06, 0x49, 0xf5, 0x3d, 0x27, 0x11,
+	0xfa, 0x12, 0xfa, 0xfc, 0x0e, 0xf8, 0x0c, 0xec, 0xe3, 0xcd, 0x1c, 0xef, 0x9d, 0x3a, 0x05, 0x1c,
+	0x5a, 0x01, 0xd3, 0x4a, 0x67, 0x96, 0x66, 0x53, 0x97, 0x5c, 0x76, 0x3d, 0x01, 0x95, 0xd9, 0x12,
+	0x2d, 0x3b, 0x16, 0xdc, 0xc2, 0x06, 0x40, 0xbf, 0x82, 0x2b, 0x81, 0x2d, 0x57, 0xc6, 0xd7, 0x90,
+	0xc6, 0xd6, 0xa2, 0x68, 0xb9, 0x06, 0x29, 0xc3, 0x1c, 0x62, 0xaf, 0x46, 0x49, 0x78, 0xd0, 0xb2,
+	0xbc, 0xd0, 0xe5, 0xc7, 0x5c, 0xe8, 0x57, 0x07, 0xa2, 0xec, 0xf1, 0xa0, 0x75, 0x3f, 0x65, 0xfb,
+	0xa3, 0x28, 0x54, 0x2f, 0x8a, 0x02, 0xd2, 0x0d, 0x72, 0x09, 0x17, 0xc0, 0xd5, 0x75, 0xf4, 0xbb,
+	0xdc, 0x91, 0x2c, 0x43, 0x8a, 0x1b, 0x3e, 0x1d, 0x1a, 0x66, 0x86, 0xd3, 0x84, 0x5c, 0x3d, 0xe2,
+	0xf6, 0x81, 0x05, 0xbb, 0xda, 0x4a, 0x9a, 0x31, 0x17, 0xcd, 0xc8, 0x77, 0xad, 0x96, 0x93, 0xe8,
+	0x2f, 0x61, 0xc2, 0xa1, 0xbc, 0x5f, 0x06, 0x93, 0xef, 0xda, 0xa2, 0xb9, 0x97, 0x1b, 0xec, 0x3a,
+	0x49, 0x57, 0xb2, 0x65, 0x74, 0x39, 0x8c, 0x2c, 0x16, 0x75, 0xe8, 0x54, 0xba, 0x49, 0xa6, 0x02,
+	0x3b, 0x3e, 0xe0, 0xb1, 0x15, 0xda, 0x01, 0xd7, 0x97, 0xb1, 0xb9, 0x32, 0xa0, 0x9c, 0xa5, 0xf0,
+	0x87, 0x76, 0xc0, 0x8b, 0x72, 0xd6, 0x83, 0x0c, 0x53, 0xe1, 0x69, 0x9b, 0x2c, 0xc3, 0x23, 0xc6,
+	0x8a, 0x8e, 0x42, 0x1e, 0x8b, 0xa6, 0xd7, 0xb2, 0xea, 0x71, 0x14, 0x58, 0x2d, 0x3b, 0xe6, 0x61,
+	0xa2, 0xbf, 0x8c, 0x29, 0xf8, 0x66, 0x47, 0xb2, 0xab, 0x60, 0xf5, 0x30, 0x37, 0xda, 0x8e, 0xa3,
+	0x60, 0x17, 0x4d, 0xba, 0x92, 0xbd, 0x9a, 0x57, 0xbc, 0x61, 0xbc, 0x61, 0x7e, 0xdd, 0x4c, 0xfa,
+	0x4b, 0x8d, 0x2c, 0x04, 0x91, 0x6b, 0x25, 0x5e, 0xc0, 0xad, 0x23, 0x2f, 0x74, 0xa3, 0x23, 0x4b,
+	0xe8, 0xaf, 0x60, 0xc2, 0x3e, 0x3e, 0x97, 0x6c, 0xc1, 0xb4, 0x8f, 0x76, 0x22, 0x77, 0xcf, 0x0b,
+	0xf8, 0x23, 0x64, 0xe1, 0x0e, 0x9f, 0x0d, 0x4a, 0x48, 0xd1, 0x82, 0x96, 0xe1, 0x3c, 0x73, 0x27,
+	0x67, 0x95, 0x41, 0x2f, 0x66, 0x9f, 0x0f, 0xfa, 0x54, 0x23, 0x4b, 0xd9, 0x31, 0x71, 0x0e, 0x63,
+	0xd0, 0x66, 0x1d, 0xc5, 0x5e, 0xc2, 0x85, 0xfe, 0x2a, 0x8a, 0xf9, 0x3e, 0x94, 0xde, 0x74, 0xc3,
+	0x67, 0xfc, 0x23, 0xa4, 0xbb, 0x92, 0x5d, 0x53, 0x4e, 0x4d, 0x89, 0x53, 0x0e, 0xcf, 0x86, 0x72,
+	0x76, 0xb4, 0x0d, 0x73, 0x98, 0x27, 0x28, 0x62, 0xf9, 0xde, 0xae, 0xc3, 0x8b, 0x49, 0x5f, 0xe9,
+	0x15, 0xb1, 0x8c, 0xd8, 0x06, 0xbc, 0x38, 0xfc, 0x2a, 0x68, 0x98, 0x25, 0x1b, 0xea, 0x93, 0x79,
+	0x7c, 0xc9, 0x5a, 0x50, 0x0b, 0xac, 0xb4, 0xbe, 0x32, 0xac, 0xaf, 0x57, 0xf2, 0xfa, 0x5a, 0x05,
+	0xbe, 0x57, 0x64, 0xb1, 0xb9, 0xdf, 0x2f, 0x61, 0x45, 0x66, 0xcb, 0xb0, 0x61, 0xf6, 0xd9, 0xd1,
+	0xcf, 0x34, 0xb2, 0x80, 0x5b, 0x08, 0x1f, 0xc2, 0x56, 0xfa, 0x12, 0xd6, 0x57, 0x31, 0xde, 0x22,
+	0x3c, 0x24, 0x36, 0xa3, 0x56, 0xdb, 0x04, 0x6e, 0x07, 0xa9, 0xea, 0x03, 0x68, 0xc5, 0x9c, 0x32,
+	0xd8, 0x95, 0x6c, 0xad, 0xd8, 0x46, 0x0a, 0xae, 0xa4, 0x51, 0x24, 0x76, 0xe8, 0xda, 0xb1, 0x0b,
+	0xf7, 0xff, 0x44, 0x3e, 0x30, 0xfb, 0x1d, 0xd1, 0x3f, 0x81, 0x1c, 0x1b, 0x0a, 0x28, 0x0f, 0x85,
+	0x97, 0x78, 0x8f, 0x21, 0xa3, 0xfa, 0x6b, 0x98, 0xce, 0x63, 0xe8, 0x0b, 0x37, 0x6d, 0xc1, 0x6b,
+	0x39, 0xb7, 0x8d, 0x7d, 0xa1, 0x53, 0x86, 0xba, 0x92, 0x2d, 0xa5, 0x62, 0xca, 0x38, 0xf4, 0x40,
+	0x03, 0xb6, 0x83, 0x10, 0xb4, 0x81, 0x7d, 0x41, 0xcc, 0x3e, 0x1b, 0x41, 0xff, 0xa8, 0x91, 0xf9,
+	0x7a, 0xe4, 0xfb, 0xd1, 0x91, 0xf5, 0xc9, 0x61, 0xe8, 0x40, 0x3b, 0x22, 0x74, 0xa3, 0xa7, 0xf2,
+	0x7b, 0x39, 0xf8, 0x81, 0xd8, 0xf2, 0x62, 0x01, 0x2a, 0x3f, 0x29, 0x43, 0x85, 0xca, 0x3e, 0x1c,
+	0x55, 0xf6, 0xdb, 0x0e, 0x42, 0xa0, 0xb2, 0x2f, 0x88, 0x39, 0x97, 0x2a, 0x2a, 0x60, 0xfa, 0x90,
+	0xcc, 0xc2, 0x8e, 0xea, 0x55, 0x07, 0xfd, 0x75, 0x94, 0x08, 0xef, 0xab, 0x19, 0x60, 0x8a, 0x73,
+	0xdd, 0x95, 0x6c, 0x31, 0xbd, 0xfc, 0x54, 0xd4, 0x30, 0xcb, 0x56, 0xe8, 0x90, 0x87, 0xae, 0xe2,
+	0xb0, 0xa2, 0x38, 0xe4, 0xa1, 0x3b, 0xc4, 0xa1, 0x8a, 0x82, 0x43, 0x75, 0x0c, 0x45, 0x10, 0x15,
+	0x1e, 0x43, 0x37, 0x2a, 0xf4, 0x6b, 0xe8, 0x0d, 0x8b, 0x20, 0xc0, 0x3f, 0x42, 0xb4, 0x28, 0x82,
+	0x3d, 0xc8, 0x30, 0x15, 0x1e, 0x9d, 0x80, 0xaa, 0xcc, 0xc9, 0x1b, 0x8a, 0x13, 0x1e, 0xba, 0xfd,
+	0x4e, 0x0a, 0x08, 0x9c, 0x14, 0x03, 0x68, 0xec, 0x71, 0x3e, 0xdc, 0x7d, 0x09, 0x8f, 0xf5, 0xeb,
+	0xd8, 0x83, 0x2e, 0xe6, 0x27, 0x0e, 0xad, 0xb6, 0x91, 0xaa, 0xae, 0xe5, 0x8d, 0xef, 0x71, 0x0f,
+	0xec, 0x4a, 0xb6, 0x80, 0xfe, 0x15, 0xcc, 0x30, 0x55, 0x0b, 0x7a, 0x40, 0x26, 0x63, 0x6e, 0xbb,
+	0x56, 0x14, 0xfa, 0x6d, 0xfd, 0x2f, 0xdb, 0xa8, 0x72, 0xe7, 0x5c, 0x32, 0xba, 0xc5, 0x5b, 0x31,
+	0x77, 0xec, 0x84, 0xbb, 0x26, 0xb7, 0xdd, 0x87, 0xa1, 0xdf, 0xee, 0x48, 0xa6, 0xbd, 0x53, 0xfc,
+	0x97, 0x12, 0x47, 0xd8, 0xac, 0xbf, 0x1d, 0x05, 0x1e, 0xdc, 0x9c, 0x49, 0x1b, 0xff, 0x4b, 0x19,
+	0x40, 0x75, 0xcd, 0x9c, 0x88, 0x33, 0x07, 0xf4, 0x67, 0x64, 0xa1, 0xd4, 0xc1, 0xe3, 0x6d, 0xf6,
+	0x57, 0x08, 0xaa, 0x55, 0xef, 0x9d, 0x4b, 0xa6, 0xf7, 0x82, 0xee, 0xf4, 0xfa, 0xf0, 0x5d, 0x27,
+	0xc9, 0x43, 0xaf, 0xf4, 0xb7, 0xf1, 0xbb, 0x4e, 0xa2, 0x28, 0xd0, 0x35, 0x73, 0xb6, 0x4c, 0xd2,
+	0x1f, 0x93, 0xf1, 0xb4, 0x7b, 0x11, 0xfa, 0x97, 0xdb, 0x58, 0x79, 0xbf, 0x05, 0xd7, 0x40, 0x2f,
+	0x50, 0xda, 0x95, 0x8a, 0xf2, 0xc7, 0x65, 0x53, 0x14, 0xd7, 0x59, 0xb9, 0xd5, 0x35, 0x33, 0xf7,
+	0x47, 0x0f, 0xc8, 0x2c, 0xf6, 0x75, 0xbd, 0x7d, 0xf7, 0xb7, 0x34, 0x7f, 0x9b, 0xe7, 0x92, 0x5d,
+	0xed, 0x45, 0xa8, 0x39, 0x76, 0x58, 0x6c, 0xae, 0x3c, 0xce, 0xab, 0x45, 0x57, 0x57, 0x50, 0xe5,
+	0x0f, 0x99, 0x29, 0x71, 0xc6, 0x2f, 0xc6, 0xc8, 0x94, 0xb2, 0xdc, 0xf4, 0x63, 0x32, 0xce, 0xc3,
+	0x24, 0xf6, 0xb8, 0xd0, 0x35, 0xfc, 0x77, 0x41, 0x1f, 0xb2, 0x29, 0xee, 0x85, 0x49, 0xdc, 0xae,
+	0x5e, 0xcf, 0xff, 0x54, 0xc8, 0x26, 0x14, 0x3d, 0x2f, 0x8c, 0x71, 0xd9, 0x2e, 0xe2, 0x2f, 0x33,
+	0x37, 0xa0, 0x9f, 0x67, 0x97, 0x97, 0xf0, 0xc2, 0x86, 0xcf, 0x2d, 0x64, 0x2d, 0x01, 0x8f, 0xbe,
+	0x51, 0x4c, 0x61, 0x1d, 0xfa, 0xa2, 0xc0, 0x3e, 0xae, 0x21, 0x8f, 0x51, 0x6a, 0xea, 0xcb, 0x6f,
+	0x90, 0x2a, 0xf5, 0x7d, 0x1b, 0xb7, 0x95, 0x47, 0xc4, 0x10, 0x3f, 0xf0, 0x00, 0x04, 0x2b, 0x73,
+	0x08, 0x47, 0x9f, 0x90, 0x59, 0x90, 0x96, 0x44, 0x09, 0x34, 0xd0, 0xa0, 0x69, 0x0c, 0x35, 0xed,
+	0x65, 0xfd, 0xe7, 0x1e, 0x10, 0x99, 0x9a, 0xd7, 0x72, 0x35, 0x05, 0xa8, 0xe8, 0xb8, 0x7d, 0xf3,
+	0xfd, 0xf7, 0x14, 0x1d, 0xa5, 0xb9, 0xa0, 0x00, 0x78, 0xb3, 0x84, 0x1a, 0x7f, 0xd0, 0xc8, 0x7c,
+	0x7f, 0x7a, 0xe1, 0xb9, 0x11, 0xc0, 0x6b, 0x3c, 0xfb, 0x83, 0xee, 0x1b, 0xf0, 0xb6, 0x40, 0x40,
+	0xe9, 0x93, 0x12, 0xa7, 0x59, 0xbc, 0xb4, 0x49, 0x6f, 0x68, 0xa6, 0x86, 0x74, 0x9b, 0x5c, 0x82,
+	0x87, 0xbb, 0x97, 0x60, 0x7e, 0x27, 0xaa, 0xeb, 0xd8, 0x1f, 0x22, 0x52, 0x1c, 0xe1, 0x74, 0x58,
+	0x78, 0x99, 0x52, 0xc6, 0x66, 0x66, 0x5b, 0x7d, 0xf0, 0xec, 0xab, 0x95, 0x91, 0xb3, 0xaf, 0x56,
+	0x46, 0x9e, 0x9d, 0xaf, 0x68, 0x67, 0xe7, 0x2b, 0xda, 0x6f, 0x9f, 0xaf, 0x8c, 0x7c, 0xf1, 0x7c,
+	0x45, 0x3b, 0x7b, 0xbe, 0x32, 0xf2, 0xef, 0xe7, 0x2b, 0x23, 0x1f, 0xbd, 0xf9, 0x3f, 0xfc, 0x9f,
+	0x9a, 0xee, 0xa3, 0xfd, 0x4b, 0xf8, 0xbf, 0xea, 0xbb, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x9a,
+	0x47, 0x7c, 0xbb, 0x75, 0x17, 0x00, 0x00,
 }
 
 func (m *FolderDeviceConfiguration) Marshal() (dAtA []byte, err error) {
@@ -355,6 +464,20 @@ func (m *FolderConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	if m.DeprecatedScanOwnership {
+		i--
+		if m.DeprecatedScanOwnership {
+			dAtA[i] = 1
+		} else {
+			dAtA[i] = 0
+		}
+		i--
+		dAtA[i] = 0x4
+		i--
+		dAtA[i] = 0xb2
+		i--
+		dAtA[i] = 0xd8
+	}
 	if m.DeprecatedPullers != 0 {
 		i = encodeVarintFolderconfiguration(dAtA, i, uint64(m.DeprecatedPullers))
 		i--
@@ -388,9 +511,45 @@ func (m *FolderConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 		i--
 		dAtA[i] = 0xc0
 	}
-	if m.ScanOwnership {
+	{
+		size, err := m.XattrFilter.MarshalToSizedBuffer(dAtA[:i])
+		if err != nil {
+			return 0, err
+		}
+		i -= size
+		i = encodeVarintFolderconfiguration(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0x2
+	i--
+	dAtA[i] = 0xba
+	if m.SendXattrs {
 		i--
-		if m.ScanOwnership {
+		if m.SendXattrs {
+			dAtA[i] = 1
+		} else {
+			dAtA[i] = 0
+		}
+		i--
+		dAtA[i] = 0x2
+		i--
+		dAtA[i] = 0xb0
+	}
+	if m.SyncXattrs {
+		i--
+		if m.SyncXattrs {
+			dAtA[i] = 1
+		} else {
+			dAtA[i] = 0
+		}
+		i--
+		dAtA[i] = 0x2
+		i--
+		dAtA[i] = 0xa8
+	}
+	if m.SendOwnership {
+		i--
+		if m.SendOwnership {
 			dAtA[i] = 1
 		} else {
 			dAtA[i] = 0
@@ -705,6 +864,93 @@ func (m *FolderConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	return len(dAtA) - i, nil
 }
 
+func (m *XattrFilter) Marshal() (dAtA []byte, err error) {
+	size := m.ProtoSize()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *XattrFilter) MarshalTo(dAtA []byte) (int, error) {
+	size := m.ProtoSize()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *XattrFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.MaxTotalSize != 0 {
+		i = encodeVarintFolderconfiguration(dAtA, i, uint64(m.MaxTotalSize))
+		i--
+		dAtA[i] = 0x18
+	}
+	if m.MaxSingleEntrySize != 0 {
+		i = encodeVarintFolderconfiguration(dAtA, i, uint64(m.MaxSingleEntrySize))
+		i--
+		dAtA[i] = 0x10
+	}
+	if len(m.Entries) > 0 {
+		for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- {
+			{
+				size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+				if err != nil {
+					return 0, err
+				}
+				i -= size
+				i = encodeVarintFolderconfiguration(dAtA, i, uint64(size))
+			}
+			i--
+			dAtA[i] = 0xa
+		}
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *XattrFilterEntry) Marshal() (dAtA []byte, err error) {
+	size := m.ProtoSize()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *XattrFilterEntry) MarshalTo(dAtA []byte) (int, error) {
+	size := m.ProtoSize()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *XattrFilterEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.Permit {
+		i--
+		if m.Permit {
+			dAtA[i] = 1
+		} else {
+			dAtA[i] = 0
+		}
+		i--
+		dAtA[i] = 0x10
+	}
+	if len(m.Match) > 0 {
+		i -= len(m.Match)
+		copy(dAtA[i:], m.Match)
+		i = encodeVarintFolderconfiguration(dAtA, i, uint64(len(m.Match)))
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
 func encodeVarintFolderconfiguration(dAtA []byte, offset int, v uint64) int {
 	offset -= sovFolderconfiguration(v)
 	base := offset
@@ -849,9 +1095,17 @@ func (m *FolderConfiguration) ProtoSize() (n int) {
 	if m.SyncOwnership {
 		n += 3
 	}
-	if m.ScanOwnership {
+	if m.SendOwnership {
+		n += 3
+	}
+	if m.SyncXattrs {
+		n += 3
+	}
+	if m.SendXattrs {
 		n += 3
 	}
+	l = m.XattrFilter.ProtoSize()
+	n += 2 + l + sovFolderconfiguration(uint64(l))
 	if m.DeprecatedReadOnly {
 		n += 4
 	}
@@ -861,6 +1115,46 @@ func (m *FolderConfiguration) ProtoSize() (n int) {
 	if m.DeprecatedPullers != 0 {
 		n += 3 + sovFolderconfiguration(uint64(m.DeprecatedPullers))
 	}
+	if m.DeprecatedScanOwnership {
+		n += 4
+	}
+	return n
+}
+
+func (m *XattrFilter) ProtoSize() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if len(m.Entries) > 0 {
+		for _, e := range m.Entries {
+			l = e.ProtoSize()
+			n += 1 + l + sovFolderconfiguration(uint64(l))
+		}
+	}
+	if m.MaxSingleEntrySize != 0 {
+		n += 1 + sovFolderconfiguration(uint64(m.MaxSingleEntrySize))
+	}
+	if m.MaxTotalSize != 0 {
+		n += 1 + sovFolderconfiguration(uint64(m.MaxTotalSize))
+	}
+	return n
+}
+
+func (m *XattrFilterEntry) ProtoSize() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.Match)
+	if l > 0 {
+		n += 1 + l + sovFolderconfiguration(uint64(l))
+	}
+	if m.Permit {
+		n += 2
+	}
 	return n
 }
 
@@ -1821,7 +2115,47 @@ func (m *FolderConfiguration) Unmarshal(dAtA []byte) error {
 			m.SyncOwnership = bool(v != 0)
 		case 36:
 			if wireType != 0 {
-				return fmt.Errorf("proto: wrong wireType = %d for field ScanOwnership", wireType)
+				return fmt.Errorf("proto: wrong wireType = %d for field SendOwnership", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				v |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.SendOwnership = bool(v != 0)
+		case 37:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field SyncXattrs", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				v |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.SyncXattrs = bool(v != 0)
+		case 38:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field SendXattrs", wireType)
 			}
 			var v int
 			for shift := uint(0); ; shift += 7 {
@@ -1838,7 +2172,40 @@ func (m *FolderConfiguration) Unmarshal(dAtA []byte) error {
 					break
 				}
 			}
-			m.ScanOwnership = bool(v != 0)
+			m.SendXattrs = bool(v != 0)
+		case 39:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field XattrFilter", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.XattrFilter.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		case 9000:
 			if wireType != 0 {
 				return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedReadOnly", wireType)
@@ -1889,6 +2256,250 @@ func (m *FolderConfiguration) Unmarshal(dAtA []byte) error {
 					break
 				}
 			}
+		case 9003:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedScanOwnership", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				v |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.DeprecatedScanOwnership = bool(v != 0)
+		default:
+			iNdEx = preIndex
+			skippy, err := skipFolderconfiguration(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *XattrFilter) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowFolderconfiguration
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: XattrFilter: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: XattrFilter: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Entries = append(m.Entries, XattrFilterEntry{})
+			if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field MaxSingleEntrySize", wireType)
+			}
+			m.MaxSingleEntrySize = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.MaxSingleEntrySize |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 3:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field MaxTotalSize", wireType)
+			}
+			m.MaxTotalSize = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.MaxTotalSize |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		default:
+			iNdEx = preIndex
+			skippy, err := skipFolderconfiguration(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *XattrFilterEntry) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowFolderconfiguration
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: XattrFilterEntry: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: XattrFilterEntry: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Match", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthFolderconfiguration
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Match = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Permit", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowFolderconfiguration
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				v |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.Permit = bool(v != 0)
 		default:
 			iNdEx = preIndex
 			skippy, err := skipFolderconfiguration(dAtA[iNdEx:])
diff --git a/lib/config/migrations.go b/lib/config/migrations.go
index 5bfd30c9c12..5bafb47019f 100644
--- a/lib/config/migrations.go
+++ b/lib/config/migrations.go
@@ -27,6 +27,7 @@ import (
 // put the newest on top for readability.
 var (
 	migrations = migrationSet{
+		{37, migrateToConfigV37},
 		{36, migrateToConfigV36},
 		{35, migrateToConfigV35},
 		{34, migrateToConfigV34},
@@ -95,6 +96,14 @@ func (m migration) apply(cfg *Configuration) {
 	cfg.Version = m.targetVersion
 }
 
+func migrateToConfigV37(cfg *Configuration) {
+	// "scan ownership" changed name to "send ownership"
+	for i := range cfg.Folders {
+		cfg.Folders[i].SendOwnership = cfg.Folders[i].DeprecatedScanOwnership
+		cfg.Folders[i].DeprecatedScanOwnership = false
+	}
+}
+
 func migrateToConfigV36(cfg *Configuration) {
 	for i := range cfg.Folders {
 		delete(cfg.Folders[i].Versioning.Params, "cleanInterval")
diff --git a/lib/db/structs.go b/lib/db/structs.go
index e23c91f690c..daa514fab7a 100644
--- a/lib/db/structs.go
+++ b/lib/db/structs.go
@@ -125,6 +125,14 @@ func (f FileInfoTruncated) FileModifiedBy() protocol.ShortID {
 	return f.ModifiedBy
 }
 
+func (f FileInfoTruncated) PlatformData() protocol.PlatformData {
+	return f.Platform
+}
+
+func (f FileInfoTruncated) InodeChangeTime() time.Time {
+	return time.Unix(0, f.InodeChangeNs)
+}
+
 func (f FileInfoTruncated) ConvertToIgnoredFileInfo() protocol.FileInfo {
 	file := f.copyToFileInfo()
 	file.SetIgnored()
diff --git a/lib/db/structs.pb.go b/lib/db/structs.pb.go
index 8703708c4b7..a4d80af1f07 100644
--- a/lib/db/structs.pb.go
+++ b/lib/db/structs.pb.go
@@ -126,6 +126,7 @@ type FileInfoTruncated struct {
 	// see bep.proto
 	LocalFlags    uint32 `protobuf:"varint,1000,opt,name=local_flags,json=localFlags,proto3" json:"localFlags" xml:"localFlags"`
 	VersionHash   []byte `protobuf:"bytes,1001,opt,name=version_hash,json=versionHash,proto3" json:"versionHash" xml:"versionHash"`
+	InodeChangeNs int64  `protobuf:"varint,1002,opt,name=inode_change_ns,json=inodeChangeNs,proto3" json:"inodeChangeNs" xml:"inodeChangeNs"`
 	Deleted       bool   `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted" xml:"deleted"`
 	RawInvalid    bool   `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid" xml:"invalid"`
 	NoPermissions bool   `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"noPermissions" xml:"noPermissions"`
@@ -496,102 +497,104 @@ func init() {
 func init() { proto.RegisterFile("lib/db/structs.proto", fileDescriptor_5465d80e8cba02e3) }
 
 var fileDescriptor_5465d80e8cba02e3 = []byte{
-	// 1510 bytes of a gzipped FileDescriptorProto
+	// 1543 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcd, 0x6f, 0xdb, 0x46,
-	0x16, 0x37, 0x2d, 0xd9, 0x96, 0x46, 0xf2, 0x17, 0xb3, 0x36, 0xb8, 0xde, 0x5d, 0x8d, 0x76, 0xe2,
-	0x00, 0xda, 0x0f, 0xc8, 0x80, 0x83, 0x18, 0x8b, 0x00, 0xdb, 0x20, 0x8c, 0xeb, 0xc4, 0x41, 0x9a,
-	0x04, 0xe3, 0x20, 0x29, 0xda, 0x83, 0xc0, 0x8f, 0xb1, 0x4c, 0x84, 0x22, 0x55, 0x92, 0xb6, 0xa3,
-	0xdc, 0x7a, 0x29, 0xd0, 0x5b, 0x10, 0xf4, 0x50, 0x14, 0x45, 0x91, 0x53, 0xff, 0x84, 0xfe, 0x05,
-	0x45, 0x91, 0xa3, 0x8f, 0x45, 0x0f, 0x2c, 0x62, 0x5f, 0x5a, 0x1d, 0x75, 0xec, 0xa9, 0x98, 0x37,
-	0xc3, 0x21, 0x65, 0x23, 0x45, 0x92, 0xfa, 0xc6, 0xf7, 0x7b, 0xbf, 0xf7, 0x24, 0xbe, 0xf9, 0xbd,
-	0x37, 0x8f, 0xe8, 0x2f, 0xbe, 0x67, 0xaf, 0xb9, 0xf6, 0x5a, 0x9c, 0x44, 0xfb, 0x4e, 0x12, 0xb7,
-	0xfb, 0x51, 0x98, 0x84, 0xfa, 0xa4, 0x6b, 0xaf, 0x5c, 0x8c, 0x58, 0x3f, 0x8c, 0xd7, 0x00, 0xb0,
-	0xf7, 0x77, 0xd7, 0xba, 0x61, 0x37, 0x04, 0x03, 0x9e, 0x04, 0x71, 0x05, 0x77, 0xc3, 0xb0, 0xeb,
-	0xb3, 0x9c, 0x95, 0x78, 0x3d, 0x16, 0x27, 0x56, 0xaf, 0x2f, 0x09, 0xcb, 0x3c, 0x3f, 0x3c, 0x3a,
-	0xa1, 0xbf, 0x66, 0xb3, 0x0c, 0xaf, 0xb2, 0x27, 0x89, 0x78, 0x24, 0xdf, 0x4c, 0xa2, 0xda, 0x96,
-	0xe7, 0xb3, 0x87, 0x2c, 0x8a, 0xbd, 0x30, 0xd0, 0xef, 0xa0, 0x99, 0x03, 0xf1, 0x68, 0x68, 0x4d,
-	0xad, 0x55, 0x5b, 0x5f, 0x68, 0x67, 0x09, 0xda, 0x0f, 0x99, 0x93, 0x84, 0x91, 0xd9, 0x7c, 0x99,
-	0xe2, 0x89, 0x61, 0x8a, 0x33, 0xe2, 0x28, 0xc5, 0xb3, 0x4f, 0x7a, 0xfe, 0x55, 0x22, 0x6d, 0x42,
-	0x33, 0x8f, 0xbe, 0x81, 0x66, 0x5c, 0xe6, 0xb3, 0x84, 0xb9, 0xc6, 0x64, 0x53, 0x6b, 0x55, 0xcc,
-	0xbf, 0xf3, 0x38, 0x09, 0xa9, 0x38, 0x69, 0x13, 0x9a, 0x79, 0xf4, 0x2b, 0x3c, 0xee, 0xc0, 0x73,
-	0x58, 0x6c, 0x94, 0x9a, 0xa5, 0x56, 0xdd, 0xfc, 0x9b, 0x88, 0x03, 0x68, 0x94, 0xe2, 0xba, 0x8c,
-	0xe3, 0x36, 0x84, 0x81, 0x43, 0xa7, 0x68, 0xde, 0x0b, 0x0e, 0x2c, 0xdf, 0x73, 0x3b, 0x59, 0x78,
-	0x19, 0xc2, 0xff, 0x35, 0x4c, 0xf1, 0x9c, 0x74, 0x6d, 0xaa, 0x2c, 0x17, 0x20, 0xcb, 0x18, 0x4c,
-	0xe8, 0x29, 0x1a, 0xf9, 0x54, 0x43, 0x35, 0x59, 0x9c, 0x3b, 0x5e, 0x9c, 0xe8, 0x3e, 0xaa, 0xc8,
-	0xb7, 0x8b, 0x0d, 0xad, 0x59, 0x6a, 0xd5, 0xd6, 0xe7, 0xdb, 0xae, 0xdd, 0x2e, 0xd4, 0xd0, 0xbc,
-	0xc6, 0x0b, 0x74, 0x9c, 0xe2, 0x1a, 0xb5, 0x0e, 0x25, 0x16, 0x0f, 0x53, 0xac, 0xe2, 0xce, 0x14,
-	0xec, 0xf9, 0xd1, 0x6a, 0x91, 0x4b, 0x15, 0xf3, 0x6a, 0xf9, 0xcb, 0x17, 0x78, 0x82, 0x1c, 0xd5,
-	0xd0, 0x22, 0xff, 0x81, 0xed, 0x60, 0x37, 0x7c, 0x10, 0xed, 0x07, 0x8e, 0xc5, 0x8b, 0xf4, 0x6f,
-	0x54, 0x0e, 0xac, 0x1e, 0x83, 0x73, 0xaa, 0x9a, 0xcb, 0xc3, 0x14, 0x83, 0x3d, 0x4a, 0x31, 0x82,
-	0xec, 0xdc, 0x20, 0x14, 0x30, 0xce, 0x8d, 0xbd, 0xa7, 0xcc, 0x28, 0x35, 0xb5, 0x56, 0x49, 0x70,
-	0xb9, 0xad, 0xb8, 0xdc, 0x20, 0x14, 0x30, 0xfd, 0x1a, 0x42, 0xbd, 0xd0, 0xf5, 0x76, 0x3d, 0xe6,
-	0x76, 0x62, 0x63, 0x0a, 0x22, 0x9a, 0xc3, 0x14, 0x57, 0x33, 0x74, 0x67, 0x94, 0xe2, 0x79, 0x08,
-	0x53, 0x08, 0xa1, 0xb9, 0x57, 0xff, 0x4e, 0x43, 0x35, 0x95, 0xc1, 0x1e, 0x18, 0xf5, 0xa6, 0xd6,
-	0x2a, 0x9b, 0x5f, 0x68, 0xbc, 0x2c, 0x3f, 0xa5, 0xf8, 0x72, 0xd7, 0x4b, 0xf6, 0xf6, 0xed, 0xb6,
-	0x13, 0xf6, 0xd6, 0xe2, 0x41, 0xe0, 0x24, 0x7b, 0x5e, 0xd0, 0x2d, 0x3c, 0x15, 0x45, 0xdb, 0xde,
-	0xd9, 0x0b, 0xa3, 0x64, 0x7b, 0x73, 0x98, 0x62, 0xf5, 0xa7, 0xcc, 0xc1, 0x28, 0xc5, 0x0b, 0x63,
-	0xbf, 0x6f, 0x0e, 0xc8, 0x57, 0x47, 0xab, 0xef, 0x92, 0x98, 0x16, 0xd2, 0x16, 0xc5, 0x5f, 0xfd,
-	0xf3, 0xe2, 0xbf, 0x8a, 0x2a, 0x31, 0xfb, 0x64, 0x9f, 0x05, 0x0e, 0x33, 0x10, 0x54, 0xb1, 0xc1,
-	0x55, 0x90, 0x61, 0xa3, 0x14, 0xcf, 0x89, 0xda, 0x4b, 0x80, 0x50, 0xe5, 0xd3, 0xef, 0xa1, 0xb9,
-	0x78, 0xd0, 0xf3, 0xbd, 0xe0, 0x71, 0x27, 0xb1, 0xa2, 0x2e, 0x4b, 0x8c, 0x45, 0x38, 0xe5, 0xd6,
-	0x30, 0xc5, 0xb3, 0xd2, 0xf3, 0x00, 0x1c, 0x4a, 0xc7, 0x63, 0x28, 0xa1, 0xe3, 0x2c, 0xfd, 0x06,
-	0xaa, 0xd9, 0x7e, 0xe8, 0x3c, 0x8e, 0x3b, 0x7b, 0x56, 0xbc, 0x67, 0xe8, 0x4d, 0xad, 0x55, 0x37,
-	0x09, 0x2f, 0xab, 0x80, 0x6f, 0x59, 0xf1, 0x9e, 0x2a, 0x6b, 0x0e, 0x11, 0x5a, 0xf0, 0xeb, 0xef,
-	0xa1, 0x2a, 0x0b, 0x9c, 0x68, 0xd0, 0xe7, 0x0d, 0x7d, 0x01, 0x52, 0x80, 0x30, 0x14, 0xa8, 0x84,
-	0xa1, 0x10, 0x42, 0x73, 0xaf, 0x6e, 0xa2, 0x72, 0x32, 0xe8, 0x33, 0x98, 0x05, 0x73, 0xeb, 0xcb,
-	0x79, 0x71, 0x95, 0xb8, 0x07, 0x7d, 0x26, 0xd4, 0xc9, 0x79, 0x4a, 0x9d, 0xdc, 0x20, 0x14, 0x30,
-	0x7d, 0x0b, 0xd5, 0xfa, 0x2c, 0xea, 0x79, 0xb1, 0x68, 0xc1, 0x72, 0x53, 0x6b, 0xcd, 0x9a, 0xab,
-	0xc3, 0x14, 0x17, 0xe1, 0x51, 0x8a, 0x17, 0x21, 0xb2, 0x80, 0x11, 0x5a, 0x64, 0xe8, 0xb7, 0x0b,
-	0x1a, 0x0d, 0x62, 0xa3, 0xd6, 0xd4, 0x5a, 0x53, 0x30, 0x27, 0x94, 0x20, 0xee, 0xc6, 0x67, 0x74,
-	0x76, 0x37, 0x26, 0xbf, 0xa5, 0xb8, 0xe4, 0x05, 0x09, 0x2d, 0xd0, 0xf4, 0x5d, 0x24, 0xaa, 0xd4,
-	0x81, 0x1e, 0x9b, 0x85, 0x54, 0x37, 0x8f, 0x53, 0x5c, 0xa7, 0xd6, 0xa1, 0xc9, 0x1d, 0x3b, 0xde,
-	0x53, 0xc6, 0x0b, 0x65, 0x67, 0x86, 0x2a, 0x94, 0x42, 0xb2, 0xc4, 0xcf, 0x8f, 0x56, 0xc7, 0xc2,
-	0x68, 0x1e, 0xa4, 0x3f, 0x44, 0x95, 0xbe, 0x6f, 0x25, 0xbb, 0x61, 0xd4, 0x33, 0xe6, 0x40, 0xa0,
-	0x85, 0x1a, 0xde, 0x97, 0x9e, 0x4d, 0x2b, 0xb1, 0x4c, 0x22, 0x65, 0xaa, 0xf8, 0x4a, 0x6d, 0x19,
-	0x40, 0xa8, 0xf2, 0xe9, 0x9b, 0xa8, 0xe6, 0x87, 0x8e, 0xe5, 0x77, 0x76, 0x7d, 0xab, 0x1b, 0x1b,
-	0xbf, 0xcc, 0x40, 0x51, 0x41, 0x1d, 0x80, 0x6f, 0x71, 0x58, 0x15, 0x23, 0x87, 0x08, 0x2d, 0xf8,
-	0xf5, 0x5b, 0xa8, 0x2e, 0xa5, 0x2f, 0x34, 0xf6, 0xeb, 0x0c, 0x28, 0x04, 0xce, 0x46, 0x3a, 0xa4,
-	0xca, 0x16, 0x8b, 0x1d, 0x23, 0x64, 0x56, 0x64, 0x14, 0xaf, 0x8d, 0xe9, 0xb7, 0xb9, 0x36, 0x28,
-	0x9a, 0x91, 0xd3, 0xdb, 0x98, 0x81, 0xb8, 0xff, 0x1d, 0xa7, 0x18, 0x51, 0xeb, 0x70, 0x5b, 0xa0,
-	0x3c, 0x8b, 0x24, 0xa8, 0x2c, 0xd2, 0xe6, 0x33, 0xb8, 0xc0, 0xa4, 0x19, 0x8f, 0x77, 0x62, 0x10,
-	0x76, 0x8a, 0x92, 0xab, 0x40, 0x6a, 0xe8, 0xc4, 0x20, 0xbc, 0x3f, 0x26, 0x3a, 0xd1, 0x89, 0x63,
-	0x28, 0xa1, 0xe3, 0x2c, 0x39, 0xd2, 0x1f, 0xa1, 0x2a, 0x1c, 0x31, 0xdc, 0x29, 0xb7, 0xd1, 0xb4,
-	0xe8, 0x32, 0x79, 0xa3, 0x5c, 0xc8, 0x4f, 0x15, 0x48, 0xbc, 0x35, 0xcc, 0x7f, 0xc8, 0x23, 0x95,
-	0xd4, 0x51, 0x8a, 0x6b, 0xb9, 0x82, 0x08, 0x95, 0x30, 0xf9, 0x56, 0x43, 0x4b, 0xdb, 0x81, 0xeb,
-	0x45, 0xcc, 0x49, 0x64, 0x3d, 0x59, 0x7c, 0x2f, 0xf0, 0x07, 0xe7, 0x33, 0x02, 0xce, 0xed, 0x90,
-	0xc9, 0xd7, 0x65, 0x34, 0x7d, 0x23, 0xdc, 0x0f, 0x92, 0x58, 0xbf, 0x82, 0xa6, 0x76, 0x3d, 0x9f,
-	0xc5, 0x70, 0x95, 0x4d, 0x99, 0x78, 0x98, 0x62, 0x01, 0xa8, 0x97, 0x04, 0x4b, 0xf5, 0x9e, 0x70,
-	0xea, 0x1f, 0xa0, 0x9a, 0x78, 0xcf, 0x30, 0xf2, 0x58, 0x0c, 0x53, 0x65, 0xca, 0xfc, 0x0f, 0xff,
-	0x27, 0x05, 0x58, 0xfd, 0x93, 0x02, 0xa6, 0x12, 0x15, 0x89, 0xfa, 0x75, 0x54, 0x91, 0x33, 0x33,
-	0x86, 0x7b, 0x72, 0xca, 0xbc, 0x04, 0xf3, 0x5a, 0x62, 0xf9, 0xbc, 0x96, 0x80, 0xca, 0xa2, 0x28,
-	0xfa, 0xff, 0x73, 0xe1, 0x96, 0x21, 0xc3, 0xc5, 0x3f, 0x12, 0x6e, 0x16, 0xaf, 0xf4, 0xdb, 0x46,
-	0x53, 0xf6, 0x20, 0x61, 0xd9, 0xa5, 0x6b, 0xf0, 0x3a, 0x00, 0x90, 0x1f, 0x36, 0xb7, 0x08, 0x15,
-	0xe8, 0xd8, 0x0d, 0x33, 0xfd, 0x96, 0x37, 0xcc, 0x0e, 0xaa, 0x8a, 0x1d, 0xa9, 0xe3, 0xb9, 0x70,
-	0xb9, 0xd4, 0xcd, 0x8d, 0xe3, 0x14, 0x57, 0xc4, 0xde, 0x03, 0x37, 0x6e, 0x45, 0x10, 0xb6, 0x5d,
-	0x95, 0x28, 0x03, 0x78, 0xb7, 0x28, 0x26, 0x55, 0x3c, 0x2e, 0xb1, 0xe2, 0x20, 0xd1, 0xdf, 0x65,
-	0x8e, 0xc8, 0x06, 0xf9, 0x4c, 0x43, 0x55, 0x21, 0x8f, 0x1d, 0x96, 0xe8, 0xd7, 0xd1, 0xb4, 0x03,
-	0x86, 0xec, 0x10, 0xc4, 0x77, 0x2e, 0xe1, 0xce, 0x1b, 0x43, 0x30, 0x54, 0xad, 0xc0, 0x24, 0x54,
-	0xc2, 0x7c, 0xa8, 0x38, 0x11, 0xb3, 0xb2, 0x5d, 0xb4, 0x24, 0x86, 0x8a, 0x84, 0xd4, 0xd9, 0x48,
-	0x9b, 0xd0, 0xcc, 0x43, 0x3e, 0x9f, 0x44, 0x4b, 0x85, 0xed, 0x6e, 0x93, 0xf5, 0x23, 0x26, 0x16,
-	0xb0, 0xf3, 0xdd, 0x95, 0xd7, 0xd1, 0xb4, 0xa8, 0x23, 0xfc, 0xbd, 0xba, 0xb9, 0xc2, 0x5f, 0x49,
-	0x20, 0x67, 0x36, 0x5e, 0x89, 0xf3, 0x77, 0xca, 0x06, 0x5e, 0x29, 0x1f, 0x94, 0xaf, 0x1b, 0x71,
-	0xf9, 0x50, 0xdb, 0x18, 0xd7, 0xe9, 0x9b, 0x0e, 0x58, 0x72, 0x88, 0x96, 0x0a, 0xbb, 0x70, 0xa1,
-	0x14, 0x1f, 0x9e, 0xd9, 0x8a, 0xff, 0x7a, 0x6a, 0x2b, 0xce, 0xc9, 0xe6, 0x3f, 0xb3, 0xcb, 0xe9,
-	0xb5, 0x0b, 0xf1, 0x99, 0x0d, 0xf8, 0x87, 0x49, 0x34, 0x77, 0xcf, 0x8e, 0x59, 0x74, 0xc0, 0xdc,
-	0xad, 0xd0, 0x77, 0x59, 0xa4, 0xdf, 0x45, 0x65, 0xfe, 0xbd, 0x23, 0x4b, 0xbf, 0xd2, 0x16, 0x1f,
-	0x43, 0xed, 0xec, 0x63, 0xa8, 0xfd, 0x20, 0xfb, 0x18, 0x32, 0x1b, 0xf2, 0xf7, 0x80, 0x9f, 0x2f,
-	0x15, 0x5e, 0x8f, 0x91, 0x67, 0x3f, 0x63, 0x8d, 0x02, 0xce, 0x9b, 0xcf, 0xb7, 0x6c, 0xe6, 0x43,
-	0xf9, 0xab, 0xa2, 0xf9, 0x00, 0x50, 0x82, 0x02, 0x8b, 0x50, 0x81, 0xea, 0x1f, 0xa3, 0xc5, 0x88,
-	0x39, 0xcc, 0x3b, 0x60, 0x9d, 0x7c, 0x29, 0x12, 0xa7, 0xd0, 0x1e, 0xa6, 0x78, 0x41, 0x3a, 0xdf,
-	0x2f, 0xec, 0x46, 0xcb, 0x90, 0xe6, 0xb4, 0x83, 0xd0, 0x33, 0x5c, 0xfd, 0x11, 0x5a, 0x88, 0x58,
-	0x2f, 0x4c, 0x8a, 0xb9, 0xc5, 0x49, 0xfd, 0x77, 0x98, 0xe2, 0x79, 0xe1, 0x2b, 0xa6, 0x5e, 0x92,
-	0xa9, 0xc7, 0x70, 0x42, 0x4f, 0x33, 0xc9, 0xf7, 0x5a, 0x5e, 0x48, 0xd1, 0xc0, 0xe7, 0x5e, 0xc8,
-	0xec, 0xbb, 0x64, 0xf2, 0x0d, 0xbe, 0x4b, 0x36, 0xd0, 0x8c, 0xe5, 0xba, 0x11, 0x8b, 0xc5, 0xc8,
-	0xad, 0x0a, 0x21, 0x4a, 0x48, 0xc9, 0x42, 0xda, 0x84, 0x66, 0x1e, 0xf3, 0xe6, 0xcb, 0x57, 0x8d,
-	0x89, 0xa3, 0x57, 0x8d, 0x89, 0x97, 0xc7, 0x0d, 0xed, 0xe8, 0xb8, 0xa1, 0x3d, 0x3b, 0x69, 0x4c,
-	0xbc, 0x38, 0x69, 0x68, 0x47, 0x27, 0x8d, 0x89, 0x1f, 0x4f, 0x1a, 0x13, 0x1f, 0x5d, 0x7a, 0x83,
-	0x8f, 0x01, 0xd7, 0xb6, 0xa7, 0xe1, 0x35, 0x2f, 0xff, 0x1e, 0x00, 0x00, 0xff, 0xff, 0x95, 0x1d,
-	0x77, 0x00, 0x8b, 0x0f, 0x00, 0x00,
+	0x16, 0x37, 0x2d, 0xd9, 0x92, 0x46, 0xf2, 0x17, 0xb3, 0x36, 0xb4, 0xde, 0x5d, 0x51, 0x3b, 0x71,
+	0x00, 0xed, 0x07, 0x64, 0xc0, 0x41, 0x8c, 0x45, 0x80, 0x6d, 0x10, 0xc6, 0x75, 0xe2, 0x20, 0x75,
+	0xd2, 0x71, 0x90, 0x14, 0xed, 0x41, 0xe0, 0xc7, 0x58, 0x26, 0x42, 0x91, 0x2a, 0x49, 0xdb, 0x51,
+	0x6e, 0xbd, 0x14, 0xe8, 0x2d, 0x08, 0x7a, 0x28, 0x8a, 0xa2, 0x08, 0x50, 0xa0, 0x7f, 0x42, 0xff,
+	0x82, 0xa2, 0xc8, 0xd1, 0xc7, 0xa2, 0x07, 0x16, 0xb1, 0x2f, 0xad, 0x8e, 0x3a, 0xf6, 0x54, 0xcc,
+	0x9b, 0xe1, 0x70, 0x64, 0x23, 0x45, 0x92, 0xfa, 0xc6, 0xf7, 0x7b, 0xbf, 0x79, 0x12, 0xdf, 0xfc,
+	0xde, 0x07, 0xd1, 0x5f, 0x7c, 0xcf, 0x5e, 0x75, 0xed, 0xd5, 0x38, 0x89, 0xf6, 0x9d, 0x24, 0x6e,
+	0xf7, 0xa3, 0x30, 0x09, 0xf5, 0x49, 0xd7, 0x5e, 0xbe, 0x18, 0xd1, 0x7e, 0x18, 0xaf, 0x02, 0x60,
+	0xef, 0xef, 0xae, 0x76, 0xc3, 0x6e, 0x08, 0x06, 0x3c, 0x71, 0xe2, 0xb2, 0xd1, 0x0d, 0xc3, 0xae,
+	0x4f, 0x73, 0x56, 0xe2, 0xf5, 0x68, 0x9c, 0x58, 0xbd, 0xbe, 0x20, 0x2c, 0xb1, 0xf8, 0xf0, 0xe8,
+	0x84, 0xfe, 0xaa, 0x4d, 0x33, 0xbc, 0x42, 0x1f, 0x27, 0xfc, 0x11, 0x7f, 0x3d, 0x89, 0xaa, 0x9b,
+	0x9e, 0x4f, 0x1f, 0xd0, 0x28, 0xf6, 0xc2, 0x40, 0xbf, 0x83, 0x4a, 0x07, 0xfc, 0xb1, 0xae, 0x35,
+	0xb5, 0x56, 0x75, 0x6d, 0xbe, 0x9d, 0x05, 0x68, 0x3f, 0xa0, 0x4e, 0x12, 0x46, 0x66, 0xf3, 0x45,
+	0x6a, 0x4c, 0x0c, 0x53, 0x23, 0x23, 0x8e, 0x52, 0x63, 0xe6, 0x71, 0xcf, 0xbf, 0x8a, 0x85, 0x8d,
+	0x49, 0xe6, 0xd1, 0xd7, 0x51, 0xc9, 0xa5, 0x3e, 0x4d, 0xa8, 0x5b, 0x9f, 0x6c, 0x6a, 0xad, 0xb2,
+	0xf9, 0x77, 0x76, 0x4e, 0x40, 0xf2, 0x9c, 0xb0, 0x31, 0xc9, 0x3c, 0xfa, 0x15, 0x76, 0xee, 0xc0,
+	0x73, 0x68, 0x5c, 0x2f, 0x34, 0x0b, 0xad, 0x9a, 0xf9, 0x37, 0x7e, 0x0e, 0xa0, 0x51, 0x6a, 0xd4,
+	0xc4, 0x39, 0x66, 0xc3, 0x31, 0x70, 0xe8, 0x04, 0xcd, 0x79, 0xc1, 0x81, 0xe5, 0x7b, 0x6e, 0x27,
+	0x3b, 0x5e, 0x84, 0xe3, 0xff, 0x1a, 0xa6, 0xc6, 0xac, 0x70, 0x6d, 0xc8, 0x28, 0x17, 0x20, 0xca,
+	0x18, 0x8c, 0xc9, 0x29, 0x1a, 0xfe, 0x44, 0x43, 0x55, 0x91, 0x9c, 0x3b, 0x5e, 0x9c, 0xe8, 0x3e,
+	0x2a, 0x8b, 0xb7, 0x8b, 0xeb, 0x5a, 0xb3, 0xd0, 0xaa, 0xae, 0xcd, 0xb5, 0x5d, 0xbb, 0xad, 0xe4,
+	0xd0, 0xbc, 0xc6, 0x12, 0x74, 0x9c, 0x1a, 0x55, 0x62, 0x1d, 0x0a, 0x2c, 0x1e, 0xa6, 0x86, 0x3c,
+	0x77, 0x26, 0x61, 0xcf, 0x8e, 0x56, 0x54, 0x2e, 0x91, 0xcc, 0xab, 0xc5, 0x2f, 0x9e, 0x1b, 0x13,
+	0xf8, 0x9b, 0x1a, 0x5a, 0x60, 0x3f, 0xb0, 0x15, 0xec, 0x86, 0xf7, 0xa3, 0xfd, 0xc0, 0xb1, 0x58,
+	0x92, 0xfe, 0x8d, 0x8a, 0x81, 0xd5, 0xa3, 0x70, 0x4f, 0x15, 0x73, 0x69, 0x98, 0x1a, 0x60, 0x8f,
+	0x52, 0x03, 0x41, 0x74, 0x66, 0x60, 0x02, 0x18, 0xe3, 0xc6, 0xde, 0x13, 0x5a, 0x2f, 0x34, 0xb5,
+	0x56, 0x81, 0x73, 0x99, 0x2d, 0xb9, 0xcc, 0xc0, 0x04, 0x30, 0xfd, 0x1a, 0x42, 0xbd, 0xd0, 0xf5,
+	0x76, 0x3d, 0xea, 0x76, 0xe2, 0xfa, 0x14, 0x9c, 0x68, 0x0e, 0x53, 0xa3, 0x92, 0xa1, 0x3b, 0xa3,
+	0xd4, 0x98, 0x83, 0x63, 0x12, 0xc1, 0x24, 0xf7, 0xea, 0xdf, 0x69, 0xa8, 0x2a, 0x23, 0xd8, 0x83,
+	0x7a, 0xad, 0xa9, 0xb5, 0x8a, 0xe6, 0xe7, 0x1a, 0x4b, 0xcb, 0x4f, 0xa9, 0x71, 0xb9, 0xeb, 0x25,
+	0x7b, 0xfb, 0x76, 0xdb, 0x09, 0x7b, 0xab, 0xf1, 0x20, 0x70, 0x92, 0x3d, 0x2f, 0xe8, 0x2a, 0x4f,
+	0xaa, 0x68, 0xdb, 0x3b, 0x7b, 0x61, 0x94, 0x6c, 0x6d, 0x0c, 0x53, 0x43, 0xfe, 0x29, 0x73, 0x30,
+	0x4a, 0x8d, 0xf9, 0xb1, 0xdf, 0x37, 0x07, 0xf8, 0xcb, 0xa3, 0x95, 0xb7, 0x09, 0x4c, 0x94, 0xb0,
+	0xaa, 0xf8, 0x2b, 0x7f, 0x5e, 0xfc, 0x57, 0x51, 0x39, 0xa6, 0x1f, 0xef, 0xd3, 0xc0, 0xa1, 0x75,
+	0x04, 0x59, 0x6c, 0x30, 0x15, 0x64, 0xd8, 0x28, 0x35, 0x66, 0x79, 0xee, 0x05, 0x80, 0x89, 0xf4,
+	0xe9, 0x77, 0xd1, 0x6c, 0x3c, 0xe8, 0xf9, 0x5e, 0xf0, 0xa8, 0x93, 0x58, 0x51, 0x97, 0x26, 0xf5,
+	0x05, 0xb8, 0xe5, 0xd6, 0x30, 0x35, 0x66, 0x84, 0xe7, 0x3e, 0x38, 0xa4, 0x8e, 0xc7, 0x50, 0x4c,
+	0xc6, 0x59, 0xfa, 0x0d, 0x54, 0xb5, 0xfd, 0xd0, 0x79, 0x14, 0x77, 0xf6, 0xac, 0x78, 0xaf, 0xae,
+	0x37, 0xb5, 0x56, 0xcd, 0xc4, 0x2c, 0xad, 0x1c, 0xbe, 0x65, 0xc5, 0x7b, 0x32, 0xad, 0x39, 0x84,
+	0x89, 0xe2, 0xd7, 0xdf, 0x41, 0x15, 0x1a, 0x38, 0xd1, 0xa0, 0xcf, 0x0a, 0xfa, 0x02, 0x84, 0x00,
+	0x61, 0x48, 0x50, 0x0a, 0x43, 0x22, 0x98, 0xe4, 0x5e, 0xdd, 0x44, 0xc5, 0x64, 0xd0, 0xa7, 0xd0,
+	0x0b, 0x66, 0xd7, 0x96, 0xf2, 0xe4, 0x4a, 0x71, 0x0f, 0xfa, 0x94, 0xab, 0x93, 0xf1, 0xa4, 0x3a,
+	0x99, 0x81, 0x09, 0x60, 0xfa, 0x26, 0xaa, 0xf6, 0x69, 0xd4, 0xf3, 0x62, 0x5e, 0x82, 0xc5, 0xa6,
+	0xd6, 0x9a, 0x31, 0x57, 0x86, 0xa9, 0xa1, 0xc2, 0xa3, 0xd4, 0x58, 0x80, 0x93, 0x0a, 0x86, 0x89,
+	0xca, 0xd0, 0x6f, 0x2b, 0x1a, 0x0d, 0xe2, 0x7a, 0xb5, 0xa9, 0xb5, 0xa6, 0xa0, 0x4f, 0x48, 0x41,
+	0x6c, 0xc7, 0x67, 0x74, 0xb6, 0x1d, 0xe3, 0xdf, 0x52, 0xa3, 0xe0, 0x05, 0x09, 0x51, 0x68, 0xfa,
+	0x2e, 0xe2, 0x59, 0xea, 0x40, 0x8d, 0xcd, 0x40, 0xa8, 0x9b, 0xc7, 0xa9, 0x51, 0x23, 0xd6, 0xa1,
+	0xc9, 0x1c, 0x3b, 0xde, 0x13, 0xca, 0x12, 0x65, 0x67, 0x86, 0x4c, 0x94, 0x44, 0xb2, 0xc0, 0xcf,
+	0x8e, 0x56, 0xc6, 0x8e, 0x91, 0xfc, 0x90, 0xfe, 0x00, 0x95, 0xfb, 0xbe, 0x95, 0xec, 0x86, 0x51,
+	0xaf, 0x3e, 0x0b, 0x02, 0x55, 0x72, 0x78, 0x4f, 0x78, 0x36, 0xac, 0xc4, 0x32, 0xb1, 0x90, 0xa9,
+	0xe4, 0x4b, 0xb5, 0x65, 0x00, 0x26, 0xd2, 0xa7, 0x6f, 0xa0, 0xaa, 0x1f, 0x3a, 0x96, 0xdf, 0xd9,
+	0xf5, 0xad, 0x6e, 0x5c, 0xff, 0xa5, 0x04, 0x49, 0x05, 0x75, 0x00, 0xbe, 0xc9, 0x60, 0x99, 0x8c,
+	0x1c, 0xc2, 0x44, 0xf1, 0xeb, 0xb7, 0x50, 0x4d, 0x48, 0x9f, 0x6b, 0xec, 0xd7, 0x12, 0x28, 0x04,
+	0xee, 0x46, 0x38, 0x84, 0xca, 0x16, 0xd4, 0x8a, 0xe1, 0x32, 0x53, 0x19, 0xfa, 0xfb, 0xac, 0x8f,
+	0x87, 0x2e, 0xed, 0x38, 0x7b, 0x56, 0xd0, 0xa5, 0xec, 0x7e, 0x86, 0x25, 0xa8, 0x20, 0xd0, 0x3f,
+	0xf8, 0x6e, 0x80, 0x6b, 0x5b, 0xed, 0xe3, 0x0a, 0x8a, 0xc9, 0x38, 0x4b, 0x9d, 0x44, 0xd3, 0x6f,
+	0x32, 0x89, 0x08, 0x2a, 0x89, 0x81, 0x50, 0x2f, 0xc1, 0xb9, 0xff, 0x1d, 0xa7, 0x06, 0x22, 0xd6,
+	0xe1, 0x16, 0x47, 0x59, 0x14, 0x41, 0x90, 0x51, 0x84, 0xcd, 0xda, 0xba, 0xc2, 0x24, 0x19, 0x8f,
+	0x15, 0x77, 0x10, 0x76, 0x54, 0x15, 0x97, 0x21, 0x34, 0xbc, 0x5c, 0x10, 0xde, 0x1b, 0xd3, 0x31,
+	0x7f, 0xb9, 0x31, 0x14, 0x93, 0x71, 0x96, 0x98, 0x12, 0x0f, 0x51, 0x05, 0x54, 0x03, 0x63, 0xea,
+	0x36, 0x9a, 0xe6, 0x85, 0x2b, 0x86, 0xd4, 0x85, 0x5c, 0x28, 0x40, 0x62, 0xd5, 0x66, 0xfe, 0x43,
+	0xa8, 0x44, 0x50, 0x47, 0xa9, 0x51, 0xcd, 0x45, 0x89, 0x89, 0x80, 0xf1, 0xb7, 0x1a, 0x5a, 0xdc,
+	0x0a, 0x5c, 0x2f, 0xa2, 0x4e, 0x22, 0xae, 0x88, 0xc6, 0x77, 0x03, 0x7f, 0x70, 0x3e, 0x5d, 0xe5,
+	0xdc, 0x74, 0x83, 0xbf, 0x2a, 0xa2, 0xe9, 0x1b, 0xe1, 0x7e, 0x90, 0xc4, 0xfa, 0x15, 0x34, 0xb5,
+	0xeb, 0xf9, 0x34, 0x86, 0xe9, 0x38, 0x65, 0x1a, 0xc3, 0xd4, 0xe0, 0x80, 0x7c, 0x49, 0xb0, 0x64,
+	0x39, 0x73, 0xa7, 0xfe, 0x1e, 0xaa, 0xf2, 0xf7, 0x0c, 0x23, 0x8f, 0xc6, 0xd0, 0xa8, 0xa6, 0xcc,
+	0xff, 0xb0, 0x7f, 0xa2, 0xc0, 0xf2, 0x9f, 0x28, 0x98, 0x0c, 0xa4, 0x12, 0xf5, 0xeb, 0xa8, 0x2c,
+	0xda, 0x70, 0x0c, 0xa3, 0x77, 0xca, 0xbc, 0x04, 0x23, 0x40, 0x60, 0xf9, 0x08, 0x10, 0x80, 0x8c,
+	0x22, 0x29, 0xfa, 0xff, 0x73, 0xe1, 0x16, 0x21, 0xc2, 0xc5, 0x3f, 0x12, 0x6e, 0x76, 0x5e, 0xea,
+	0xb7, 0x8d, 0xa6, 0xec, 0x41, 0x42, 0xb3, 0x39, 0x5e, 0x67, 0x79, 0x00, 0x20, 0xbf, 0x6c, 0x66,
+	0x61, 0xc2, 0xd1, 0xb1, 0xa1, 0x35, 0xfd, 0x86, 0x43, 0x6b, 0x07, 0x55, 0xf8, 0xda, 0xd5, 0xf1,
+	0x5c, 0x98, 0x57, 0x35, 0x73, 0xfd, 0x38, 0x35, 0xca, 0x7c, 0x95, 0x82, 0x21, 0x5e, 0xe6, 0x84,
+	0x2d, 0x57, 0x06, 0xca, 0x00, 0x56, 0x2d, 0x92, 0x49, 0x24, 0x8f, 0x49, 0x4c, 0xed, 0x4d, 0xfa,
+	0xdb, 0xb4, 0x26, 0x51, 0x20, 0x9f, 0x6a, 0xa8, 0xc2, 0xe5, 0xb1, 0x43, 0x13, 0xfd, 0x3a, 0x9a,
+	0x76, 0xc0, 0x10, 0x15, 0x82, 0xd8, 0x1a, 0xc7, 0xdd, 0x79, 0x61, 0x70, 0x86, 0xcc, 0x15, 0x98,
+	0x98, 0x08, 0x98, 0x35, 0x15, 0x27, 0xa2, 0x56, 0xb6, 0xde, 0x16, 0x78, 0x53, 0x11, 0x90, 0xbc,
+	0x1b, 0x61, 0x63, 0x92, 0x79, 0xf0, 0x67, 0x93, 0x68, 0x51, 0x59, 0x18, 0x37, 0x68, 0x3f, 0xa2,
+	0x7c, 0xa7, 0x3b, 0xdf, 0xf5, 0x7b, 0x0d, 0x4d, 0xf3, 0x3c, 0xc2, 0xdf, 0xab, 0x99, 0xcb, 0xec,
+	0x95, 0x38, 0x72, 0x66, 0x89, 0x16, 0x38, 0x7b, 0xa7, 0xac, 0xe1, 0x15, 0xf2, 0x46, 0xf9, 0xaa,
+	0x16, 0x97, 0x37, 0xb5, 0xf5, 0x71, 0x9d, 0xbe, 0x6e, 0x83, 0xc5, 0x87, 0x68, 0x51, 0x59, 0xaf,
+	0x95, 0x54, 0x7c, 0x70, 0x66, 0xd1, 0xfe, 0xeb, 0xa9, 0x45, 0x3b, 0x27, 0x9b, 0xff, 0xcc, 0xe6,
+	0xdd, 0x2b, 0x77, 0xec, 0x33, 0x4b, 0xf5, 0x0f, 0x93, 0x68, 0xf6, 0xae, 0x1d, 0xd3, 0xe8, 0x80,
+	0xba, 0x9b, 0xa1, 0xef, 0xd2, 0x48, 0xdf, 0x46, 0x45, 0xf6, 0x09, 0x25, 0x52, 0xbf, 0xdc, 0xe6,
+	0xdf, 0x57, 0xed, 0xec, 0xfb, 0xaa, 0x7d, 0x3f, 0xfb, 0xbe, 0x32, 0x1b, 0xe2, 0xf7, 0x80, 0x9f,
+	0xef, 0x29, 0x5e, 0x8f, 0xe2, 0xa7, 0x3f, 0x1b, 0x1a, 0x01, 0x9c, 0x15, 0x9f, 0x6f, 0xd9, 0xd4,
+	0x87, 0xf4, 0x57, 0x78, 0xf1, 0x01, 0x20, 0x05, 0x05, 0x16, 0x26, 0x1c, 0xd5, 0x3f, 0x42, 0x0b,
+	0x11, 0x75, 0xa8, 0x77, 0x40, 0x3b, 0xf9, 0x9e, 0xc5, 0x6f, 0xa1, 0x3d, 0x4c, 0x8d, 0x79, 0xe1,
+	0x7c, 0x57, 0x59, 0xb7, 0x96, 0x20, 0xcc, 0x69, 0x07, 0x26, 0x67, 0xb8, 0xfa, 0x43, 0x34, 0x1f,
+	0xd1, 0x5e, 0x98, 0xa8, 0xb1, 0xf9, 0x4d, 0xfd, 0x77, 0x98, 0x1a, 0x73, 0xdc, 0xa7, 0x86, 0x5e,
+	0x14, 0xa1, 0xc7, 0x70, 0x4c, 0x4e, 0x33, 0xf1, 0xf7, 0x5a, 0x9e, 0x48, 0x5e, 0xc0, 0xe7, 0x9e,
+	0xc8, 0xec, 0x53, 0x67, 0xf2, 0x35, 0x3e, 0x75, 0xd6, 0x51, 0xc9, 0x72, 0xdd, 0x88, 0xc6, 0xbc,
+	0xe5, 0x56, 0xb8, 0x10, 0x05, 0x24, 0x65, 0x21, 0x6c, 0x4c, 0x32, 0x8f, 0x79, 0xf3, 0xc5, 0xcb,
+	0xc6, 0xc4, 0xd1, 0xcb, 0xc6, 0xc4, 0x8b, 0xe3, 0x86, 0x76, 0x74, 0xdc, 0xd0, 0x9e, 0x9e, 0x34,
+	0x26, 0x9e, 0x9f, 0x34, 0xb4, 0xa3, 0x93, 0xc6, 0xc4, 0x8f, 0x27, 0x8d, 0x89, 0x0f, 0x2f, 0xbd,
+	0xc6, 0xf7, 0x85, 0x6b, 0xdb, 0xd3, 0xf0, 0x9a, 0x97, 0x7f, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x52,
+	0x5f, 0x14, 0xfe, 0xde, 0x0f, 0x00, 0x00,
 }
 
 func (m *FileVersion) Marshal() (dAtA []byte, err error) {
@@ -712,6 +715,13 @@ func (m *FileInfoTruncated) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	if m.InodeChangeNs != 0 {
+		i = encodeVarintStructs(dAtA, i, uint64(m.InodeChangeNs))
+		i--
+		dAtA[i] = 0x3e
+		i--
+		dAtA[i] = 0xd0
+	}
 	if len(m.VersionHash) > 0 {
 		i -= len(m.VersionHash)
 		copy(dAtA[i:], m.VersionHash)
@@ -1362,6 +1372,9 @@ func (m *FileInfoTruncated) ProtoSize() (n int) {
 	if l > 0 {
 		n += 2 + l + sovStructs(uint64(l))
 	}
+	if m.InodeChangeNs != 0 {
+		n += 2 + sovStructs(uint64(m.InodeChangeNs))
+	}
 	return n
 }
 
@@ -2274,6 +2287,25 @@ func (m *FileInfoTruncated) Unmarshal(dAtA []byte) error {
 				m.VersionHash = []byte{}
 			}
 			iNdEx = postIndex
+		case 1002:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field InodeChangeNs", wireType)
+			}
+			m.InodeChangeNs = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowStructs
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.InodeChangeNs |= int64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
 		default:
 			iNdEx = preIndex
 			skippy, err := skipStructs(dAtA[iNdEx:])
diff --git a/lib/fs/basicfs_fileinfo_bsdish.go b/lib/fs/basicfs_fileinfo_bsdish.go
new file mode 100644
index 00000000000..b8e60f329be
--- /dev/null
+++ b/lib/fs/basicfs_fileinfo_bsdish.go
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+//go:build darwin || freebsd || netbsd
+// +build darwin freebsd netbsd
+
+package fs
+
+import (
+	"syscall"
+	"time"
+)
+
+func (fi basicFileInfo) InodeChangeTime() time.Time {
+	if sys, ok := fi.FileInfo.Sys().(*syscall.Stat_t); ok {
+		return time.Unix(0, sys.Ctimespec.Nano())
+	}
+	return time.Time{}
+}
diff --git a/lib/fs/basicfs_fileinfo_linuxish.go b/lib/fs/basicfs_fileinfo_linuxish.go
new file mode 100644
index 00000000000..f7de9e49ef7
--- /dev/null
+++ b/lib/fs/basicfs_fileinfo_linuxish.go
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+//go:build aix || dragonfly || linux || openbsd || solaris || illumos
+// +build aix dragonfly linux openbsd solaris illumos
+
+package fs
+
+import (
+	"syscall"
+	"time"
+)
+
+func (fi basicFileInfo) InodeChangeTime() time.Time {
+	if sys, ok := fi.FileInfo.Sys().(*syscall.Stat_t); ok {
+		return time.Unix(0, sys.Ctim.Nano())
+	}
+	return time.Time{}
+}
diff --git a/lib/fs/basicfs_fileinfo_windows.go b/lib/fs/basicfs_fileinfo_windows.go
index b7ef4cb569e..22be6dbb719 100644
--- a/lib/fs/basicfs_fileinfo_windows.go
+++ b/lib/fs/basicfs_fileinfo_windows.go
@@ -10,6 +10,7 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"time"
 )
 
 var execExts map[string]bool
@@ -57,6 +58,10 @@ func (e basicFileInfo) Group() int {
 	return -1
 }
 
+func (basicFileInfo) InodeChangeTime() time.Time {
+	return time.Time{}
+}
+
 // osFileInfo converts e to os.FileInfo that is suitable
 // to be passed to os.SameFile.
 func (e *basicFileInfo) osFileInfo() os.FileInfo {
diff --git a/lib/fs/basicfs_platformdata_unix.go b/lib/fs/basicfs_platformdata_unix.go
index 644c2c44c64..91c8f47afdd 100644
--- a/lib/fs/basicfs_platformdata_unix.go
+++ b/lib/fs/basicfs_platformdata_unix.go
@@ -13,6 +13,6 @@ import (
 	"github.com/syncthing/syncthing/lib/protocol"
 )
 
-func (f *BasicFilesystem) PlatformData(name string) (protocol.PlatformData, error) {
-	return unixPlatformData(f, name, f.userCache, f.groupCache)
+func (f *BasicFilesystem) PlatformData(name string, scanOwnership, scanXattrs bool, xattrFilter XattrFilter) (protocol.PlatformData, error) {
+	return unixPlatformData(f, name, f.userCache, f.groupCache, scanOwnership, scanXattrs, xattrFilter)
 }
diff --git a/lib/fs/basicfs_platformdata_windows.go b/lib/fs/basicfs_platformdata_windows.go
index 0bf23b808d5..ea8f44a94d6 100644
--- a/lib/fs/basicfs_platformdata_windows.go
+++ b/lib/fs/basicfs_platformdata_windows.go
@@ -13,7 +13,12 @@ import (
 	"golang.org/x/sys/windows"
 )
 
-func (f *BasicFilesystem) PlatformData(name string) (protocol.PlatformData, error) {
+func (f *BasicFilesystem) PlatformData(name string, scanOwnership, _ bool, _ XattrFilter) (protocol.PlatformData, error) {
+	if !scanOwnership {
+		// That's the only thing we do, currently
+		return protocol.PlatformData{}, nil
+	}
+
 	rootedName, err := f.rooted(name)
 	if err != nil {
 		return protocol.PlatformData{}, fmt.Errorf("rooted for %s: %w", name, err)
diff --git a/lib/fs/basicfs_xattr_bsdish.go b/lib/fs/basicfs_xattr_bsdish.go
new file mode 100644
index 00000000000..8d4cf68b734
--- /dev/null
+++ b/lib/fs/basicfs_xattr_bsdish.go
@@ -0,0 +1,101 @@
+// Copyright (C) 2022 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+//go:build freebsd || netbsd
+// +build freebsd netbsd
+
+package fs
+
+import (
+	"errors"
+	"fmt"
+	"sort"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+)
+
+var (
+	namespaces        = [...]int{unix.EXTATTR_NAMESPACE_USER, unix.EXTATTR_NAMESPACE_SYSTEM}
+	namespacePrefixes = [...]string{unix.EXTATTR_NAMESPACE_USER: "user.", unix.EXTATTR_NAMESPACE_SYSTEM: "system."}
+)
+
+func listXattr(path string) ([]string, error) {
+	var attrs []string
+
+	// List the two namespaces explicitly and prefix any results with the
+	// namespace name.
+	for _, nsid := range namespaces {
+		buf := make([]byte, 1024)
+		size, err := unixLlistxattr(path, buf, nsid)
+		if errors.Is(err, unix.ERANGE) || size == len(buf) {
+			// Buffer is too small. Try again with a zero sized buffer to
+			// get the size, then allocate a buffer of the correct size. We
+			// inlude the size == len(buf) because apparently macOS doesn't
+			// return ERANGE as it should -- no harm done, just an extra
+			// read if we happened to need precisely 1024 bytes on the first
+			// pass.
+			size, err = unixLlistxattr(path, nil, nsid)
+			if err != nil {
+				return nil, fmt.Errorf("Listxattr %s: %w", path, err)
+			}
+			buf = make([]byte, size)
+			size, err = unixLlistxattr(path, buf, nsid)
+		}
+		if err != nil {
+			return nil, fmt.Errorf("Listxattr %s: %w", path, err)
+		}
+
+		buf = buf[:size]
+
+		// "Each list entry consists of a single byte containing the length
+		// of the attribute name, followed by the attribute name.  The
+		// attribute name is not terminated by ASCII 0 (nul)."
+		i := 0
+		for i < len(buf) {
+			l := int(buf[i])
+			i++
+			if i+l > len(buf) {
+				// uh-oh
+				return nil, fmt.Errorf("get xattr %s: attribute length %d at offset %d exceeds buffer length %d", path, l, i, len(buf))
+			}
+			if l > 0 {
+				attrs = append(attrs, namespacePrefixes[nsid]+string(buf[i:i+l]))
+				i += l
+			}
+		}
+	}
+
+	sort.Strings(attrs)
+	return attrs, nil
+}
+
+// This is unix.Llistxattr except taking a namespace parameter to dodge
+// https://github.com/golang/go/issues/54357 ("Listxattr on FreeBSD loses
+// namespace info")
+func unixLlistxattr(link string, dest []byte, nsid int) (sz int, err error) {
+	d := initxattrdest(dest, 0)
+	destsiz := len(dest)
+
+	s, e := unix.ExtattrListLink(link, nsid, uintptr(d), destsiz)
+	if e != nil && e == unix.EPERM && nsid != unix.EXTATTR_NAMESPACE_USER {
+		return 0, nil
+	} else if e != nil {
+		return s, e
+	}
+
+	return s, nil
+}
+
+var _zero uintptr
+
+func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) {
+	if len(dest) > idx {
+		return unsafe.Pointer(&dest[idx])
+	} else {
+		return unsafe.Pointer(_zero)
+	}
+}
diff --git a/lib/fs/basicfs_xattr_linuxish.go b/lib/fs/basicfs_xattr_linuxish.go
new file mode 100644
index 00000000000..4857a4098e0
--- /dev/null
+++ b/lib/fs/basicfs_xattr_linuxish.go
@@ -0,0 +1,43 @@
+// Copyright (C) 2022 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+//go:build linux || darwin
+// +build linux darwin
+
+package fs
+
+import (
+	"errors"
+	"fmt"
+	"sort"
+	"strings"
+
+	"golang.org/x/sys/unix"
+)
+
+func listXattr(path string) ([]string, error) {
+	buf := make([]byte, 1024)
+	size, err := unix.Llistxattr(path, buf)
+	if errors.Is(err, unix.ERANGE) {
+		// Buffer is too small. Try again with a zero sized buffer to get
+		// the size, then allocate a buffer of the correct size.
+		size, err = unix.Llistxattr(path, nil)
+		if err != nil {
+			return nil, fmt.Errorf("Listxattr %s: %w", path, err)
+		}
+		buf = make([]byte, size)
+		size, err = unix.Llistxattr(path, buf)
+	}
+	if err != nil {
+		return nil, fmt.Errorf("Listxattr %s: %w", path, err)
+	}
+
+	buf = buf[:size]
+	attrs := compact(strings.Split(string(buf), "\x00"))
+
+	sort.Strings(attrs)
+	return attrs, nil
+}
diff --git a/lib/fs/basicfs_xattr_unix.go b/lib/fs/basicfs_xattr_unix.go
new file mode 100644
index 00000000000..eb26e7725ee
--- /dev/null
+++ b/lib/fs/basicfs_xattr_unix.go
@@ -0,0 +1,143 @@
+// Copyright (C) 2022 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+//go:build !windows && !dragonfly && !illumos && !solaris && !openbsd
+// +build !windows,!dragonfly,!illumos,!solaris,!openbsd
+
+package fs
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"syscall"
+
+	"github.com/syncthing/syncthing/lib/protocol"
+	"golang.org/x/sys/unix"
+)
+
+func (f *BasicFilesystem) GetXattr(path string, xattrFilter XattrFilter) ([]protocol.Xattr, error) {
+	path, err := f.rooted(path)
+	if err != nil {
+		return nil, fmt.Errorf("get xattr %s: %w", path, err)
+	}
+
+	attrs, err := listXattr(path)
+	if err != nil {
+		return nil, fmt.Errorf("get xattr %s: %w", path, err)
+	}
+
+	res := make([]protocol.Xattr, 0, len(attrs))
+	var val, buf []byte
+	var totSize int
+	for _, attr := range attrs {
+		if !xattrFilter.Permit(attr) {
+			l.Debugf("get xattr %s: skipping attribute %q denied by filter", path, attr)
+			continue
+		}
+		val, buf, err = getXattr(path, attr, buf)
+		var errNo syscall.Errno
+		if errors.As(err, &errNo) && errNo == 0x5d {
+			// ENOATTR, returned on BSD when asking for an attribute that
+			// doesn't exist (any more?)
+			continue
+		} else if err != nil {
+			return nil, fmt.Errorf("get xattr %s: %w", path, err)
+		}
+		if max := xattrFilter.GetMaxSingleEntrySize(); max > 0 && len(attr)+len(val) > max {
+			l.Debugf("get xattr %s: attribute %q exceeds max size", path, attr)
+			continue
+		}
+		totSize += len(attr) + len(val)
+		if max := xattrFilter.GetMaxTotalSize(); max > 0 && totSize > max {
+			l.Debugf("get xattr %s: attribute %q would cause max size to be exceeded", path, attr)
+			continue
+		}
+		res = append(res, protocol.Xattr{
+			Name:  attr,
+			Value: val,
+		})
+	}
+	return res, nil
+}
+
+func getXattr(path, name string, buf []byte) (val []byte, rest []byte, err error) {
+	if len(buf) == 0 {
+		buf = make([]byte, 1024)
+	}
+	size, err := unix.Lgetxattr(path, name, buf)
+	if errors.Is(err, unix.ERANGE) {
+		// Buffer was too small. Figure out how large it needs to be, and
+		// allocate.
+		size, err = unix.Lgetxattr(path, name, nil)
+		if err != nil {
+			return nil, nil, fmt.Errorf("Lgetxattr %s %q: %w", path, name, err)
+		}
+		if size > len(buf) {
+			buf = make([]byte, size)
+		}
+		size, err = unix.Lgetxattr(path, name, buf)
+	}
+	if err != nil {
+		return nil, buf, fmt.Errorf("Lgetxattr %s %q: %w", path, name, err)
+	}
+	return buf[:size], buf[size:], nil
+}
+
+func (f *BasicFilesystem) SetXattr(path string, xattrs []protocol.Xattr, xattrFilter XattrFilter) error {
+	// Index the new attribute set.
+	xattrsIdx := make(map[string]int)
+	for i, xa := range xattrs {
+		xattrsIdx[xa.Name] = i
+	}
+
+	// Get and index the existing attribute set
+	current, err := f.GetXattr(path, xattrFilter)
+	if err != nil {
+		return fmt.Errorf("set xattrs %s: GetXattr: %w", path, err)
+	}
+	currentIdx := make(map[string]int)
+	for i, xa := range current {
+		currentIdx[xa.Name] = i
+	}
+
+	path, err = f.rooted(path)
+	if err != nil {
+		return fmt.Errorf("set xattrs %s: %w", path, err)
+	}
+
+	// Remove all existing xattrs that are not in the new set
+	for _, xa := range current {
+		if _, ok := xattrsIdx[xa.Name]; !ok {
+			if err := unix.Lremovexattr(path, xa.Name); err != nil {
+				return fmt.Errorf("set xattrs %s: Removexattr %q: %w", path, xa.Name, err)
+			}
+		}
+	}
+
+	// Set all xattrs that are different in the new set
+	for _, xa := range xattrs {
+		if old, ok := currentIdx[xa.Name]; ok && bytes.Equal(xa.Value, current[old].Value) {
+			continue
+		}
+		if err := unix.Lsetxattr(path, xa.Name, xa.Value, 0); err != nil {
+			return fmt.Errorf("set xattrs %s: Setxattr %q: %w", path, xa.Name, err)
+		}
+	}
+
+	return nil
+}
+
+func compact(ss []string) []string {
+	i := 0
+	for _, s := range ss {
+		if s != "" {
+			ss[i] = s
+			i++
+		}
+	}
+	return ss[:i]
+}
diff --git a/lib/fs/basicfs_xattr_unsupported.go b/lib/fs/basicfs_xattr_unsupported.go
new file mode 100644
index 00000000000..e7a97598504
--- /dev/null
+++ b/lib/fs/basicfs_xattr_unsupported.go
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+//go:build windows || dragonfly || illumos || solaris || openbsd
+// +build windows dragonfly illumos solaris openbsd
+
+package fs
+
+import (
+	"github.com/syncthing/syncthing/lib/protocol"
+)
+
+func (f *BasicFilesystem) GetXattr(path string, xattrFilter XattrFilter) ([]protocol.Xattr, error) {
+	return nil, ErrXattrsNotSupported
+}
+
+func (f *BasicFilesystem) SetXattr(path string, xattrs []protocol.Xattr, xattrFilter XattrFilter) error {
+	return ErrXattrsNotSupported
+}
diff --git a/lib/fs/errorfs.go b/lib/fs/errorfs.go
index 903a6696eaa..c38cb38e02b 100644
--- a/lib/fs/errorfs.go
+++ b/lib/fs/errorfs.go
@@ -24,9 +24,15 @@ func (fs *errorFilesystem) Lchown(_, _, _ string) error      { return fs.err }
 func (fs *errorFilesystem) Chtimes(_ string, _ time.Time, _ time.Time) error {
 	return fs.err
 }
-func (fs *errorFilesystem) Create(_ string) (File, error)                { return nil, fs.err }
-func (fs *errorFilesystem) CreateSymlink(_, _ string) error              { return fs.err }
-func (fs *errorFilesystem) DirNames(_ string) ([]string, error)          { return nil, fs.err }
+func (fs *errorFilesystem) Create(_ string) (File, error)       { return nil, fs.err }
+func (fs *errorFilesystem) CreateSymlink(_, _ string) error     { return fs.err }
+func (fs *errorFilesystem) DirNames(_ string) ([]string, error) { return nil, fs.err }
+func (fs *errorFilesystem) GetXattr(_ string, _ XattrFilter) ([]protocol.Xattr, error) {
+	return nil, fs.err
+}
+func (fs *errorFilesystem) SetXattr(_ string, _ []protocol.Xattr, _ XattrFilter) error {
+	return fs.err
+}
 func (fs *errorFilesystem) Lstat(_ string) (FileInfo, error)             { return nil, fs.err }
 func (fs *errorFilesystem) Mkdir(_ string, _ FileMode) error             { return fs.err }
 func (fs *errorFilesystem) MkdirAll(_ string, _ FileMode) error          { return fs.err }
@@ -54,7 +60,7 @@ func (*errorFilesystem) SameFile(_, _ FileInfo) bool { return false }
 func (fs *errorFilesystem) Watch(_ string, _ Matcher, _ context.Context, _ bool) (<-chan Event, <-chan error, error) {
 	return nil, nil, fs.err
 }
-func (fs *errorFilesystem) PlatformData(_ string) (protocol.PlatformData, error) {
+func (fs *errorFilesystem) PlatformData(_ string, _, _ bool, _ XattrFilter) (protocol.PlatformData, error) {
 	return protocol.PlatformData{}, fs.err
 }
 
diff --git a/lib/fs/fakefs.go b/lib/fs/fakefs.go
index 86dfa8e59cd..28e16aab2eb 100644
--- a/lib/fs/fakefs.go
+++ b/lib/fs/fakefs.go
@@ -622,6 +622,14 @@ func (*fakeFS) Unhide(_ string) error {
 	return nil
 }
 
+func (*fakeFS) GetXattr(_ string, _ XattrFilter) ([]protocol.Xattr, error) {
+	return nil, nil
+}
+
+func (*fakeFS) SetXattr(_ string, _ []protocol.Xattr, _ XattrFilter) error {
+	return nil
+}
+
 func (*fakeFS) Glob(_ string) ([]string, error) {
 	// gnnh we don't seem to actually require this in practice
 	return nil, errors.New("not implemented")
@@ -662,8 +670,8 @@ func (fs *fakeFS) SameFile(fi1, fi2 FileInfo) bool {
 	return ok && fi1.ModTime().Equal(fi2.ModTime()) && fi1.Mode() == fi2.Mode() && fi1.IsDir() == fi2.IsDir() && fi1.IsRegular() == fi2.IsRegular() && fi1.IsSymlink() == fi2.IsSymlink() && fi1.Owner() == fi2.Owner() && fi1.Group() == fi2.Group()
 }
 
-func (fs *fakeFS) PlatformData(name string) (protocol.PlatformData, error) {
-	return unixPlatformData(fs, name, fs.userCache, fs.groupCache)
+func (fs *fakeFS) PlatformData(name string, scanOwnership, scanXattrs bool, xattrFilter XattrFilter) (protocol.PlatformData, error) {
+	return unixPlatformData(fs, name, fs.userCache, fs.groupCache, scanOwnership, scanXattrs, xattrFilter)
 }
 
 func (*fakeFS) underlying() (Filesystem, bool) {
@@ -961,3 +969,11 @@ func (f *fakeFileInfo) Owner() int {
 func (f *fakeFileInfo) Group() int {
 	return f.gid
 }
+
+func (*fakeFileInfo) Sys() interface{} {
+	return nil
+}
+
+func (*fakeFileInfo) InodeChangeTime() time.Time {
+	return time.Time{}
+}
diff --git a/lib/fs/filesystem.go b/lib/fs/filesystem.go
index 0653b128a48..219788fb722 100644
--- a/lib/fs/filesystem.go
+++ b/lib/fs/filesystem.go
@@ -29,6 +29,12 @@ const (
 	filesystemWrapperTypeLog
 )
 
+type XattrFilter interface {
+	Permit(string) bool
+	GetMaxSingleEntrySize() int
+	GetMaxTotalSize() int
+}
+
 // The Filesystem interface abstracts access to the file system.
 type Filesystem interface {
 	Chmod(name string, mode FileMode) error
@@ -62,7 +68,9 @@ type Filesystem interface {
 	URI() string
 	Options() []Option
 	SameFile(fi1, fi2 FileInfo) bool
-	PlatformData(name string) (protocol.PlatformData, error)
+	PlatformData(name string, withOwnership, withXattrs bool, xattrFilter XattrFilter) (protocol.PlatformData, error)
+	GetXattr(name string, xattrFilter XattrFilter) ([]protocol.Xattr, error)
+	SetXattr(path string, xattrs []protocol.Xattr, xattrFilter XattrFilter) error
 
 	// Used for unwrapping things
 	underlying() (Filesystem, bool)
@@ -94,11 +102,13 @@ type FileInfo interface {
 	Size() int64
 	ModTime() time.Time
 	IsDir() bool
+	Sys() interface{}
 	// Extensions
 	IsRegular() bool
 	IsSymlink() bool
 	Owner() int
 	Group() int
+	InodeChangeTime() time.Time // may be zero if not supported
 }
 
 // FileMode is similar to os.FileMode
@@ -154,7 +164,10 @@ func (evType EventType) String() string {
 	}
 }
 
-var ErrWatchNotSupported = errors.New("watching is not supported")
+var (
+	ErrWatchNotSupported  = errors.New("watching is not supported")
+	ErrXattrsNotSupported = errors.New("extended attributes are not supported on this platform")
+)
 
 // Equivalents from os package.
 
diff --git a/lib/fs/platform_common.go b/lib/fs/platform_common.go
index 3b7e45ff739..591398cf63c 100644
--- a/lib/fs/platform_common.go
+++ b/lib/fs/platform_common.go
@@ -17,42 +17,48 @@ import (
 // unixPlatformData is used on all platforms, because apart from being the
 // implementation for BasicFilesystem on Unixes it's also the implementation
 // in fakeFS.
-func unixPlatformData(fs Filesystem, name string, userCache *userCache, groupCache *groupCache) (protocol.PlatformData, error) {
-	stat, err := fs.Lstat(name)
-	if err != nil {
-		return protocol.PlatformData{}, err
-	}
+func unixPlatformData(fs Filesystem, name string, userCache *userCache, groupCache *groupCache, scanOwnership, scanXattrs bool, xattrFilter XattrFilter) (protocol.PlatformData, error) {
+	var pd protocol.PlatformData
+	if scanOwnership {
+		var ud protocol.UnixData
+
+		stat, err := fs.Lstat(name)
+		if err != nil {
+			return protocol.PlatformData{}, err
+		}
+
+		ud.UID = stat.Owner()
+		if user := userCache.lookup(strconv.Itoa(ud.UID)); user != nil {
+			ud.OwnerName = user.Username
+		} else if ud.UID == 0 {
+			// We couldn't look up a name, but UID zero should be "root". This
+			// fixup works around the (unlikely) situation where the ownership
+			// is 0:0 but we can't look up a name for either uid zero or gid
+			// zero. If that were the case we'd return a zero PlatformData which
+			// wouldn't get serialized over the wire and the other side would
+			// assume a lack of ownership info...
+			ud.OwnerName = "root"
+		}
+
+		ud.GID = stat.Group()
+		if group := groupCache.lookup(strconv.Itoa(ud.GID)); group != nil {
+			ud.GroupName = group.Name
+		} else if ud.GID == 0 {
+			ud.GroupName = "root"
+		}
 
-	ownerUID := stat.Owner()
-	ownerName := ""
-	if user := userCache.lookup(strconv.Itoa(ownerUID)); user != nil {
-		ownerName = user.Username
-	} else if ownerUID == 0 {
-		// We couldn't look up a name, but UID zero should be "root". This
-		// fixup works around the (unlikely) situation where the ownership
-		// is 0:0 but we can't look up a name for either uid zero or gid
-		// zero. If that were the case we'd return a zero PlatformData which
-		// wouldn't get serialized over the wire and the other side would
-		// assume a lack of ownership info...
-		ownerName = "root"
+		pd.Unix = &ud
 	}
 
-	groupID := stat.Group()
-	groupName := ""
-	if group := groupCache.lookup(strconv.Itoa(ownerUID)); group != nil {
-		groupName = group.Name
-	} else if groupID == 0 {
-		groupName = "root"
+	if scanXattrs {
+		xattrs, err := fs.GetXattr(name, xattrFilter)
+		if err != nil {
+			return protocol.PlatformData{}, err
+		}
+		pd.SetXattrs(xattrs)
 	}
 
-	return protocol.PlatformData{
-		Unix: &protocol.UnixData{
-			OwnerName: ownerName,
-			GroupName: groupName,
-			UID:       ownerUID,
-			GID:       groupID,
-		},
-	}, nil
+	return pd, nil
 }
 
 type valueCache[K comparable, V any] struct {
diff --git a/lib/model/folder.go b/lib/model/folder.go
index d1a630e6ddc..555de4ac69c 100644
--- a/lib/model/folder.go
+++ b/lib/model/folder.go
@@ -607,6 +607,7 @@ func (b *scanBatch) Update(fi protocol.FileInfo, snap *db.Snapshot) bool {
 		IgnoreBlocks:    true,
 		IgnoreFlags:     protocol.FlagLocalReceiveOnly,
 		IgnoreOwnership: !b.f.SyncOwnership,
+		IgnoreXattrs:    !b.f.SyncXattrs,
 	}):
 		// What we have locally is equivalent to the global file.
 		l.Debugf("%v scanning: Merging identical locally changed item with global", b.f, fi)
@@ -637,7 +638,6 @@ func (f *folder) scanSubdirsChangedAndNew(subDirs []string, batch *scanBatch) (i
 		CurrentFiler:          cFiler{snap},
 		Filesystem:            f.mtimefs,
 		IgnorePerms:           f.IgnorePerms,
-		IgnoreOwnership:       !f.SyncOwnership,
 		AutoNormalize:         f.AutoNormalize,
 		Hashers:               f.model.numHashers(f.ID),
 		ShortID:               f.shortID,
@@ -645,7 +645,9 @@ func (f *folder) scanSubdirsChangedAndNew(subDirs []string, batch *scanBatch) (i
 		LocalFlags:            f.localFlags,
 		ModTimeWindow:         f.modTimeWindow,
 		EventLogger:           f.evLogger,
-		ScanOwnership:         f.ScanOwnership || f.SyncOwnership,
+		ScanOwnership:         f.SendOwnership || f.SyncOwnership,
+		ScanXattrs:            f.SendXattrs || f.SyncXattrs,
+		XattrFilter:           f.XattrFilter,
 	}
 	var fchan chan scanner.ScanResult
 	if f.Type == config.FolderTypeReceiveEncrypted {
diff --git a/lib/model/folder_recvonly.go b/lib/model/folder_recvonly.go
index b410c069e36..21f927cd442 100644
--- a/lib/model/folder_recvonly.go
+++ b/lib/model/folder_recvonly.go
@@ -130,6 +130,7 @@ func (f *receiveOnlyFolder) revert() error {
 			ModTimeWindow:   f.modTimeWindow,
 			IgnoreFlags:     protocol.FlagLocalReceiveOnly,
 			IgnoreOwnership: !f.SyncOwnership,
+			IgnoreXattrs:    !f.SyncXattrs,
 		}):
 			// What we have locally is equivalent to the global file.
 			fi = gf
diff --git a/lib/model/folder_sendonly.go b/lib/model/folder_sendonly.go
index f71cb5de4d3..0e23a9f557b 100644
--- a/lib/model/folder_sendonly.go
+++ b/lib/model/folder_sendonly.go
@@ -76,6 +76,7 @@ func (f *sendOnlyFolder) pull() (bool, error) {
 			ModTimeWindow:   f.modTimeWindow,
 			IgnorePerms:     f.IgnorePerms,
 			IgnoreOwnership: !f.SyncOwnership,
+			IgnoreXattrs:    !f.SyncXattrs,
 		}) {
 			return true
 		}
diff --git a/lib/model/folder_sendrecv.go b/lib/model/folder_sendrecv.go
index af00eb2b5de..df8b5778331 100644
--- a/lib/model/folder_sendrecv.go
+++ b/lib/model/folder_sendrecv.go
@@ -592,8 +592,7 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo, snap *db.Snapshot,
 		// Check that it is what we have in the database.
 		curFile, hasCurFile := snap.Get(protocol.LocalDeviceID, file.Name)
 		if err := f.scanIfItemChanged(file.Name, info, curFile, hasCurFile, scanChan); err != nil {
-			err = fmt.Errorf("handling dir: %w", err)
-			f.newPullError(file.Name, err)
+			f.newPullError(file.Name, fmt.Errorf("handling dir: %w", err))
 			return
 		}
 
@@ -661,7 +660,7 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo, snap *db.Snapshot,
 	// It's OK to change mode bits on stuff within non-writable directories.
 	if !f.IgnorePerms && !file.NoPermissions {
 		if err := f.mtimefs.Chmod(file.Name, mode|(info.Mode()&retainBits)); err != nil {
-			f.newPullError(file.Name, err)
+			f.newPullError(file.Name, fmt.Errorf("handling dir (setting permissions): %w", err))
 			return
 		}
 	}
@@ -988,13 +987,14 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, sn
 		err = errModified
 	default:
 		var fi protocol.FileInfo
-		if fi, err = scanner.CreateFileInfo(stat, target.Name, f.mtimefs, f.SyncOwnership); err == nil {
+		if fi, err = scanner.CreateFileInfo(stat, target.Name, f.mtimefs, f.SyncOwnership, f.SyncXattrs, f.XattrFilter); err == nil {
 			if !fi.IsEquivalentOptional(curTarget, protocol.FileInfoComparison{
 				ModTimeWindow:   f.modTimeWindow,
 				IgnorePerms:     f.IgnorePerms,
 				IgnoreBlocks:    true,
 				IgnoreFlags:     protocol.LocalAllFlags,
 				IgnoreOwnership: !f.SyncOwnership,
+				IgnoreXattrs:    !f.SyncXattrs,
 			}) {
 				// Target changed
 				scanChan <- target.Name
@@ -1203,8 +1203,8 @@ func populateOffsets(blocks []protocol.BlockInfo) {
 	}
 }
 
-// shortcutFile sets file mode and modification time, when that's the only
-// thing that has changed.
+// shortcutFile sets file metadata, when that's the only thing that has
+// changed.
 func (f *sendReceiveFolder) shortcutFile(file protocol.FileInfo, dbUpdateChan chan<- dbUpdateJob) {
 	l.Debugln(f, "taking shortcut on", file.Name)
 
@@ -1228,13 +1228,22 @@ func (f *sendReceiveFolder) shortcutFile(file protocol.FileInfo, dbUpdateChan ch
 
 	if !f.IgnorePerms && !file.NoPermissions {
 		if err = f.mtimefs.Chmod(file.Name, fs.FileMode(file.Permissions&0777)); err != nil {
-			f.newPullError(file.Name, err)
+			f.newPullError(file.Name, fmt.Errorf("shortcut file (setting permissions): %w", err))
+			return
+		}
+	}
+
+	if f.SyncXattrs {
+		if err = f.mtimefs.SetXattr(file.Name, file.Platform.Xattrs(), f.XattrFilter); errors.Is(err, fs.ErrXattrsNotSupported) {
+			l.Debugf("Cannot set xattrs on %q: %v", file.Name, err)
+		} else if err != nil {
+			f.newPullError(file.Name, fmt.Errorf("shortcut file (setting xattrs): %w", err))
 			return
 		}
 	}
 
 	if err := f.maybeAdjustOwnership(&file, file.Name); err != nil {
-		f.newPullError(file.Name, err)
+		f.newPullError(file.Name, fmt.Errorf("shortcut file (setting ownership): %w", err))
 		return
 	}
 
@@ -1253,7 +1262,7 @@ func (f *sendReceiveFolder) shortcutFile(file protocol.FileInfo, dbUpdateChan ch
 			return fd.Truncate(file.Size + trailerSize)
 		}, f.mtimefs, file.Name, true)
 		if err != nil {
-			f.newPullError(file.Name, err)
+			f.newPullError(file.Name, fmt.Errorf("writing encrypted file trailer: %w", err))
 			return
 		}
 	}
@@ -1599,13 +1608,22 @@ func (f *sendReceiveFolder) performFinish(file, curFile protocol.FileInfo, hasCu
 	// Set the correct permission bits on the new file
 	if !f.IgnorePerms && !file.NoPermissions {
 		if err := f.mtimefs.Chmod(tempName, fs.FileMode(file.Permissions&0777)); err != nil {
-			return err
+			return fmt.Errorf("setting permissions: %w", err)
+		}
+	}
+
+	// Set extended attributes
+	if f.SyncXattrs {
+		if err := f.mtimefs.SetXattr(tempName, file.Platform.Xattrs(), f.XattrFilter); errors.Is(err, fs.ErrXattrsNotSupported) {
+			l.Debugf("Cannot set xattrs on %q: %v", file.Name, err)
+		} else if err != nil {
+			return fmt.Errorf("setting xattrs: %w", err)
 		}
 	}
 
 	// Set ownership based on file metadata or parent, maybe.
 	if err := f.maybeAdjustOwnership(&file, tempName); err != nil {
-		return err
+		return fmt.Errorf("setting ownership: %w", err)
 	}
 
 	if stat, err := f.mtimefs.Lstat(file.Name); err == nil {
@@ -1613,7 +1631,7 @@ func (f *sendReceiveFolder) performFinish(file, curFile protocol.FileInfo, hasCu
 		// handle that.
 
 		if err := f.scanIfItemChanged(file.Name, stat, curFile, hasCurFile, scanChan); err != nil {
-			return err
+			return fmt.Errorf("checking existing file: %w", err)
 		}
 
 		if !curFile.IsDirectory() && !curFile.IsSymlink() && f.inConflict(curFile.Version, file.Version) {
@@ -1629,16 +1647,16 @@ func (f *sendReceiveFolder) performFinish(file, curFile protocol.FileInfo, hasCu
 			err = f.deleteItemOnDisk(curFile, snap, scanChan)
 		}
 		if err != nil {
-			return err
+			return fmt.Errorf("moving for conflict: %w", err)
 		}
 	} else if !fs.IsNotExist(err) {
-		return err
+		return fmt.Errorf("checking existing file: %w", err)
 	}
 
 	// Replace the original content with the new one. If it didn't work,
 	// leave the temp file in place for reuse.
 	if err := osutil.RenameOrCopy(f.CopyRangeMethod, f.mtimefs, f.mtimefs, tempName, file.Name); err != nil {
-		return err
+		return fmt.Errorf("replacing file: %w", err)
 	}
 
 	// Set the correct timestamp on the new file
@@ -1661,7 +1679,7 @@ func (f *sendReceiveFolder) finisherRoutine(snap *db.Snapshot, in <-chan *shared
 			}
 
 			if err != nil {
-				f.newPullError(state.file.Name, err)
+				f.newPullError(state.file.Name, fmt.Errorf("finishing: %w", err))
 			} else {
 				minBlocksPerBlock := state.file.BlockSize() / protocol.MinBlockSize
 				blockStatsMut.Lock()
@@ -1768,6 +1786,15 @@ loop:
 				lastFile = job.file
 			}
 
+			if !job.file.IsDeleted() && !job.file.IsInvalid() {
+				// Now that the file is finalized, grab possibly updated
+				// inode change time from disk into the local FileInfo. We
+				// use this change time to check for changes to xattrs etc
+				// on next scan.
+				if err := f.updateFileInfoChangeTime(&job.file); err != nil {
+					l.Warnln("Error updating metadata for %q at database commit: %v", job.file.Name, err)
+				}
+			}
 			job.file.Sequence = 0
 
 			batch.Append(job.file)
@@ -1878,7 +1905,7 @@ func (f *sendReceiveFolder) newPullError(path string, err error) {
 	// Establish context to differentiate from errors while scanning.
 	// Use "syncing" as opposed to "pulling" as the latter might be used
 	// for errors occurring specifically in the puller routine.
-	errStr := fmt.Sprintln("syncing:", err)
+	errStr := fmt.Sprintf("syncing: %s", err)
 	f.tempPullErrors[path] = errStr
 
 	l.Debugf("%v new error for %v: %v", f, path, err)
@@ -1978,7 +2005,7 @@ func (f *sendReceiveFolder) deleteDirOnDiskHandleChildren(dir string, snap *db.S
 			hasReceiveOnlyChanged = true
 			return nil
 		}
-		diskFile, err := scanner.CreateFileInfo(info, path, f.mtimefs, f.SyncOwnership)
+		diskFile, err := scanner.CreateFileInfo(info, path, f.mtimefs, f.SyncOwnership, f.SyncXattrs, f.XattrFilter)
 		if err != nil {
 			// Lets just assume the file has changed.
 			scanChan <- path
@@ -1991,6 +2018,7 @@ func (f *sendReceiveFolder) deleteDirOnDiskHandleChildren(dir string, snap *db.S
 			IgnoreBlocks:    true,
 			IgnoreFlags:     protocol.LocalAllFlags,
 			IgnoreOwnership: !f.SyncOwnership,
+			IgnoreXattrs:    !f.SyncXattrs,
 		}) {
 			// File on disk changed compared to what we have in db
 			// -> schedule scan.
@@ -2055,7 +2083,7 @@ func (f *sendReceiveFolder) scanIfItemChanged(name string, stat fs.FileInfo, ite
 	// to the database. If there's a mismatch here, there might be local
 	// changes that we don't know about yet and we should scan before
 	// touching the item.
-	statItem, err := scanner.CreateFileInfo(stat, item.Name, f.mtimefs, f.SyncOwnership)
+	statItem, err := scanner.CreateFileInfo(stat, item.Name, f.mtimefs, f.SyncOwnership, f.SyncXattrs, f.XattrFilter)
 	if err != nil {
 		return fmt.Errorf("comparing item on disk to db: %w", err)
 	}
@@ -2066,6 +2094,7 @@ func (f *sendReceiveFolder) scanIfItemChanged(name string, stat fs.FileInfo, ite
 		IgnoreBlocks:    true,
 		IgnoreFlags:     protocol.LocalAllFlags,
 		IgnoreOwnership: !f.SyncOwnership,
+		IgnoreXattrs:    !f.SyncXattrs,
 	}) {
 		return errModified
 	}
@@ -2150,6 +2179,22 @@ func (f *sendReceiveFolder) withLimiter(fn func() error) error {
 	return fn()
 }
 
+// updateFileInfoChangeTime updates the inode change time in the FileInfo,
+// because that depends on the current, new, state of the file on disk.
+func (f *sendReceiveFolder) updateFileInfoChangeTime(file *protocol.FileInfo) error {
+	info, err := f.mtimefs.Lstat(file.Name)
+	if err != nil {
+		return err
+	}
+
+	if ct := info.InodeChangeTime(); !ct.IsZero() {
+		file.InodeChangeNs = ct.UnixNano()
+	} else {
+		file.InodeChangeNs = 0
+	}
+	return nil
+}
+
 // A []FileError is sent as part of an event and will be JSON serialized.
 type FileError struct {
 	Path string `json:"path"`
diff --git a/lib/model/indexhandler.go b/lib/model/indexhandler.go
index 1d53cbaa0c9..747eab96f88 100644
--- a/lib/model/indexhandler.go
+++ b/lib/model/indexhandler.go
@@ -360,6 +360,7 @@ func prepareFileInfoForIndex(f protocol.FileInfo) protocol.FileInfo {
 	// never sent externally
 	f.LocalFlags = 0
 	f.VersionHash = nil
+	f.InodeChangeNs = 0
 	return f
 }
 
diff --git a/lib/protocol/bep.pb.go b/lib/protocol/bep.pb.go
index 148da5be710..56d034e9577 100644
--- a/lib/protocol/bep.pb.go
+++ b/lib/protocol/bep.pb.go
@@ -513,10 +513,13 @@ type FileInfo struct {
 	LocalFlags uint32 `protobuf:"varint,1000,opt,name=local_flags,json=localFlags,proto3" json:"localFlags" xml:"localFlags"`
 	// The version_hash is an implementation detail and not part of the wire
 	// format.
-	VersionHash   []byte `protobuf:"bytes,1001,opt,name=version_hash,json=versionHash,proto3" json:"versionHash" xml:"versionHash"`
-	Deleted       bool   `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted" xml:"deleted"`
-	RawInvalid    bool   `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid" xml:"invalid"`
-	NoPermissions bool   `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"noPermissions" xml:"noPermissions"`
+	VersionHash []byte `protobuf:"bytes,1001,opt,name=version_hash,json=versionHash,proto3" json:"versionHash" xml:"versionHash"`
+	// The time when the inode was last changed (i.e., permissions, xattrs
+	// etc changed). This is host-local, not sent over the wire.
+	InodeChangeNs int64 `protobuf:"varint,1002,opt,name=inode_change_ns,json=inodeChangeNs,proto3" json:"inodeChangeNs" xml:"inodeChangeNs"`
+	Deleted       bool  `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted" xml:"deleted"`
+	RawInvalid    bool  `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid" xml:"invalid"`
+	NoPermissions bool  `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"noPermissions" xml:"noPermissions"`
 }
 
 func (m *FileInfo) Reset()      { *m = FileInfo{} }
@@ -668,6 +671,10 @@ var xxx_messageInfo_Counter proto.InternalMessageInfo
 type PlatformData struct {
 	Unix    *UnixData    `protobuf:"bytes,1,opt,name=unix,proto3" json:"unix" xml:"unix"`
 	Windows *WindowsData `protobuf:"bytes,2,opt,name=windows,proto3" json:"windows" xml:"windows"`
+	Linux   *XattrData   `protobuf:"bytes,3,opt,name=linux,proto3" json:"linux" xml:"linux"`
+	Darwin  *XattrData   `protobuf:"bytes,4,opt,name=darwin,proto3" json:"darwin" xml:"darwin"`
+	FreeBSD *XattrData   `protobuf:"bytes,5,opt,name=freebsd,proto3" json:"freebsd" xml:"freebsd"`
+	NetBSD  *XattrData   `protobuf:"bytes,6,opt,name=netbsd,proto3" json:"netbsd" xml:"netbsd"`
 }
 
 func (m *PlatformData) Reset()         { *m = PlatformData{} }
@@ -787,6 +794,81 @@ func (m *WindowsData) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_WindowsData proto.InternalMessageInfo
 
+type XattrData struct {
+	Xattrs []Xattr `protobuf:"bytes,1,rep,name=xattrs,proto3" json:"xattrs" xml:"xattr"`
+}
+
+func (m *XattrData) Reset()         { *m = XattrData{} }
+func (m *XattrData) String() string { return proto.CompactTextString(m) }
+func (*XattrData) ProtoMessage()    {}
+func (*XattrData) Descriptor() ([]byte, []int) {
+	return fileDescriptor_311ef540e10d9705, []int{14}
+}
+func (m *XattrData) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *XattrData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_XattrData.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *XattrData) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_XattrData.Merge(m, src)
+}
+func (m *XattrData) XXX_Size() int {
+	return m.ProtoSize()
+}
+func (m *XattrData) XXX_DiscardUnknown() {
+	xxx_messageInfo_XattrData.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_XattrData proto.InternalMessageInfo
+
+type Xattr struct {
+	Name  string `protobuf:"bytes,1,opt,name=name,proto3" json:"name" xml:"name"`
+	Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value" xml:"value"`
+}
+
+func (m *Xattr) Reset()         { *m = Xattr{} }
+func (m *Xattr) String() string { return proto.CompactTextString(m) }
+func (*Xattr) ProtoMessage()    {}
+func (*Xattr) Descriptor() ([]byte, []int) {
+	return fileDescriptor_311ef540e10d9705, []int{15}
+}
+func (m *Xattr) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Xattr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Xattr.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *Xattr) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Xattr.Merge(m, src)
+}
+func (m *Xattr) XXX_Size() int {
+	return m.ProtoSize()
+}
+func (m *Xattr) XXX_DiscardUnknown() {
+	xxx_messageInfo_Xattr.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Xattr proto.InternalMessageInfo
+
 type Request struct {
 	ID            int    `protobuf:"varint,1,opt,name=id,proto3,casttype=int" json:"id" xml:"id"`
 	Folder        string `protobuf:"bytes,2,opt,name=folder,proto3" json:"folder" xml:"folder"`
@@ -803,7 +885,7 @@ func (m *Request) Reset()         { *m = Request{} }
 func (m *Request) String() string { return proto.CompactTextString(m) }
 func (*Request) ProtoMessage()    {}
 func (*Request) Descriptor() ([]byte, []int) {
-	return fileDescriptor_311ef540e10d9705, []int{14}
+	return fileDescriptor_311ef540e10d9705, []int{16}
 }
 func (m *Request) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -842,7 +924,7 @@ func (m *Response) Reset()         { *m = Response{} }
 func (m *Response) String() string { return proto.CompactTextString(m) }
 func (*Response) ProtoMessage()    {}
 func (*Response) Descriptor() ([]byte, []int) {
-	return fileDescriptor_311ef540e10d9705, []int{15}
+	return fileDescriptor_311ef540e10d9705, []int{17}
 }
 func (m *Response) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -880,7 +962,7 @@ func (m *DownloadProgress) Reset()         { *m = DownloadProgress{} }
 func (m *DownloadProgress) String() string { return proto.CompactTextString(m) }
 func (*DownloadProgress) ProtoMessage()    {}
 func (*DownloadProgress) Descriptor() ([]byte, []int) {
-	return fileDescriptor_311ef540e10d9705, []int{16}
+	return fileDescriptor_311ef540e10d9705, []int{18}
 }
 func (m *DownloadProgress) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -921,7 +1003,7 @@ func (m *FileDownloadProgressUpdate) Reset()         { *m = FileDownloadProgress
 func (m *FileDownloadProgressUpdate) String() string { return proto.CompactTextString(m) }
 func (*FileDownloadProgressUpdate) ProtoMessage()    {}
 func (*FileDownloadProgressUpdate) Descriptor() ([]byte, []int) {
-	return fileDescriptor_311ef540e10d9705, []int{17}
+	return fileDescriptor_311ef540e10d9705, []int{19}
 }
 func (m *FileDownloadProgressUpdate) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -957,7 +1039,7 @@ func (m *Ping) Reset()         { *m = Ping{} }
 func (m *Ping) String() string { return proto.CompactTextString(m) }
 func (*Ping) ProtoMessage()    {}
 func (*Ping) Descriptor() ([]byte, []int) {
-	return fileDescriptor_311ef540e10d9705, []int{18}
+	return fileDescriptor_311ef540e10d9705, []int{20}
 }
 func (m *Ping) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -994,7 +1076,7 @@ func (m *Close) Reset()         { *m = Close{} }
 func (m *Close) String() string { return proto.CompactTextString(m) }
 func (*Close) ProtoMessage()    {}
 func (*Close) Descriptor() ([]byte, []int) {
-	return fileDescriptor_311ef540e10d9705, []int{19}
+	return fileDescriptor_311ef540e10d9705, []int{21}
 }
 func (m *Close) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1044,6 +1126,8 @@ func init() {
 	proto.RegisterType((*PlatformData)(nil), "protocol.PlatformData")
 	proto.RegisterType((*UnixData)(nil), "protocol.UnixData")
 	proto.RegisterType((*WindowsData)(nil), "protocol.WindowsData")
+	proto.RegisterType((*XattrData)(nil), "protocol.XattrData")
+	proto.RegisterType((*Xattr)(nil), "protocol.Xattr")
 	proto.RegisterType((*Request)(nil), "protocol.Request")
 	proto.RegisterType((*Response)(nil), "protocol.Response")
 	proto.RegisterType((*DownloadProgress)(nil), "protocol.DownloadProgress")
@@ -1055,190 +1139,203 @@ func init() {
 func init() { proto.RegisterFile("lib/protocol/bep.proto", fileDescriptor_311ef540e10d9705) }
 
 var fileDescriptor_311ef540e10d9705 = []byte{
-	// 2920 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x4f, 0x6c, 0x1b, 0xc7,
-	0xd5, 0xd7, 0x92, 0x94, 0x44, 0x8d, 0x64, 0x87, 0x1a, 0xff, 0x63, 0x68, 0x5b, 0xcb, 0x6f, 0xe2,
-	0x7c, 0x9f, 0xa2, 0x7c, 0xb1, 0x13, 0x27, 0xf9, 0xbe, 0x34, 0x4e, 0x1d, 0x88, 0x22, 0x25, 0x33,
-	0x91, 0x49, 0x65, 0x28, 0xdb, 0xb5, 0xd1, 0x82, 0x58, 0x71, 0x47, 0xd4, 0xc2, 0xe4, 0x2e, 0xbb,
-	0x4b, 0xea, 0x4f, 0xd0, 0x4b, 0x5b, 0xa0, 0x08, 0x74, 0x28, 0x8a, 0x9c, 0x8a, 0xa2, 0x42, 0x83,
-	0x02, 0x45, 0x6f, 0x05, 0x7a, 0xe8, 0xa1, 0x39, 0xf5, 0xe8, 0xa3, 0x11, 0xa0, 0x40, 0xd1, 0xc3,
-	0x02, 0xb1, 0x2f, 0x2d, 0x8f, 0x3c, 0xf6, 0x54, 0xcc, 0x9b, 0xd9, 0xd9, 0x59, 0xfd, 0x09, 0x94,
-	0xe4, 0xd0, 0xdb, 0xbe, 0xdf, 0xfb, 0xb3, 0xc3, 0x37, 0xef, 0xfd, 0xe6, 0xcd, 0x12, 0x5d, 0xec,
-	0x38, 0x1b, 0x37, 0x7a, 0xbe, 0xd7, 0xf7, 0x5a, 0x5e, 0xe7, 0xc6, 0x06, 0xeb, 0x5d, 0x07, 0x01,
-	0x67, 0x23, 0xac, 0x30, 0xc5, 0x76, 0xfb, 0x02, 0x2c, 0xbc, 0xe4, 0xb3, 0x9e, 0x17, 0x08, 0xf3,
-	0x8d, 0xc1, 0xe6, 0x8d, 0xb6, 0xd7, 0xf6, 0x40, 0x80, 0x27, 0x61, 0x44, 0x9e, 0x19, 0x68, 0xfc,
-	0x0e, 0xeb, 0x74, 0x3c, 0xbc, 0x84, 0xa6, 0x6d, 0xb6, 0xed, 0xb4, 0x58, 0xd3, 0xb5, 0xba, 0x2c,
-	0x6f, 0x14, 0x8d, 0xf9, 0xa9, 0x12, 0x19, 0x86, 0x26, 0x12, 0x70, 0xcd, 0xea, 0xb2, 0x51, 0x68,
-	0xe6, 0x76, 0xbb, 0x9d, 0x77, 0x49, 0x0c, 0x11, 0xaa, 0xe9, 0x79, 0x90, 0x56, 0xc7, 0x61, 0x6e,
-	0x5f, 0x04, 0x49, 0xc5, 0x41, 0x04, 0x9c, 0x08, 0x12, 0x43, 0x84, 0x6a, 0x7a, 0x5c, 0x47, 0x67,
-	0x65, 0x90, 0x6d, 0xe6, 0x07, 0x8e, 0xe7, 0xe6, 0xd3, 0x10, 0x67, 0x7e, 0x18, 0x9a, 0x67, 0x84,
-	0xe6, 0xbe, 0x50, 0x8c, 0x42, 0xf3, 0x9c, 0x16, 0x4a, 0xa2, 0x84, 0x26, 0xad, 0xc8, 0x1f, 0x0d,
-	0x34, 0x71, 0x87, 0x59, 0x36, 0xf3, 0xf1, 0x22, 0xca, 0xf4, 0xf7, 0x7a, 0xe2, 0xe7, 0x9d, 0xbd,
-	0x79, 0xe1, 0x7a, 0x94, 0xb8, 0xeb, 0x77, 0x59, 0x10, 0x58, 0x6d, 0xb6, 0xbe, 0xd7, 0x63, 0xa5,
-	0x8b, 0xc3, 0xd0, 0x04, 0xb3, 0x51, 0x68, 0x22, 0x88, 0xcf, 0x05, 0x42, 0x01, 0xc3, 0x36, 0x9a,
-	0x6e, 0x79, 0xdd, 0x9e, 0xcf, 0x02, 0x58, 0x5b, 0x0a, 0x22, 0x5d, 0x39, 0x12, 0x69, 0x29, 0xb6,
-	0x29, 0x5d, 0x1b, 0x86, 0xa6, 0xee, 0x34, 0x0a, 0xcd, 0x59, 0xb1, 0xee, 0x18, 0x23, 0x54, 0xb7,
-	0x20, 0xdf, 0x47, 0x67, 0x96, 0x3a, 0x83, 0xa0, 0xcf, 0xfc, 0x25, 0xcf, 0xdd, 0x74, 0xda, 0xf8,
-	0x43, 0x34, 0xb9, 0xe9, 0x75, 0x6c, 0xe6, 0x07, 0x79, 0xa3, 0x98, 0x9e, 0x9f, 0xbe, 0x99, 0x8b,
-	0x5f, 0xb9, 0x0c, 0x8a, 0x92, 0xf9, 0x24, 0x34, 0xc7, 0x86, 0xa1, 0x19, 0x19, 0x8e, 0x42, 0x73,
-	0x06, 0x5e, 0x23, 0x64, 0x42, 0x23, 0x05, 0xf9, 0x3c, 0x83, 0x26, 0x84, 0x13, 0xbe, 0x8e, 0x52,
-	0x8e, 0x2d, 0xb7, 0x7b, 0xee, 0x59, 0x68, 0xa6, 0xaa, 0xe5, 0x61, 0x68, 0xa6, 0x1c, 0x7b, 0x14,
-	0x9a, 0x59, 0xf0, 0x76, 0x6c, 0xf2, 0xe9, 0xd3, 0x6b, 0xa9, 0x6a, 0x99, 0xa6, 0x1c, 0x1b, 0x5f,
-	0x47, 0xe3, 0x1d, 0x6b, 0x83, 0x75, 0xe4, 0xe6, 0xe6, 0x87, 0xa1, 0x29, 0x80, 0x51, 0x68, 0x4e,
-	0x83, 0x3d, 0x48, 0x84, 0x0a, 0x14, 0xdf, 0x42, 0x53, 0x3e, 0xb3, 0xec, 0xa6, 0xe7, 0x76, 0xf6,
-	0x60, 0x23, 0xb3, 0xa5, 0xb9, 0x61, 0x68, 0x66, 0x39, 0x58, 0x77, 0x3b, 0x7b, 0xa3, 0xd0, 0x3c,
-	0x0b, 0x6e, 0x11, 0x40, 0xa8, 0xd2, 0xe1, 0x26, 0xc2, 0x4e, 0xdb, 0xf5, 0x7c, 0xd6, 0xec, 0x31,
-	0xbf, 0xeb, 0x40, 0x6a, 0x82, 0x7c, 0x06, 0xa2, 0xbc, 0x3e, 0x0c, 0xcd, 0x59, 0xa1, 0x5d, 0x8b,
-	0x95, 0xa3, 0xd0, 0xbc, 0x24, 0x56, 0x7d, 0x58, 0x43, 0xe8, 0x51, 0x6b, 0xfc, 0x21, 0x3a, 0x23,
-	0x5f, 0x60, 0xb3, 0x0e, 0xeb, 0xb3, 0xfc, 0x38, 0xc4, 0xfe, 0xef, 0x61, 0x68, 0xce, 0x08, 0x45,
-	0x19, 0xf0, 0x51, 0x68, 0x62, 0x2d, 0xac, 0x00, 0x09, 0x4d, 0xd8, 0x60, 0x1b, 0x9d, 0xb7, 0x9d,
-	0xc0, 0xda, 0xe8, 0xb0, 0x66, 0x9f, 0x75, 0x7b, 0x4d, 0xc7, 0xb5, 0xd9, 0x2e, 0x0b, 0xf2, 0x13,
-	0x10, 0xf3, 0xe6, 0x30, 0x34, 0xb1, 0xd4, 0xaf, 0xb3, 0x6e, 0xaf, 0x2a, 0xb4, 0xa3, 0xd0, 0xcc,
-	0x8b, 0x9e, 0x3a, 0xa2, 0x22, 0xf4, 0x18, 0x7b, 0x7c, 0x13, 0x4d, 0xf4, 0xac, 0x41, 0xc0, 0xec,
-	0xfc, 0x24, 0xc4, 0x2d, 0x0c, 0x43, 0x53, 0x22, 0x6a, 0xc3, 0x85, 0x48, 0xa8, 0xc4, 0x79, 0xf1,
-	0x88, 0x2e, 0x0d, 0xf2, 0xb9, 0xc3, 0xc5, 0x53, 0x06, 0x45, 0x5c, 0x3c, 0xd2, 0x50, 0xc5, 0x12,
-	0x32, 0xa1, 0x91, 0x82, 0xfc, 0x65, 0x02, 0x4d, 0x08, 0x27, 0x5c, 0x52, 0xc5, 0x33, 0x53, 0xba,
-	0xc9, 0x03, 0xfc, 0x3d, 0x34, 0xb3, 0x42, 0x57, 0x2d, 0x9f, 0x54, 0x4c, 0x9f, 0x3c, 0xbd, 0x66,
-	0x68, 0x05, 0xb5, 0x80, 0x32, 0x1a, 0x59, 0x40, 0xef, 0xb9, 0x82, 0x26, 0x44, 0xef, 0xb9, 0x40,
-	0x10, 0x80, 0xe1, 0xf7, 0xd0, 0x94, 0x65, 0xdb, 0xbc, 0x47, 0x58, 0x90, 0x4f, 0x17, 0xd3, 0xbc,
-	0x66, 0x87, 0xa1, 0x19, 0x83, 0xa3, 0xd0, 0x3c, 0x03, 0x5e, 0x12, 0x21, 0x34, 0xd6, 0xe1, 0x1f,
-	0x24, 0x3b, 0x37, 0x73, 0x98, 0x03, 0xbe, 0x5d, 0xcb, 0xf2, 0x4a, 0x6f, 0x31, 0x5f, 0x52, 0xdf,
-	0xb8, 0x68, 0x28, 0x5e, 0xe9, 0x1c, 0x94, 0xc4, 0x27, 0x2a, 0x3d, 0x02, 0x08, 0x55, 0x3a, 0xbc,
-	0x82, 0x66, 0xba, 0xd6, 0x6e, 0x33, 0x60, 0x3f, 0x1c, 0x30, 0xb7, 0xc5, 0xa0, 0x66, 0xd2, 0x62,
-	0x15, 0x5d, 0x6b, 0xb7, 0x21, 0x61, 0xb5, 0x0a, 0x0d, 0x23, 0x54, 0xb7, 0xc0, 0x25, 0x84, 0x1c,
-	0xb7, 0xef, 0x7b, 0xf6, 0xa0, 0xc5, 0x7c, 0x59, 0x22, 0xc0, 0xc0, 0x31, 0xaa, 0x18, 0x38, 0x86,
-	0x08, 0xd5, 0xf4, 0xb8, 0x8d, 0xb2, 0x50, 0xbb, 0x4d, 0xc7, 0xce, 0x67, 0x8b, 0xc6, 0x7c, 0xa6,
-	0xb4, 0x2a, 0x37, 0x77, 0x12, 0xaa, 0x10, 0xf6, 0x36, 0x7a, 0xe4, 0x35, 0x03, 0xd6, 0x55, 0x5b,
-	0x65, 0x5f, 0xca, 0x9c, 0x37, 0x22, 0xb3, 0x5f, 0xc5, 0x8f, 0x34, 0xb2, 0xc7, 0x3f, 0x42, 0x85,
-	0xe0, 0xb1, 0xc3, 0x3b, 0x45, 0xbc, 0xbb, 0xef, 0x78, 0x6e, 0xd3, 0x67, 0x5d, 0x6f, 0xdb, 0xea,
-	0x04, 0xf9, 0x29, 0x58, 0xfc, 0xed, 0x61, 0x68, 0xe6, 0xb9, 0x55, 0x55, 0x33, 0xa2, 0xd2, 0x66,
-	0x14, 0x9a, 0x73, 0xf0, 0xc6, 0x93, 0x0c, 0x08, 0x3d, 0xd1, 0x17, 0xef, 0xa2, 0x17, 0x99, 0xdb,
-	0xf2, 0xf7, 0x7a, 0xf0, 0xda, 0x9e, 0x15, 0x04, 0x3b, 0x9e, 0x6f, 0x37, 0xfb, 0xde, 0x63, 0xe6,
-	0xe6, 0x11, 0x14, 0xf5, 0x7b, 0xc3, 0xd0, 0xbc, 0x14, 0x1b, 0xad, 0x49, 0x9b, 0x75, 0x6e, 0x32,
-	0x0a, 0xcd, 0xab, 0xf0, 0xee, 0x13, 0xf4, 0x84, 0x9e, 0xe4, 0x49, 0x7e, 0x62, 0xa0, 0x71, 0x48,
-	0x06, 0xef, 0x66, 0x41, 0xca, 0x92, 0x82, 0xa1, 0x9b, 0x05, 0x72, 0x84, 0xbe, 0x25, 0x8e, 0x2b,
-	0x68, 0x7c, 0xd3, 0xe9, 0xb0, 0x20, 0x9f, 0x82, 0x5e, 0xc6, 0xda, 0x41, 0xe0, 0x74, 0x58, 0xd5,
-	0xdd, 0xf4, 0x4a, 0x97, 0x65, 0x37, 0x0b, 0x43, 0xd5, 0x4b, 0x5c, 0x22, 0x54, 0x80, 0xe4, 0x13,
-	0x03, 0x4d, 0xc3, 0x22, 0xee, 0xf5, 0x6c, 0xab, 0xcf, 0xfe, 0x93, 0x4b, 0xf9, 0xf3, 0x34, 0xca,
-	0x46, 0x0e, 0x8a, 0x10, 0x8c, 0x53, 0x10, 0xc2, 0x02, 0xca, 0x04, 0xce, 0xc7, 0x0c, 0x0e, 0x96,
-	0xb4, 0xb0, 0xe5, 0xb2, 0xb2, 0xe5, 0x02, 0xa1, 0x80, 0xe1, 0xf7, 0x11, 0xea, 0x7a, 0xb6, 0xb3,
-	0xe9, 0x30, 0xbb, 0x19, 0x40, 0x83, 0xa6, 0x4b, 0x45, 0xce, 0x1e, 0x11, 0xda, 0x18, 0x85, 0xe6,
-	0x0b, 0xa2, 0xbd, 0x22, 0x84, 0xd0, 0x58, 0xcb, 0xf9, 0x43, 0x05, 0xd8, 0xd8, 0xcb, 0xcf, 0x40,
-	0x67, 0xbc, 0x17, 0x75, 0x46, 0x63, 0xcb, 0xf3, 0xfb, 0xd0, 0x0e, 0xea, 0x35, 0xa5, 0x3d, 0xd5,
-	0x6a, 0x31, 0x44, 0x78, 0x27, 0x48, 0x63, 0xaa, 0x99, 0xe2, 0x55, 0x34, 0x19, 0x0d, 0x3c, 0xbc,
-	0xf2, 0x13, 0x24, 0x7d, 0x9f, 0xb5, 0xfa, 0x9e, 0x5f, 0x2a, 0x46, 0x24, 0xbd, 0xad, 0x06, 0x20,
-	0xd1, 0x70, 0xdb, 0xd1, 0xe8, 0x13, 0x69, 0xf0, 0xbb, 0x28, 0xab, 0xc8, 0x04, 0xc1, 0x6f, 0x05,
-	0x32, 0x0a, 0x62, 0x26, 0x11, 0x64, 0x14, 0x28, 0x1a, 0x51, 0x3a, 0xfc, 0x01, 0x9a, 0xd8, 0xe8,
-	0x78, 0xad, 0xc7, 0xd1, 0x69, 0x71, 0x2e, 0x5e, 0x48, 0x89, 0xe3, 0xb0, 0xaf, 0x57, 0xe5, 0x5a,
-	0xa4, 0xa9, 0x3a, 0xfe, 0x41, 0x24, 0x54, 0xc2, 0x7c, 0x9a, 0x0b, 0xf6, 0xba, 0x1d, 0xc7, 0x7d,
-	0xdc, 0xec, 0x5b, 0x7e, 0x9b, 0xf5, 0xf3, 0xb3, 0xf1, 0x34, 0x27, 0x35, 0xeb, 0xa0, 0x50, 0xd3,
-	0x5c, 0x02, 0x25, 0x34, 0x69, 0xc5, 0x67, 0x4c, 0x11, 0xba, 0xb9, 0x65, 0x05, 0x5b, 0x79, 0x0c,
-	0x7d, 0x0a, 0x0c, 0x27, 0xe0, 0x3b, 0x56, 0xb0, 0xa5, 0xd2, 0x1e, 0x43, 0x84, 0x6a, 0x7a, 0x7c,
-	0x1b, 0x4d, 0xc9, 0xde, 0x64, 0x76, 0xfe, 0x1c, 0x84, 0x80, 0x52, 0x50, 0xa0, 0x2a, 0x05, 0x85,
-	0x10, 0x1a, 0x6b, 0x71, 0x49, 0xce, 0x91, 0x62, 0xfa, 0xbb, 0x78, 0xb4, 0xec, 0x4f, 0x31, 0x48,
-	0x2e, 0xa3, 0xe9, 0xc3, 0x53, 0xcd, 0x19, 0xc1, 0xf8, 0xbd, 0xc4, 0x3c, 0x23, 0x18, 0xbf, 0xa7,
-	0x4f, 0x32, 0xba, 0x05, 0xfe, 0x40, 0x2b, 0x4b, 0x37, 0xc8, 0x4f, 0x17, 0x8d, 0xf9, 0xf1, 0xd2,
-	0x2b, 0x7a, 0x1d, 0xd6, 0x82, 0x23, 0x75, 0x58, 0x0b, 0xc8, 0xbf, 0x42, 0x33, 0xed, 0xb8, 0x7d,
-	0xaa, 0x99, 0xe1, 0x4d, 0x24, 0xb2, 0xd4, 0x84, 0xae, 0x3a, 0x03, 0xa1, 0x56, 0x9e, 0x85, 0xe6,
-	0x0c, 0xb5, 0x76, 0x60, 0xeb, 0x1b, 0xce, 0xc7, 0x8c, 0x27, 0x6a, 0x23, 0x12, 0x54, 0xa2, 0x14,
-	0x12, 0x05, 0xfe, 0xf4, 0xe9, 0xb5, 0x84, 0x1b, 0x8d, 0x9d, 0xf0, 0x7d, 0x94, 0xed, 0x75, 0xac,
-	0xfe, 0xa6, 0xe7, 0x77, 0xf3, 0x67, 0xa1, 0xd8, 0xb5, 0x1c, 0xae, 0x49, 0x4d, 0xd9, 0xea, 0x5b,
-	0x25, 0x22, 0xcb, 0x4c, 0xd9, 0xab, 0xca, 0x8d, 0x00, 0x42, 0x95, 0x0e, 0x97, 0xd1, 0x74, 0xc7,
-	0x6b, 0x59, 0x9d, 0xe6, 0x66, 0xc7, 0x6a, 0x07, 0xf9, 0x7f, 0x4c, 0x42, 0x52, 0xa1, 0x3a, 0x00,
-	0x5f, 0xe6, 0xb0, 0x4a, 0x46, 0x0c, 0x11, 0xaa, 0xe9, 0xf1, 0x1d, 0x34, 0x23, 0xdb, 0x48, 0xd4,
-	0xd8, 0x3f, 0x27, 0xa1, 0x42, 0x60, 0x6f, 0xa4, 0x42, 0x56, 0xd9, 0xac, 0xde, 0x7d, 0xa2, 0xcc,
-	0x74, 0x0b, 0xfc, 0x7f, 0x7c, 0xf0, 0xe2, 0xc3, 0xa1, 0x2d, 0xa7, 0xc0, 0x2b, 0x62, 0xc4, 0x02,
-	0x48, 0x75, 0xaf, 0x94, 0x61, 0xc6, 0x82, 0x27, 0x4c, 0xd1, 0xa4, 0xe3, 0x6e, 0x5b, 0x1d, 0x27,
-	0x9a, 0xf2, 0xde, 0x79, 0x16, 0x9a, 0x88, 0x5a, 0x3b, 0x55, 0x81, 0x8a, 0x43, 0x17, 0x1e, 0xb5,
-	0x43, 0x17, 0x64, 0x7e, 0xe8, 0x6a, 0x96, 0x34, 0xb2, 0xe3, 0x9d, 0xe8, 0x7a, 0x89, 0x41, 0x3a,
-	0x0b, 0xa1, 0xa1, 0x13, 0x5d, 0x2f, 0x39, 0x44, 0x8b, 0x4e, 0x4c, 0xa0, 0x84, 0x26, 0xad, 0xde,
-	0xcd, 0xfc, 0xf2, 0x33, 0x73, 0x8c, 0x7c, 0x69, 0xa0, 0x29, 0xc5, 0x0a, 0x9c, 0x90, 0x21, 0x65,
-	0x69, 0xc8, 0x18, 0x34, 0xc0, 0x96, 0x48, 0x95, 0x68, 0x80, 0x2d, 0xc8, 0x11, 0x60, 0xfc, 0xc0,
-	0xf1, 0x36, 0x37, 0x03, 0xd6, 0x07, 0xaa, 0x4f, 0x8b, 0x03, 0x47, 0x20, 0xea, 0xc0, 0x11, 0x22,
-	0xa1, 0x12, 0xc7, 0x6f, 0x48, 0xc2, 0x4f, 0x41, 0x69, 0x5e, 0x3d, 0x9e, 0xf0, 0xa3, 0xca, 0x16,
-	0xbc, 0x7f, 0x0b, 0x4d, 0xed, 0x30, 0xeb, 0xb1, 0xd8, 0x4a, 0xd1, 0x65, 0x40, 0x85, 0x1c, 0x94,
-	0xdb, 0x28, 0x0a, 0x2a, 0x02, 0x08, 0x55, 0x3a, 0xf9, 0x1b, 0x1f, 0xa1, 0x09, 0xc1, 0xc0, 0x78,
-	0x0d, 0x65, 0x5b, 0xde, 0xc0, 0xed, 0xc7, 0xf7, 0xb0, 0x59, 0x7d, 0x80, 0x04, 0x4d, 0xe9, 0xbf,
-	0xa2, 0x9a, 0x8d, 0x4c, 0xd5, 0x1e, 0x49, 0x80, 0x4f, 0x7e, 0x52, 0x45, 0x7e, 0x6a, 0xa0, 0x49,
-	0xe9, 0x88, 0xef, 0xa8, 0x79, 0x3a, 0x53, 0x7a, 0xe7, 0xd0, 0xc1, 0xf2, 0xd5, 0x77, 0x33, 0xfd,
-	0x50, 0x91, 0xd7, 0xb4, 0x6d, 0xab, 0x33, 0x10, 0x89, 0xca, 0x88, 0x6b, 0x1a, 0x00, 0x8a, 0xa7,
-	0x41, 0x22, 0x54, 0xa0, 0xe4, 0x77, 0x06, 0x9a, 0xd1, 0xfb, 0x8e, 0x33, 0xdc, 0xc0, 0x75, 0x76,
-	0x61, 0x31, 0x89, 0x83, 0xfd, 0x9e, 0xeb, 0xec, 0x42, 0x67, 0x16, 0x9e, 0x84, 0xa6, 0xc1, 0x37,
-	0x80, 0xdb, 0xa9, 0x0d, 0xe0, 0x02, 0xa1, 0x80, 0xe1, 0x8f, 0xd0, 0xe4, 0x8e, 0xe3, 0xda, 0xde,
-	0x4e, 0x00, 0xcb, 0x98, 0xd6, 0x87, 0xed, 0x07, 0x42, 0x01, 0x91, 0x8a, 0x32, 0x52, 0x64, 0xad,
-	0xd2, 0x25, 0x65, 0x42, 0x23, 0x0d, 0xf9, 0x59, 0x0a, 0x65, 0xa3, 0x15, 0xf0, 0x13, 0xdd, 0xdb,
-	0x71, 0x99, 0xaf, 0x7f, 0xb2, 0x00, 0x1a, 0x07, 0x54, 0xce, 0xdc, 0x82, 0x9d, 0x14, 0x42, 0x68,
-	0xac, 0xe5, 0x01, 0xda, 0xbe, 0x37, 0xe8, 0xe9, 0x9f, 0x2b, 0x20, 0x00, 0xa0, 0x89, 0x00, 0x0a,
-	0x21, 0x34, 0xd6, 0xe2, 0x5b, 0x28, 0x3d, 0x70, 0x6c, 0xa8, 0xf6, 0xf1, 0xd2, 0x2b, 0xcf, 0x42,
-	0x33, 0x7d, 0x0f, 0xf6, 0x88, 0xa3, 0xa3, 0xd0, 0x9c, 0x12, 0x29, 0x71, 0x6c, 0x8d, 0x13, 0xb9,
-	0x05, 0xe5, 0x7a, 0xee, 0xdc, 0x76, 0x6c, 0x28, 0x49, 0xe9, 0xbc, 0x22, 0x9c, 0xdb, 0x9a, 0x73,
-	0x3b, 0xe9, 0xbc, 0xc2, 0x9d, 0x39, 0xf6, 0x6b, 0x03, 0x4d, 0x6b, 0x39, 0xfc, 0xf6, 0xb9, 0x58,
-	0x45, 0x67, 0x45, 0x00, 0x27, 0x68, 0xc2, 0x0f, 0x84, 0x7c, 0xc8, 0xbb, 0x30, 0x68, 0xaa, 0xc1,
-	0x0a, 0xc7, 0xd5, 0x5d, 0x58, 0x07, 0x09, 0x4d, 0xd8, 0x90, 0x1f, 0x67, 0xd0, 0x24, 0xe5, 0xf3,
-	0x44, 0xd0, 0xc7, 0x6f, 0xab, 0xaa, 0x1e, 0x2f, 0xbd, 0x7c, 0x52, 0x19, 0xc7, 0xbf, 0x31, 0xba,
-	0x18, 0xc6, 0xf3, 0x68, 0xea, 0xd4, 0xf3, 0x68, 0x34, 0x3b, 0xa6, 0x4f, 0x31, 0x3b, 0xc6, 0xf4,
-	0x93, 0xf9, 0xda, 0xf4, 0x33, 0x7e, 0x7a, 0xfa, 0x89, 0x18, 0x71, 0xe2, 0x14, 0x8c, 0x58, 0x47,
-	0x67, 0x37, 0x7d, 0xaf, 0x0b, 0x9f, 0x0f, 0x3c, 0xdf, 0xf2, 0xf7, 0x24, 0xfb, 0x03, 0x45, 0x73,
-	0xcd, 0x7a, 0xa4, 0x50, 0x14, 0x9d, 0x40, 0x09, 0x4d, 0x5a, 0x25, 0xb9, 0x2f, 0xfb, 0xf5, 0xb8,
-	0x0f, 0xdf, 0x46, 0x59, 0x31, 0x0c, 0xb8, 0x1e, 0x4c, 0xa4, 0xe3, 0xa5, 0x97, 0x78, 0x93, 0x02,
-	0x56, 0xf3, 0x54, 0x93, 0x4a, 0x59, 0xfd, 0xec, 0xc8, 0x80, 0xfc, 0xc1, 0x40, 0x59, 0xca, 0x82,
-	0x9e, 0xe7, 0x06, 0xec, 0x9b, 0x16, 0xc1, 0x02, 0xca, 0xd8, 0x56, 0xdf, 0x82, 0x12, 0x90, 0xd9,
-	0xe3, 0xb2, 0xca, 0x1e, 0x17, 0x08, 0x05, 0x0c, 0xbf, 0x8f, 0x32, 0x2d, 0xcf, 0x16, 0x9b, 0x7f,
-	0x56, 0x1f, 0x5a, 0x2b, 0xbe, 0xef, 0xf9, 0x4b, 0x9e, 0x2d, 0x27, 0x32, 0x6e, 0xa4, 0x02, 0x70,
-	0x81, 0x50, 0xc0, 0xc8, 0xef, 0x0d, 0x94, 0x2b, 0x7b, 0x3b, 0x6e, 0xc7, 0xb3, 0xec, 0x35, 0xdf,
-	0x6b, 0xf3, 0x9b, 0xfd, 0x37, 0xba, 0x16, 0x35, 0xd1, 0xe4, 0x00, 0x2e, 0x55, 0xd1, 0xc5, 0xe8,
-	0x5a, 0x72, 0x42, 0x3c, 0xfc, 0x12, 0x71, 0x03, 0x8b, 0xbf, 0xc1, 0x48, 0x67, 0x15, 0x5f, 0xc8,
-	0x84, 0x46, 0x0a, 0xf2, 0xdb, 0x34, 0x2a, 0x9c, 0x1c, 0x08, 0x77, 0xd1, 0xb4, 0xb0, 0x6c, 0x6a,
-	0x5f, 0x3b, 0xe7, 0x4f, 0xb3, 0x06, 0x98, 0x5b, 0x61, 0x5e, 0x1a, 0x28, 0x59, 0xcd, 0x4b, 0x31,
-	0x44, 0xa8, 0xa6, 0xff, 0x5a, 0x9f, 0x70, 0xb4, 0x5b, 0x4e, 0xfa, 0xdb, 0xdf, 0x72, 0x1a, 0xe8,
-	0x8c, 0x28, 0xd1, 0xe8, 0x5b, 0x5b, 0xa6, 0x98, 0x9e, 0x1f, 0x2f, 0x5d, 0xe7, 0x9c, 0xb5, 0x21,
-	0x86, 0x92, 0xe8, 0x2b, 0xdb, 0x6c, 0x5c, 0xac, 0x02, 0x8c, 0xaa, 0x2d, 0x37, 0x46, 0x13, 0xb6,
-	0x78, 0x39, 0x31, 0x04, 0x8b, 0x56, 0xff, 0x9f, 0x53, 0x0e, 0xbd, 0xda, 0x90, 0x4b, 0x26, 0x50,
-	0x66, 0xcd, 0x71, 0xdb, 0xe4, 0x16, 0x1a, 0x5f, 0xea, 0x78, 0x01, 0x30, 0x8e, 0xcf, 0xac, 0xc0,
-	0x73, 0xf5, 0x52, 0x12, 0x88, 0xda, 0x6a, 0x21, 0x12, 0x2a, 0xf1, 0x85, 0xcf, 0xd3, 0x68, 0x5a,
-	0xfb, 0x38, 0x8d, 0xbf, 0x8b, 0x2e, 0xdf, 0xad, 0x34, 0x1a, 0x8b, 0x2b, 0x95, 0xe6, 0xfa, 0xc3,
-	0xb5, 0x4a, 0x73, 0x69, 0xf5, 0x5e, 0x63, 0xbd, 0x42, 0x9b, 0x4b, 0xf5, 0xda, 0x72, 0x75, 0x25,
-	0x37, 0x56, 0xb8, 0xb2, 0x7f, 0x50, 0xcc, 0x6b, 0x1e, 0xc9, 0xcf, 0xc8, 0xff, 0x8b, 0x70, 0xc2,
-	0xbd, 0x5a, 0x2b, 0x57, 0xbe, 0x97, 0x33, 0x0a, 0xe7, 0xf7, 0x0f, 0x8a, 0x39, 0xcd, 0x4b, 0x7c,
-	0x9d, 0xf8, 0x0e, 0x7a, 0xf1, 0xa8, 0x75, 0xf3, 0xde, 0x5a, 0x79, 0x71, 0xbd, 0x92, 0x4b, 0x15,
-	0x0a, 0xfb, 0x07, 0xc5, 0x8b, 0x87, 0x9d, 0x64, 0x09, 0xbe, 0x8e, 0xce, 0x27, 0x5c, 0x69, 0xe5,
-	0xa3, 0x7b, 0x95, 0xc6, 0x7a, 0x2e, 0x5d, 0xb8, 0xb8, 0x7f, 0x50, 0xc4, 0x9a, 0x57, 0x74, 0x4c,
-	0xdc, 0x44, 0x17, 0x0e, 0x79, 0x34, 0xd6, 0xea, 0xb5, 0x46, 0x25, 0x97, 0x29, 0x5c, 0xda, 0x3f,
-	0x28, 0x9e, 0x4b, 0xb8, 0x48, 0x56, 0x59, 0x42, 0x73, 0x09, 0x9f, 0x72, 0xfd, 0x41, 0x6d, 0xb5,
-	0xbe, 0x58, 0x6e, 0xae, 0xd1, 0xfa, 0x0a, 0xad, 0x34, 0x1a, 0xb9, 0xf1, 0x82, 0xb9, 0x7f, 0x50,
-	0xbc, 0xac, 0x39, 0x1f, 0xe9, 0xf0, 0x05, 0x34, 0x9b, 0x08, 0xb2, 0x56, 0xad, 0xad, 0xe4, 0x26,
-	0x0a, 0xe7, 0xf6, 0x0f, 0x8a, 0x2f, 0x68, 0x7e, 0x7c, 0x2f, 0x8f, 0xe4, 0x6f, 0x69, 0xb5, 0xde,
-	0xa8, 0xe4, 0x26, 0x8f, 0xe4, 0x0f, 0x36, 0x7c, 0xe1, 0x37, 0x06, 0xc2, 0x47, 0xff, 0x0f, 0xc0,
-	0xef, 0xa0, 0x7c, 0x14, 0x64, 0xa9, 0x7e, 0x77, 0x8d, 0xaf, 0xb3, 0x5a, 0xaf, 0x35, 0x6b, 0xf5,
-	0x5a, 0x25, 0x37, 0x96, 0xc8, 0xaa, 0xe6, 0x55, 0xf3, 0x5c, 0x86, 0xeb, 0xe8, 0xd2, 0x71, 0x9e,
-	0xab, 0x8f, 0xde, 0xca, 0x19, 0x85, 0x9b, 0xfb, 0x07, 0xc5, 0x0b, 0x47, 0x1d, 0x57, 0x1f, 0xbd,
-	0xf5, 0xc5, 0xcf, 0x5f, 0x3e, 0x5e, 0xb1, 0xc0, 0xc7, 0x08, 0x7d, 0x69, 0x6f, 0xa0, 0xf3, 0x7a,
-	0xe0, 0xbb, 0x95, 0xf5, 0xc5, 0xf2, 0xe2, 0xfa, 0x62, 0x6e, 0x4c, 0xec, 0x81, 0x66, 0x7a, 0x97,
-	0xf5, 0x2d, 0xa0, 0xdd, 0x57, 0xd1, 0x6c, 0xe2, 0x57, 0x54, 0xee, 0x57, 0x68, 0x54, 0x51, 0xfa,
-	0xfa, 0xd9, 0x36, 0xf3, 0xf1, 0x6b, 0x08, 0xeb, 0xc6, 0x8b, 0xab, 0x0f, 0x16, 0x1f, 0x36, 0x72,
-	0xa9, 0xc2, 0x85, 0xfd, 0x83, 0xe2, 0xac, 0x66, 0xbd, 0xd8, 0xd9, 0xb1, 0xf6, 0x82, 0x85, 0x3f,
-	0xa5, 0xd0, 0x8c, 0x7e, 0xa5, 0xc6, 0xaf, 0xa1, 0x73, 0xcb, 0xd5, 0x55, 0x5e, 0x89, 0xcb, 0x75,
-	0xb1, 0x03, 0x5c, 0xcc, 0x8d, 0x89, 0xd7, 0xe9, 0xa6, 0xfc, 0x19, 0xff, 0x3f, 0xca, 0x1f, 0x32,
-	0x2f, 0x57, 0x69, 0x65, 0x69, 0xbd, 0x4e, 0x1f, 0xe6, 0x8c, 0xc2, 0x8b, 0x3c, 0x61, 0xba, 0x4f,
-	0xd9, 0xf1, 0x81, 0x82, 0xf6, 0xf0, 0x6d, 0x74, 0xf9, 0x90, 0x63, 0xe3, 0xe1, 0xdd, 0xd5, 0x6a,
-	0xed, 0x43, 0xf1, 0xbe, 0x54, 0xe1, 0xea, 0xfe, 0x41, 0xf1, 0x92, 0xee, 0xdb, 0x10, 0x5f, 0x29,
-	0x38, 0x94, 0x35, 0xf0, 0x1d, 0x54, 0x3c, 0xc1, 0x3f, 0x5e, 0x40, 0xba, 0x40, 0xf6, 0x0f, 0x8a,
-	0x57, 0x8e, 0x09, 0xa2, 0xd6, 0x91, 0x35, 0xf0, 0x9b, 0xe8, 0xe2, 0xf1, 0x91, 0xa2, 0xbe, 0x38,
-	0xc6, 0x7f, 0xe1, 0xaf, 0x06, 0x9a, 0x52, 0xa7, 0x1e, 0x4f, 0x5a, 0x85, 0xd2, 0x3a, 0x27, 0x89,
-	0x72, 0xa5, 0x59, 0xab, 0x37, 0x41, 0x8a, 0x92, 0xa6, 0xec, 0x6a, 0x1e, 0x3c, 0xf2, 0x1a, 0xd7,
-	0xcc, 0x57, 0x2a, 0xb5, 0x0a, 0xad, 0x2e, 0x45, 0x3b, 0xaa, 0xac, 0x57, 0x98, 0xcb, 0x7c, 0xa7,
-	0x85, 0xdf, 0x42, 0x97, 0x92, 0xc1, 0x1b, 0xf7, 0x96, 0xee, 0x44, 0x59, 0x82, 0x05, 0x6a, 0x2f,
-	0x68, 0x0c, 0x5a, 0x5b, 0xb0, 0x31, 0x6f, 0x27, 0xbc, 0xaa, 0xb5, 0xfb, 0x8b, 0xab, 0xd5, 0xb2,
-	0xf0, 0x4a, 0x17, 0xf2, 0xfb, 0x07, 0xc5, 0xf3, 0xca, 0x4b, 0x5e, 0x64, 0xb9, 0xdb, 0xc2, 0x17,
-	0x06, 0x9a, 0xfb, 0xea, 0xc3, 0x0b, 0x3f, 0x40, 0xaf, 0x40, 0xbe, 0x8e, 0x50, 0x81, 0xe4, 0x2d,
-	0x91, 0xc3, 0xc5, 0xb5, 0xb5, 0x4a, 0xad, 0x9c, 0x1b, 0x2b, 0xcc, 0xef, 0x1f, 0x14, 0xaf, 0x7d,
-	0x75, 0xc8, 0xc5, 0x5e, 0x8f, 0xb9, 0xf6, 0x29, 0x03, 0x2f, 0xd7, 0xe9, 0x4a, 0x65, 0x3d, 0x67,
-	0x9c, 0x26, 0xf0, 0xb2, 0xe7, 0xb7, 0x59, 0xbf, 0x74, 0xf7, 0xc9, 0x97, 0x73, 0x63, 0x4f, 0xbf,
-	0x9c, 0x1b, 0x7b, 0xf2, 0x6c, 0xce, 0x78, 0xfa, 0x6c, 0xce, 0xf8, 0xc5, 0xf3, 0xb9, 0xb1, 0xcf,
-	0x9e, 0xcf, 0x19, 0x4f, 0x9f, 0xcf, 0x8d, 0xfd, 0xed, 0xf9, 0xdc, 0xd8, 0xa3, 0x57, 0xdb, 0x4e,
-	0x7f, 0x6b, 0xb0, 0x71, 0xbd, 0xe5, 0x75, 0x6f, 0x04, 0x7b, 0x6e, 0xab, 0xbf, 0xe5, 0xb8, 0x6d,
-	0xed, 0x49, 0xff, 0x5f, 0x78, 0x63, 0x02, 0x9e, 0xde, 0xfc, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff,
-	0xc7, 0x92, 0x60, 0x1e, 0x2e, 0x1e, 0x00, 0x00,
+	// 3122 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5a, 0x4f, 0x6c, 0x1b, 0xc7,
+	0xb9, 0x17, 0xc5, 0x3f, 0xa2, 0x46, 0xb2, 0x4d, 0x8d, 0xff, 0x31, 0xb4, 0xad, 0xe5, 0x9b, 0x38,
+	0xef, 0x29, 0xca, 0x8b, 0x9d, 0x28, 0x7f, 0x5e, 0x5e, 0x9c, 0xe7, 0x40, 0x14, 0x29, 0x99, 0xb1,
+	0x4c, 0x2a, 0x43, 0xd9, 0x8e, 0x8d, 0x57, 0x10, 0x2b, 0xee, 0x88, 0x5a, 0x98, 0xdc, 0x65, 0x77,
+	0x49, 0xfd, 0x09, 0x7a, 0x69, 0x03, 0x14, 0x81, 0x50, 0x14, 0x45, 0x4e, 0x45, 0x51, 0xa1, 0x41,
+	0x2f, 0xbd, 0x15, 0xe8, 0xa1, 0x97, 0x9c, 0x7a, 0xf4, 0xd1, 0x08, 0x50, 0xa0, 0xe8, 0x61, 0x81,
+	0xd8, 0x97, 0x96, 0x47, 0x1e, 0x7b, 0x2a, 0xe6, 0x9b, 0xd9, 0xd9, 0x59, 0xc9, 0x4a, 0xe5, 0xe4,
+	0xd0, 0x93, 0xf9, 0xfd, 0xbe, 0xdf, 0xf7, 0xed, 0xec, 0xcc, 0xf7, 0x6f, 0x56, 0x46, 0x17, 0x3a,
+	0xf6, 0xc6, 0xf5, 0x9e, 0xe7, 0xf6, 0xdd, 0x96, 0xdb, 0xb9, 0xbe, 0xc1, 0x7a, 0xd7, 0x40, 0xc0,
+	0xd9, 0x10, 0x2b, 0x4c, 0xb2, 0xdd, 0xbe, 0x00, 0x0b, 0x2f, 0x7b, 0xac, 0xe7, 0xfa, 0x82, 0xbe,
+	0x31, 0xd8, 0xbc, 0xde, 0x76, 0xdb, 0x2e, 0x08, 0xf0, 0x4b, 0x90, 0xc8, 0xd3, 0x04, 0x4a, 0xdf,
+	0x62, 0x9d, 0x8e, 0x8b, 0x97, 0xd0, 0x94, 0xc5, 0xb6, 0xed, 0x16, 0x6b, 0x3a, 0x66, 0x97, 0xe5,
+	0x13, 0xc5, 0xc4, 0xdc, 0x64, 0x89, 0x0c, 0x03, 0x03, 0x09, 0xb8, 0x66, 0x76, 0xd9, 0x28, 0x30,
+	0x72, 0xbb, 0xdd, 0xce, 0xfb, 0x24, 0x82, 0x08, 0xd5, 0xf4, 0xdc, 0x49, 0xab, 0x63, 0x33, 0xa7,
+	0x2f, 0x9c, 0x8c, 0x47, 0x4e, 0x04, 0x1c, 0x73, 0x12, 0x41, 0x84, 0x6a, 0x7a, 0x5c, 0x47, 0xa7,
+	0xa5, 0x93, 0x6d, 0xe6, 0xf9, 0xb6, 0xeb, 0xe4, 0x93, 0xe0, 0x67, 0x6e, 0x18, 0x18, 0xa7, 0x84,
+	0xe6, 0x9e, 0x50, 0x8c, 0x02, 0xe3, 0xac, 0xe6, 0x4a, 0xa2, 0x84, 0xc6, 0x59, 0xe4, 0x0f, 0x09,
+	0x94, 0xb9, 0xc5, 0x4c, 0x8b, 0x79, 0x78, 0x11, 0xa5, 0xfa, 0x7b, 0x3d, 0xf1, 0x7a, 0xa7, 0x17,
+	0xce, 0x5f, 0x0b, 0x37, 0xee, 0xda, 0x1d, 0xe6, 0xfb, 0x66, 0x9b, 0xad, 0xef, 0xf5, 0x58, 0xe9,
+	0xc2, 0x30, 0x30, 0x80, 0x36, 0x0a, 0x0c, 0x04, 0xfe, 0xb9, 0x40, 0x28, 0x60, 0xd8, 0x42, 0x53,
+	0x2d, 0xb7, 0xdb, 0xf3, 0x98, 0x0f, 0x6b, 0x1b, 0x07, 0x4f, 0x97, 0x8f, 0x78, 0x5a, 0x8a, 0x38,
+	0xa5, 0xab, 0xc3, 0xc0, 0xd0, 0x8d, 0x46, 0x81, 0x31, 0x23, 0xd6, 0x1d, 0x61, 0x84, 0xea, 0x0c,
+	0xf2, 0xff, 0xe8, 0xd4, 0x52, 0x67, 0xe0, 0xf7, 0x99, 0xb7, 0xe4, 0x3a, 0x9b, 0x76, 0x1b, 0xdf,
+	0x46, 0x13, 0x9b, 0x6e, 0xc7, 0x62, 0x9e, 0x9f, 0x4f, 0x14, 0x93, 0x73, 0x53, 0x0b, 0xb9, 0xe8,
+	0x91, 0xcb, 0xa0, 0x28, 0x19, 0x8f, 0x03, 0x63, 0x6c, 0x18, 0x18, 0x21, 0x71, 0x14, 0x18, 0xd3,
+	0xf0, 0x18, 0x21, 0x13, 0x1a, 0x2a, 0xc8, 0x57, 0x29, 0x94, 0x11, 0x46, 0xf8, 0x1a, 0x1a, 0xb7,
+	0x2d, 0x79, 0xdc, 0xb3, 0x4f, 0x03, 0x63, 0xbc, 0x5a, 0x1e, 0x06, 0xc6, 0xb8, 0x6d, 0x8d, 0x02,
+	0x23, 0x0b, 0xd6, 0xb6, 0x45, 0xbe, 0x78, 0x72, 0x75, 0xbc, 0x5a, 0xa6, 0xe3, 0xb6, 0x85, 0xaf,
+	0xa1, 0x74, 0xc7, 0xdc, 0x60, 0x1d, 0x79, 0xb8, 0xf9, 0x61, 0x60, 0x08, 0x60, 0x14, 0x18, 0x53,
+	0xc0, 0x07, 0x89, 0x50, 0x81, 0xe2, 0x1b, 0x68, 0xd2, 0x63, 0xa6, 0xd5, 0x74, 0x9d, 0xce, 0x1e,
+	0x1c, 0x64, 0xb6, 0x34, 0x3b, 0x0c, 0x8c, 0x2c, 0x07, 0xeb, 0x4e, 0x67, 0x6f, 0x14, 0x18, 0xa7,
+	0xc1, 0x2c, 0x04, 0x08, 0x55, 0x3a, 0xdc, 0x44, 0xd8, 0x6e, 0x3b, 0xae, 0xc7, 0x9a, 0x3d, 0xe6,
+	0x75, 0x6d, 0xd8, 0x1a, 0x3f, 0x9f, 0x02, 0x2f, 0x6f, 0x0c, 0x03, 0x63, 0x46, 0x68, 0xd7, 0x22,
+	0xe5, 0x28, 0x30, 0x2e, 0x8a, 0x55, 0x1f, 0xd6, 0x10, 0x7a, 0x94, 0x8d, 0x6f, 0xa3, 0x53, 0xf2,
+	0x01, 0x16, 0xeb, 0xb0, 0x3e, 0xcb, 0xa7, 0xc1, 0xf7, 0x7f, 0x0e, 0x03, 0x63, 0x5a, 0x28, 0xca,
+	0x80, 0x8f, 0x02, 0x03, 0x6b, 0x6e, 0x05, 0x48, 0x68, 0x8c, 0x83, 0x2d, 0x74, 0xce, 0xb2, 0x7d,
+	0x73, 0xa3, 0xc3, 0x9a, 0x7d, 0xd6, 0xed, 0x35, 0x6d, 0xc7, 0x62, 0xbb, 0xcc, 0xcf, 0x67, 0xc0,
+	0xe7, 0xc2, 0x30, 0x30, 0xb0, 0xd4, 0xaf, 0xb3, 0x6e, 0xaf, 0x2a, 0xb4, 0xa3, 0xc0, 0xc8, 0x8b,
+	0x9c, 0x3a, 0xa2, 0x22, 0xf4, 0x39, 0x7c, 0xbc, 0x80, 0x32, 0x3d, 0x73, 0xe0, 0x33, 0x2b, 0x3f,
+	0x01, 0x7e, 0x0b, 0xc3, 0xc0, 0x90, 0x88, 0x3a, 0x70, 0x21, 0x12, 0x2a, 0x71, 0x1e, 0x3c, 0x22,
+	0x4b, 0xfd, 0x7c, 0xee, 0x70, 0xf0, 0x94, 0x41, 0x11, 0x05, 0x8f, 0x24, 0x2a, 0x5f, 0x42, 0x26,
+	0x34, 0x54, 0x90, 0x3f, 0x65, 0x50, 0x46, 0x18, 0xe1, 0x92, 0x0a, 0x9e, 0xe9, 0xd2, 0x02, 0x77,
+	0xf0, 0xd7, 0xc0, 0xc8, 0x0a, 0x5d, 0xb5, 0x7c, 0x5c, 0x30, 0x7d, 0xfe, 0xe4, 0x6a, 0x42, 0x0b,
+	0xa8, 0x79, 0x94, 0xd2, 0x8a, 0x05, 0xe4, 0x9e, 0x23, 0xca, 0x84, 0xc8, 0x3d, 0x07, 0x0a, 0x04,
+	0x60, 0xf8, 0x03, 0x34, 0x69, 0x5a, 0x16, 0xcf, 0x11, 0xe6, 0xe7, 0x93, 0xc5, 0x24, 0x8f, 0xd9,
+	0x61, 0x60, 0x44, 0xe0, 0x28, 0x30, 0x4e, 0x81, 0x95, 0x44, 0x08, 0x8d, 0x74, 0xf8, 0x07, 0xf1,
+	0xcc, 0x4d, 0x1d, 0xae, 0x01, 0xdf, 0x2f, 0x65, 0x79, 0xa4, 0xb7, 0x98, 0x27, 0x4b, 0x5f, 0x5a,
+	0x24, 0x14, 0x8f, 0x74, 0x0e, 0xca, 0xc2, 0x27, 0x22, 0x3d, 0x04, 0x08, 0x55, 0x3a, 0xbc, 0x82,
+	0xa6, 0xbb, 0xe6, 0x6e, 0xd3, 0x67, 0x3f, 0x1c, 0x30, 0xa7, 0xc5, 0x20, 0x66, 0x92, 0x62, 0x15,
+	0x5d, 0x73, 0xb7, 0x21, 0x61, 0xb5, 0x0a, 0x0d, 0x23, 0x54, 0x67, 0xe0, 0x12, 0x42, 0xb6, 0xd3,
+	0xf7, 0x5c, 0x6b, 0xd0, 0x62, 0x9e, 0x0c, 0x11, 0xa8, 0xc0, 0x11, 0xaa, 0x2a, 0x70, 0x04, 0x11,
+	0xaa, 0xe9, 0x71, 0x1b, 0x65, 0x21, 0x76, 0x9b, 0xb6, 0x95, 0xcf, 0x16, 0x13, 0x73, 0xa9, 0xd2,
+	0xaa, 0x3c, 0xdc, 0x09, 0x88, 0x42, 0x38, 0xdb, 0xf0, 0x27, 0x8f, 0x19, 0x60, 0x57, 0x2d, 0xb5,
+	0xfb, 0x52, 0xe6, 0x75, 0x23, 0xa4, 0xfd, 0x2a, 0xfa, 0x49, 0x43, 0x3e, 0xfe, 0x11, 0x2a, 0xf8,
+	0x8f, 0x6c, 0x9e, 0x29, 0xe2, 0xd9, 0x7d, 0xdb, 0x75, 0x9a, 0x1e, 0xeb, 0xba, 0xdb, 0x66, 0xc7,
+	0xcf, 0x4f, 0xc2, 0xe2, 0x6f, 0x0e, 0x03, 0x23, 0xcf, 0x59, 0x55, 0x8d, 0x44, 0x25, 0x67, 0x14,
+	0x18, 0xb3, 0xf0, 0xc4, 0xe3, 0x08, 0x84, 0x1e, 0x6b, 0x8b, 0x77, 0xd1, 0x4b, 0xcc, 0x69, 0x79,
+	0x7b, 0x3d, 0x78, 0x6c, 0xcf, 0xf4, 0xfd, 0x1d, 0xd7, 0xb3, 0x9a, 0x7d, 0xf7, 0x11, 0x73, 0xf2,
+	0x08, 0x82, 0xfa, 0x83, 0x61, 0x60, 0x5c, 0x8c, 0x48, 0x6b, 0x92, 0xb3, 0xce, 0x29, 0xa3, 0xc0,
+	0xb8, 0x02, 0xcf, 0x3e, 0x46, 0x4f, 0xe8, 0x71, 0x96, 0xe4, 0x27, 0x09, 0x94, 0x86, 0xcd, 0xe0,
+	0xd9, 0x2c, 0x8a, 0xb2, 0x2c, 0xc1, 0x90, 0xcd, 0x02, 0x39, 0x52, 0xbe, 0x25, 0x8e, 0x2b, 0x28,
+	0xbd, 0x69, 0x77, 0x98, 0x9f, 0x1f, 0x87, 0x5c, 0xc6, 0x5a, 0x23, 0xb0, 0x3b, 0xac, 0xea, 0x6c,
+	0xba, 0xa5, 0x4b, 0x32, 0x9b, 0x05, 0x51, 0xe5, 0x12, 0x97, 0x08, 0x15, 0x20, 0xf9, 0x3c, 0x81,
+	0xa6, 0x60, 0x11, 0x77, 0x7b, 0x96, 0xd9, 0x67, 0xff, 0xce, 0xa5, 0xfc, 0x6c, 0x1a, 0x65, 0x43,
+	0x03, 0x55, 0x10, 0x12, 0x27, 0x28, 0x08, 0xf3, 0x28, 0xe5, 0xdb, 0x9f, 0x32, 0x68, 0x2c, 0x49,
+	0xc1, 0xe5, 0xb2, 0xe2, 0x72, 0x81, 0x50, 0xc0, 0xf0, 0x87, 0x08, 0x75, 0x5d, 0xcb, 0xde, 0xb4,
+	0x99, 0xd5, 0xf4, 0x21, 0x41, 0x93, 0xa5, 0x22, 0xaf, 0x1e, 0x21, 0xda, 0x18, 0x05, 0xc6, 0x19,
+	0x91, 0x5e, 0x21, 0x42, 0x68, 0xa4, 0xe5, 0xf5, 0x43, 0x39, 0xd8, 0xd8, 0xcb, 0x4f, 0x43, 0x66,
+	0x7c, 0x10, 0x66, 0x46, 0x63, 0xcb, 0xf5, 0xfa, 0x90, 0x0e, 0xea, 0x31, 0xa5, 0x3d, 0x95, 0x6a,
+	0x11, 0x44, 0x78, 0x26, 0x48, 0x32, 0xd5, 0xa8, 0x78, 0x15, 0x4d, 0x84, 0x03, 0x0f, 0x8f, 0xfc,
+	0x58, 0x91, 0xbe, 0xc7, 0x5a, 0x7d, 0xd7, 0x2b, 0x15, 0xc3, 0x22, 0xbd, 0xad, 0x06, 0x20, 0x91,
+	0x70, 0xdb, 0xe1, 0xe8, 0x13, 0x6a, 0xf0, 0xfb, 0x28, 0xab, 0x8a, 0x09, 0x82, 0x77, 0x85, 0x62,
+	0xe4, 0x47, 0x95, 0x44, 0x14, 0x23, 0x5f, 0x95, 0x11, 0xa5, 0xc3, 0x1f, 0xa1, 0xcc, 0x46, 0xc7,
+	0x6d, 0x3d, 0x0a, 0xbb, 0xc5, 0xd9, 0x68, 0x21, 0x25, 0x8e, 0xc3, 0xb9, 0x5e, 0x91, 0x6b, 0x91,
+	0x54, 0xd5, 0xfe, 0x41, 0x24, 0x54, 0xc2, 0x7c, 0x9a, 0xf3, 0xf7, 0xba, 0x1d, 0xdb, 0x79, 0xd4,
+	0xec, 0x9b, 0x5e, 0x9b, 0xf5, 0xf3, 0x33, 0xd1, 0x34, 0x27, 0x35, 0xeb, 0xa0, 0x50, 0xd3, 0x5c,
+	0x0c, 0x25, 0x34, 0xce, 0xe2, 0x33, 0xa6, 0x70, 0xdd, 0xdc, 0x32, 0xfd, 0xad, 0x3c, 0x86, 0x3c,
+	0x85, 0x0a, 0x27, 0xe0, 0x5b, 0xa6, 0xbf, 0xa5, 0xb6, 0x3d, 0x82, 0x08, 0xd5, 0xf4, 0xf8, 0x26,
+	0x9a, 0x94, 0xb9, 0xc9, 0xac, 0xfc, 0x59, 0x70, 0x01, 0xa1, 0xa0, 0x40, 0x15, 0x0a, 0x0a, 0x21,
+	0x34, 0xd2, 0xe2, 0x92, 0x9c, 0x23, 0xc5, 0xf4, 0x77, 0xe1, 0x68, 0xd8, 0x9f, 0x60, 0x90, 0x5c,
+	0x46, 0x53, 0x87, 0xa7, 0x9a, 0x53, 0xa2, 0xe2, 0xf7, 0x62, 0xf3, 0x8c, 0xa8, 0xf8, 0x3d, 0x7d,
+	0x92, 0xd1, 0x19, 0xf8, 0x23, 0x2d, 0x2c, 0x1d, 0x3f, 0x3f, 0x55, 0x4c, 0xcc, 0xa5, 0x4b, 0xaf,
+	0xea, 0x71, 0x58, 0xf3, 0x8f, 0xc4, 0x61, 0xcd, 0x27, 0xff, 0x08, 0x8c, 0xa4, 0xed, 0xf4, 0xa9,
+	0x46, 0xc3, 0x9b, 0x48, 0xec, 0x52, 0x13, 0xb2, 0xea, 0x14, 0xb8, 0x5a, 0x79, 0x1a, 0x18, 0xd3,
+	0xd4, 0xdc, 0x81, 0xa3, 0x6f, 0xd8, 0x9f, 0x32, 0xbe, 0x51, 0x1b, 0xa1, 0xa0, 0x36, 0x4a, 0x21,
+	0xa1, 0xe3, 0x2f, 0x9e, 0x5c, 0x8d, 0x99, 0xd1, 0xc8, 0x08, 0xdf, 0x43, 0xd9, 0x5e, 0xc7, 0xec,
+	0x6f, 0xba, 0x5e, 0x37, 0x7f, 0x1a, 0x82, 0x5d, 0xdb, 0xc3, 0x35, 0xa9, 0x29, 0x9b, 0x7d, 0xb3,
+	0x44, 0x64, 0x98, 0x29, 0xbe, 0x8a, 0xdc, 0x10, 0x20, 0x54, 0xe9, 0x70, 0x19, 0x4d, 0x75, 0xdc,
+	0x96, 0xd9, 0x69, 0x6e, 0x76, 0xcc, 0xb6, 0x9f, 0xff, 0xdb, 0x04, 0x6c, 0x2a, 0x44, 0x07, 0xe0,
+	0xcb, 0x1c, 0x56, 0x9b, 0x11, 0x41, 0x84, 0x6a, 0x7a, 0x7c, 0x0b, 0x4d, 0xcb, 0x34, 0x12, 0x31,
+	0xf6, 0xf7, 0x09, 0x88, 0x10, 0x38, 0x1b, 0xa9, 0x90, 0x51, 0x36, 0xa3, 0x67, 0x9f, 0x08, 0x33,
+	0x9d, 0x81, 0x3f, 0x46, 0x67, 0x6c, 0xc7, 0xb5, 0x58, 0xb3, 0xb5, 0x65, 0x3a, 0x6d, 0xc6, 0xcf,
+	0x67, 0x38, 0x01, 0xd9, 0x08, 0xf1, 0x0f, 0xba, 0x25, 0x50, 0xc1, 0x19, 0x9d, 0x95, 0xdd, 0x53,
+	0x43, 0x09, 0x8d, 0xb3, 0xf0, 0xbb, 0x7c, 0x96, 0xe3, 0xf3, 0xa6, 0x25, 0x07, 0xcb, 0xcb, 0x62,
+	0x6a, 0x03, 0x48, 0x15, 0x04, 0x29, 0xc3, 0xd8, 0x06, 0xbf, 0x30, 0x45, 0x13, 0xb6, 0xb3, 0x6d,
+	0x76, 0xec, 0x70, 0x70, 0x7c, 0xef, 0x69, 0x60, 0x20, 0x6a, 0xee, 0x54, 0x05, 0x2a, 0xfa, 0x38,
+	0xfc, 0xd4, 0xfa, 0x38, 0xc8, 0xbc, 0x8f, 0x6b, 0x4c, 0x1a, 0xf2, 0x78, 0x72, 0x3b, 0x6e, 0x6c,
+	0x36, 0xcf, 0x82, 0x6b, 0x78, 0x39, 0xc7, 0x8d, 0xcf, 0xe5, 0xe2, 0xe5, 0x62, 0x28, 0xa1, 0x71,
+	0xd6, 0xfb, 0xa9, 0x5f, 0x7e, 0x69, 0x8c, 0x91, 0x6f, 0x12, 0x68, 0x52, 0x15, 0x1a, 0x5e, 0xe3,
+	0xe1, 0x14, 0x92, 0x70, 0x08, 0x90, 0x53, 0x5b, 0x62, 0xf7, 0x45, 0x4e, 0x6d, 0xc1, 0xb6, 0x03,
+	0xc6, 0x7b, 0x98, 0xbb, 0xb9, 0xe9, 0xb3, 0x3e, 0x74, 0x8f, 0xa4, 0xe8, 0x61, 0x02, 0x51, 0x3d,
+	0x4c, 0x88, 0x84, 0x4a, 0x1c, 0xbf, 0x29, 0x7b, 0xc8, 0x38, 0x44, 0xfb, 0x95, 0xe7, 0xf7, 0x90,
+	0x30, 0x59, 0x44, 0x2b, 0xb9, 0x81, 0x26, 0x77, 0x98, 0xf9, 0x48, 0x44, 0x87, 0x48, 0x5c, 0xa8,
+	0xae, 0x1c, 0x94, 0x91, 0x21, 0x62, 0x34, 0x04, 0x08, 0x55, 0x3a, 0xf9, 0x8e, 0x0f, 0x51, 0x46,
+	0x14, 0x75, 0xbc, 0x86, 0xb2, 0x2d, 0x77, 0xe0, 0xf4, 0xa3, 0xab, 0xdd, 0x8c, 0x3e, 0x93, 0x82,
+	0xa6, 0xf4, 0x1f, 0x61, 0x1a, 0x84, 0x54, 0x75, 0x46, 0x12, 0xe0, 0xc3, 0xa4, 0x54, 0x91, 0xcf,
+	0x12, 0x68, 0x42, 0x1a, 0xe2, 0x5b, 0x6a, 0x44, 0x4f, 0x95, 0xde, 0x3b, 0xd4, 0xab, 0xbe, 0xfd,
+	0xba, 0xa7, 0xf7, 0x29, 0x79, 0xf3, 0xdb, 0x36, 0x3b, 0x03, 0xb1, 0x51, 0x29, 0x71, 0xf3, 0x03,
+	0x40, 0x95, 0x7e, 0x90, 0x08, 0x15, 0x28, 0xf9, 0x2c, 0x85, 0xa6, 0xf5, 0x54, 0xe6, 0x45, 0x73,
+	0xe0, 0xd8, 0xbb, 0xb0, 0x98, 0xd8, 0xac, 0x70, 0xd7, 0xb1, 0x77, 0x21, 0xd9, 0x0b, 0x8f, 0x03,
+	0x23, 0xc1, 0x0f, 0x80, 0xf3, 0xd4, 0x01, 0x70, 0x81, 0x50, 0xc0, 0xf0, 0xc7, 0x68, 0x62, 0xc7,
+	0x76, 0x2c, 0x77, 0xc7, 0x87, 0x65, 0x4c, 0xe9, 0xf3, 0xfb, 0x7d, 0xa1, 0x00, 0x4f, 0x45, 0xe9,
+	0x29, 0x64, 0xab, 0xed, 0x92, 0x32, 0xa1, 0xa1, 0x06, 0xaf, 0xa0, 0x74, 0xc7, 0x76, 0x06, 0xbb,
+	0x10, 0x60, 0xb1, 0x66, 0xf7, 0x89, 0xd9, 0xef, 0x7b, 0xe0, 0xee, 0xb2, 0x74, 0x27, 0x98, 0xd1,
+	0x55, 0x97, 0x4b, 0xfc, 0xaa, 0xcb, 0xff, 0xc5, 0xb7, 0x51, 0xc6, 0x32, 0xbd, 0x1d, 0x5b, 0x5c,
+	0x2d, 0x8e, 0xf1, 0x34, 0x2b, 0x3d, 0x49, 0x6a, 0x74, 0xcd, 0x02, 0x91, 0x50, 0x89, 0x63, 0x86,
+	0x26, 0x36, 0x3d, 0xc6, 0x36, 0x7c, 0x0b, 0x46, 0x95, 0x63, 0xbc, 0xbd, 0xcb, 0xbd, 0xf1, 0x61,
+	0x7c, 0xd9, 0x63, 0xac, 0xd4, 0x80, 0x61, 0x5c, 0x9a, 0xa9, 0x37, 0x96, 0x32, 0x0c, 0xe3, 0x92,
+	0x46, 0x43, 0x12, 0x6e, 0xa2, 0x8c, 0xc3, 0xfa, 0xfc, 0x29, 0x99, 0xe3, 0x9f, 0xb2, 0x20, 0x9f,
+	0x92, 0xa9, 0xb1, 0xbe, 0x78, 0x88, 0x34, 0x52, 0xab, 0x17, 0x22, 0x7f, 0x84, 0xe4, 0x50, 0xc9,
+	0x20, 0x3f, 0x1d, 0x47, 0xd9, 0xf0, 0x7c, 0xf9, 0x08, 0xe6, 0xee, 0x38, 0xcc, 0xd3, 0xbf, 0x31,
+	0x41, 0xdf, 0x05, 0x54, 0x5e, 0x92, 0x44, 0x3b, 0x51, 0x08, 0xa1, 0x91, 0x96, 0x3b, 0x68, 0x7b,
+	0xee, 0xa0, 0xa7, 0x7f, 0x5f, 0x02, 0x07, 0x80, 0xc6, 0x1c, 0x28, 0x84, 0xd0, 0x48, 0x8b, 0x6f,
+	0xa0, 0xe4, 0xc0, 0xb6, 0xe0, 0xa8, 0xd3, 0xa5, 0x57, 0x9f, 0x06, 0x46, 0xf2, 0x2e, 0x64, 0x00,
+	0x47, 0x47, 0x81, 0x31, 0x29, 0x02, 0xce, 0xb6, 0xb4, 0x26, 0xc6, 0x19, 0x94, 0xeb, 0xb9, 0x71,
+	0xdb, 0xb6, 0xe0, 0x74, 0xa5, 0xf1, 0x8a, 0x30, 0x6e, 0x6b, 0xc6, 0xed, 0xb8, 0xf1, 0x0a, 0x37,
+	0xe6, 0xd8, 0xaf, 0x13, 0x68, 0x4a, 0x8b, 0xd0, 0xef, 0xbf, 0x17, 0xab, 0xe8, 0xb4, 0x70, 0x60,
+	0xfb, 0x4d, 0x78, 0x41, 0xd8, 0x0f, 0xf9, 0xf1, 0x02, 0x34, 0x55, 0x7f, 0x85, 0xe3, 0xea, 0xe3,
+	0x85, 0x0e, 0x12, 0x1a, 0xe3, 0x90, 0x06, 0x9a, 0x54, 0x07, 0x8e, 0x97, 0x51, 0x66, 0x97, 0x0b,
+	0x61, 0x41, 0x3a, 0x73, 0x28, 0x2a, 0xa2, 0xe1, 0x4f, 0xd0, 0x54, 0x42, 0x80, 0x48, 0xa8, 0x84,
+	0x49, 0x0b, 0xa5, 0x81, 0xff, 0x42, 0x33, 0x7d, 0xac, 0xce, 0x4c, 0xff, 0xeb, 0x3a, 0xf3, 0xe3,
+	0x14, 0x9a, 0xa0, 0x7c, 0x74, 0xf5, 0xfb, 0xf8, 0x1d, 0x55, 0xed, 0xd2, 0xa5, 0x57, 0x8e, 0x2b,
+	0x6f, 0xd1, 0xe9, 0x84, 0xdf, 0x20, 0xa2, 0xab, 0xcf, 0xf8, 0x89, 0xaf, 0x3e, 0xe1, 0x2b, 0x25,
+	0x4f, 0xf0, 0x4a, 0x51, 0x5b, 0x4a, 0xbd, 0x70, 0x5b, 0x4a, 0x9f, 0xbc, 0x2d, 0x85, 0x9d, 0x32,
+	0x73, 0x82, 0x4e, 0x59, 0x47, 0xa7, 0x37, 0x3d, 0xb7, 0x0b, 0x5f, 0xaa, 0x5c, 0xcf, 0xf4, 0xf6,
+	0xe4, 0x54, 0x00, 0xad, 0x9b, 0x6b, 0xd6, 0x43, 0x85, 0x6a, 0xdd, 0x31, 0x94, 0xd0, 0x38, 0x2b,
+	0xde, 0x13, 0xb3, 0x2f, 0xd6, 0x13, 0xf1, 0x4d, 0x94, 0x15, 0x73, 0xa7, 0xe3, 0xc2, 0xe5, 0x27,
+	0x5d, 0x7a, 0x99, 0x97, 0x32, 0xc0, 0x6a, 0xae, 0x2a, 0x65, 0x52, 0x56, 0xaf, 0x1d, 0x12, 0xc8,
+	0xef, 0x13, 0x28, 0x4b, 0x99, 0xdf, 0x73, 0x1d, 0x9f, 0x7d, 0xd7, 0x20, 0x98, 0x47, 0x29, 0xcb,
+	0xec, 0x9b, 0x32, 0xec, 0x60, 0xf7, 0xb8, 0xac, 0x76, 0x8f, 0x0b, 0x84, 0x02, 0x86, 0x3f, 0x44,
+	0xa9, 0x96, 0x6b, 0x89, 0xc3, 0x3f, 0xad, 0x17, 0xcd, 0x8a, 0xe7, 0xb9, 0xde, 0x92, 0x6b, 0xc9,
+	0xe1, 0x9f, 0x93, 0x94, 0x03, 0x2e, 0x10, 0x0a, 0x18, 0xf9, 0x5d, 0x02, 0xe5, 0xca, 0xee, 0x8e,
+	0xd3, 0x71, 0x4d, 0x6b, 0xcd, 0x73, 0xdb, 0x1e, 0xf3, 0xfd, 0xef, 0x74, 0x03, 0x6f, 0xa2, 0x89,
+	0x01, 0xdc, 0xdf, 0xc3, 0x3b, 0xf8, 0xd5, 0xf8, 0x65, 0xe4, 0xf0, 0x43, 0xc4, 0x65, 0x3f, 0xfa,
+	0xdc, 0x27, 0x8d, 0x95, 0x7f, 0x21, 0x13, 0x1a, 0x2a, 0xc8, 0x6f, 0x93, 0xa8, 0x70, 0xbc, 0x23,
+	0xdc, 0x45, 0x53, 0x82, 0xd9, 0xd4, 0x3e, 0xac, 0xcf, 0x9d, 0x64, 0x0d, 0x70, 0x45, 0x82, 0xd1,
+	0x7c, 0xa0, 0x64, 0x35, 0x9a, 0x47, 0x10, 0xa1, 0x9a, 0xfe, 0x85, 0xbe, 0x16, 0x6a, 0x17, 0xea,
+	0xe4, 0xf7, 0xbf, 0x50, 0x37, 0xd0, 0x29, 0x11, 0xa2, 0xe1, 0x67, 0xdd, 0x54, 0x31, 0x39, 0x97,
+	0x2e, 0x5d, 0xe3, 0xd5, 0x76, 0x43, 0x0c, 0xab, 0xe1, 0x07, 0xdd, 0x99, 0x28, 0x58, 0x05, 0x18,
+	0x46, 0x5b, 0x6e, 0x8c, 0xc6, 0xb8, 0x78, 0x39, 0x76, 0xdf, 0x12, 0xa9, 0xfe, 0x5f, 0x27, 0xbc,
+	0x5f, 0x69, 0xf7, 0x29, 0x92, 0x41, 0xa9, 0x35, 0xdb, 0x69, 0x93, 0x1b, 0x28, 0xbd, 0xd4, 0x71,
+	0x7d, 0xa8, 0x38, 0x1e, 0x33, 0x7d, 0xd7, 0xd1, 0x43, 0x49, 0x20, 0xea, 0xa8, 0x85, 0x48, 0xa8,
+	0xc4, 0xe7, 0xbf, 0x4a, 0xa2, 0x29, 0xed, 0xef, 0x20, 0xf8, 0xff, 0xd0, 0xa5, 0x3b, 0x95, 0x46,
+	0x63, 0x71, 0xa5, 0xd2, 0x5c, 0x7f, 0xb0, 0x56, 0x69, 0x2e, 0xad, 0xde, 0x6d, 0xac, 0x57, 0x68,
+	0x73, 0xa9, 0x5e, 0x5b, 0xae, 0xae, 0xe4, 0xc6, 0x0a, 0x97, 0xf7, 0x0f, 0x8a, 0x79, 0xcd, 0x22,
+	0xfe, 0x17, 0x8b, 0xff, 0x46, 0x38, 0x66, 0x5e, 0xad, 0x95, 0x2b, 0x9f, 0xe4, 0x12, 0x85, 0x73,
+	0xfb, 0x07, 0xc5, 0x9c, 0x66, 0x25, 0x3e, 0x84, 0xfd, 0x2f, 0x7a, 0xe9, 0x28, 0xbb, 0x79, 0x77,
+	0xad, 0xbc, 0xb8, 0x5e, 0xc9, 0x8d, 0x17, 0x0a, 0xfb, 0x07, 0xc5, 0x0b, 0x87, 0x8d, 0x64, 0x08,
+	0xbe, 0x81, 0xce, 0xc5, 0x4c, 0x69, 0xe5, 0xe3, 0xbb, 0x95, 0xc6, 0x7a, 0x2e, 0x59, 0xb8, 0xb0,
+	0x7f, 0x50, 0xc4, 0x9a, 0x55, 0xd8, 0x26, 0x16, 0xd0, 0xf9, 0x43, 0x16, 0x8d, 0xb5, 0x7a, 0xad,
+	0x51, 0xc9, 0xa5, 0x0a, 0x17, 0xf7, 0x0f, 0x8a, 0x67, 0x63, 0x26, 0xb2, 0xaa, 0x2c, 0xa1, 0xd9,
+	0x98, 0x4d, 0xb9, 0x7e, 0xbf, 0xb6, 0x5a, 0x5f, 0x2c, 0x37, 0xd7, 0x68, 0x7d, 0x85, 0x56, 0x1a,
+	0x8d, 0x5c, 0xba, 0x60, 0xec, 0x1f, 0x14, 0x2f, 0x69, 0xc6, 0x47, 0x32, 0x7c, 0x1e, 0xcd, 0xc4,
+	0x9c, 0xac, 0x55, 0x6b, 0x2b, 0xb9, 0x4c, 0xe1, 0xec, 0xfe, 0x41, 0xf1, 0x8c, 0x66, 0xc7, 0xcf,
+	0xf2, 0xc8, 0xfe, 0x2d, 0xad, 0xd6, 0x1b, 0x95, 0xdc, 0xc4, 0x91, 0xfd, 0x83, 0x03, 0x9f, 0xff,
+	0x4d, 0x02, 0xe1, 0xa3, 0x7f, 0x7a, 0xc2, 0xef, 0xa1, 0x7c, 0xe8, 0x64, 0xa9, 0x7e, 0x67, 0x8d,
+	0xaf, 0xb3, 0x5a, 0xaf, 0x35, 0x6b, 0xf5, 0x5a, 0x25, 0x37, 0x16, 0xdb, 0x55, 0xcd, 0xaa, 0xe6,
+	0x3a, 0x0c, 0xd7, 0xd1, 0xc5, 0xe7, 0x59, 0xae, 0x3e, 0x7c, 0x3b, 0x97, 0x28, 0x2c, 0xec, 0x1f,
+	0x14, 0xcf, 0x1f, 0x35, 0x5c, 0x7d, 0xf8, 0xf6, 0xd7, 0x3f, 0x7f, 0xe5, 0xf9, 0x8a, 0x79, 0x3e,
+	0x00, 0xe9, 0x4b, 0x7b, 0x13, 0x9d, 0xd3, 0x1d, 0xdf, 0xa9, 0xac, 0x2f, 0x96, 0x17, 0xd7, 0x17,
+	0x73, 0x63, 0xe2, 0x0c, 0x34, 0xea, 0x1d, 0xd6, 0x37, 0xa1, 0xec, 0xbe, 0x86, 0x66, 0x62, 0x6f,
+	0x51, 0xb9, 0x57, 0xa1, 0x61, 0x44, 0xe9, 0xeb, 0x67, 0xdb, 0xcc, 0xc3, 0xaf, 0x23, 0xac, 0x93,
+	0x17, 0x57, 0xef, 0x2f, 0x3e, 0x68, 0xe4, 0xc6, 0x0b, 0xe7, 0xf7, 0x0f, 0x8a, 0x33, 0x1a, 0x7b,
+	0xb1, 0xb3, 0x63, 0xee, 0xf9, 0xf3, 0x7f, 0x1c, 0x47, 0xd3, 0xfa, 0xd7, 0x1b, 0xfc, 0x3a, 0x3a,
+	0xbb, 0x5c, 0x5d, 0xe5, 0x91, 0xb8, 0x5c, 0x17, 0x27, 0xc0, 0xc5, 0xdc, 0x98, 0x78, 0x9c, 0x4e,
+	0xe5, 0xbf, 0xf1, 0xff, 0xa0, 0xfc, 0x21, 0x7a, 0xb9, 0x4a, 0x2b, 0x4b, 0xeb, 0x75, 0xfa, 0x20,
+	0x97, 0x28, 0xbc, 0xc4, 0x37, 0x4c, 0xb7, 0x29, 0xdb, 0x1e, 0x94, 0xa0, 0x3d, 0x7c, 0x13, 0x5d,
+	0x3a, 0x64, 0xd8, 0x78, 0x70, 0x67, 0xb5, 0x5a, 0xbb, 0x2d, 0x9e, 0x37, 0x5e, 0xb8, 0xb2, 0x7f,
+	0x50, 0xbc, 0xa8, 0xdb, 0x36, 0xc4, 0x07, 0x31, 0x0e, 0x65, 0x13, 0xf8, 0x16, 0x2a, 0x1e, 0x63,
+	0x1f, 0x2d, 0x20, 0x59, 0x20, 0xfb, 0x07, 0xc5, 0xcb, 0xcf, 0x71, 0xa2, 0xd6, 0x91, 0x4d, 0xe0,
+	0xb7, 0xd0, 0x85, 0xe7, 0x7b, 0x0a, 0xf3, 0xe2, 0x39, 0xf6, 0xf3, 0x7f, 0x4e, 0xa0, 0x49, 0xd5,
+	0xf5, 0xf8, 0xa6, 0x55, 0x28, 0xad, 0xf3, 0x22, 0x51, 0xae, 0x34, 0x6b, 0xf5, 0x26, 0x48, 0xe1,
+	0xa6, 0x29, 0x5e, 0xcd, 0x85, 0x9f, 0x3c, 0xc6, 0x35, 0xfa, 0x4a, 0xa5, 0x56, 0xa1, 0xd5, 0xa5,
+	0xf0, 0x44, 0x15, 0x7b, 0x85, 0x39, 0xcc, 0xb3, 0x5b, 0xf8, 0x6d, 0x74, 0x31, 0xee, 0xbc, 0x71,
+	0x77, 0xe9, 0x56, 0xb8, 0x4b, 0xb0, 0x40, 0xed, 0x01, 0x8d, 0x41, 0x6b, 0x0b, 0x0e, 0xe6, 0x9d,
+	0x98, 0x55, 0xb5, 0x76, 0x6f, 0x71, 0xb5, 0x5a, 0x16, 0x56, 0xc9, 0x42, 0x7e, 0xff, 0xa0, 0x78,
+	0x4e, 0x59, 0xc9, 0x0f, 0x1c, 0xdc, 0x6c, 0xfe, 0xeb, 0x04, 0x9a, 0xfd, 0xf6, 0xe6, 0x85, 0xef,
+	0xa3, 0x57, 0x61, 0xbf, 0x8e, 0x94, 0x02, 0x59, 0xb7, 0xc4, 0x1e, 0x2e, 0xae, 0xad, 0x55, 0x6a,
+	0xe5, 0xdc, 0x58, 0x61, 0x6e, 0xff, 0xa0, 0x78, 0xf5, 0xdb, 0x5d, 0x2e, 0xf6, 0x7a, 0xcc, 0xb1,
+	0x4e, 0xe8, 0x78, 0xb9, 0x4e, 0x57, 0x2a, 0xeb, 0xb9, 0xc4, 0x49, 0x1c, 0x2f, 0xbb, 0x5e, 0x9b,
+	0xf5, 0x4b, 0x77, 0x1e, 0x7f, 0x33, 0x3b, 0xf6, 0xe4, 0x9b, 0xd9, 0xb1, 0xc7, 0x4f, 0x67, 0x13,
+	0x4f, 0x9e, 0xce, 0x26, 0x7e, 0xf1, 0x6c, 0x76, 0xec, 0xcb, 0x67, 0xb3, 0x89, 0x27, 0xcf, 0x66,
+	0xc7, 0xfe, 0xf2, 0x6c, 0x76, 0xec, 0xe1, 0x6b, 0x6d, 0xbb, 0xbf, 0x35, 0xd8, 0xb8, 0xd6, 0x72,
+	0xbb, 0xd7, 0xfd, 0x3d, 0xa7, 0xd5, 0xdf, 0xb2, 0x9d, 0xb6, 0xf6, 0x4b, 0xff, 0x2f, 0x08, 0x1b,
+	0x19, 0xf8, 0xf5, 0xd6, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x4c, 0xc3, 0x32, 0x75, 0x99, 0x20,
+	0x00, 0x00,
 }
 
 func (m *Hello) Marshal() (dAtA []byte, err error) {
@@ -1664,6 +1761,13 @@ func (m *FileInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	if m.InodeChangeNs != 0 {
+		i = encodeVarintBep(dAtA, i, uint64(m.InodeChangeNs))
+		i--
+		dAtA[i] = 0x3e
+		i--
+		dAtA[i] = 0xd0
+	}
 	if len(m.VersionHash) > 0 {
 		i -= len(m.VersionHash)
 		copy(dAtA[i:], m.VersionHash)
@@ -1958,6 +2062,54 @@ func (m *PlatformData) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	if m.NetBSD != nil {
+		{
+			size, err := m.NetBSD.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintBep(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x32
+	}
+	if m.FreeBSD != nil {
+		{
+			size, err := m.FreeBSD.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintBep(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x2a
+	}
+	if m.Darwin != nil {
+		{
+			size, err := m.Darwin.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintBep(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x22
+	}
+	if m.Linux != nil {
+		{
+			size, err := m.Linux.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintBep(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x1a
+	}
 	if m.Windows != nil {
 		{
 			size, err := m.Windows.MarshalToSizedBuffer(dAtA[:i])
@@ -2072,6 +2224,80 @@ func (m *WindowsData) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	return len(dAtA) - i, nil
 }
 
+func (m *XattrData) Marshal() (dAtA []byte, err error) {
+	size := m.ProtoSize()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *XattrData) MarshalTo(dAtA []byte) (int, error) {
+	size := m.ProtoSize()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *XattrData) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if len(m.Xattrs) > 0 {
+		for iNdEx := len(m.Xattrs) - 1; iNdEx >= 0; iNdEx-- {
+			{
+				size, err := m.Xattrs[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+				if err != nil {
+					return 0, err
+				}
+				i -= size
+				i = encodeVarintBep(dAtA, i, uint64(size))
+			}
+			i--
+			dAtA[i] = 0xa
+		}
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *Xattr) Marshal() (dAtA []byte, err error) {
+	size := m.ProtoSize()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *Xattr) MarshalTo(dAtA []byte) (int, error) {
+	size := m.ProtoSize()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *Xattr) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if len(m.Value) > 0 {
+		i -= len(m.Value)
+		copy(dAtA[i:], m.Value)
+		i = encodeVarintBep(dAtA, i, uint64(len(m.Value)))
+		i--
+		dAtA[i] = 0x12
+	}
+	if len(m.Name) > 0 {
+		i -= len(m.Name)
+		copy(dAtA[i:], m.Name)
+		i = encodeVarintBep(dAtA, i, uint64(len(m.Name)))
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
 func (m *Request) Marshal() (dAtA []byte, err error) {
 	size := m.ProtoSize()
 	dAtA = make([]byte, size)
@@ -2599,6 +2825,9 @@ func (m *FileInfo) ProtoSize() (n int) {
 	if l > 0 {
 		n += 2 + l + sovBep(uint64(l))
 	}
+	if m.InodeChangeNs != 0 {
+		n += 2 + sovBep(uint64(m.InodeChangeNs))
+	}
 	return n
 }
 
@@ -2668,6 +2897,22 @@ func (m *PlatformData) ProtoSize() (n int) {
 		l = m.Windows.ProtoSize()
 		n += 1 + l + sovBep(uint64(l))
 	}
+	if m.Linux != nil {
+		l = m.Linux.ProtoSize()
+		n += 1 + l + sovBep(uint64(l))
+	}
+	if m.Darwin != nil {
+		l = m.Darwin.ProtoSize()
+		n += 1 + l + sovBep(uint64(l))
+	}
+	if m.FreeBSD != nil {
+		l = m.FreeBSD.ProtoSize()
+		n += 1 + l + sovBep(uint64(l))
+	}
+	if m.NetBSD != nil {
+		l = m.NetBSD.ProtoSize()
+		n += 1 + l + sovBep(uint64(l))
+	}
 	return n
 }
 
@@ -2710,6 +2955,38 @@ func (m *WindowsData) ProtoSize() (n int) {
 	return n
 }
 
+func (m *XattrData) ProtoSize() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if len(m.Xattrs) > 0 {
+		for _, e := range m.Xattrs {
+			l = e.ProtoSize()
+			n += 1 + l + sovBep(uint64(l))
+		}
+	}
+	return n
+}
+
+func (m *Xattr) ProtoSize() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.Name)
+	if l > 0 {
+		n += 1 + l + sovBep(uint64(l))
+	}
+	l = len(m.Value)
+	if l > 0 {
+		n += 1 + l + sovBep(uint64(l))
+	}
+	return n
+}
+
 func (m *Request) ProtoSize() (n int) {
 	if m == nil {
 		return 0
@@ -4475,6 +4752,25 @@ func (m *FileInfo) Unmarshal(dAtA []byte) error {
 				m.VersionHash = []byte{}
 			}
 			iNdEx = postIndex
+		case 1002:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field InodeChangeNs", wireType)
+			}
+			m.InodeChangeNs = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.InodeChangeNs |= int64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
 		default:
 			iNdEx = preIndex
 			skippy, err := skipBep(dAtA[iNdEx:])
@@ -4910,35 +5206,179 @@ func (m *PlatformData) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
-		default:
-			iNdEx = preIndex
-			skippy, err := skipBep(dAtA[iNdEx:])
-			if err != nil {
-				return err
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Linux", wireType)
 			}
-			if (skippy < 0) || (iNdEx+skippy) < 0 {
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
 				return ErrInvalidLengthBep
 			}
-			if (iNdEx + skippy) > l {
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthBep
+			}
+			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			iNdEx += skippy
-		}
-	}
-
-	if iNdEx > l {
-		return io.ErrUnexpectedEOF
-	}
-	return nil
-}
-func (m *UnixData) Unmarshal(dAtA []byte) error {
-	l := len(dAtA)
-	iNdEx := 0
-	for iNdEx < l {
-		preIndex := iNdEx
-		var wire uint64
-		for shift := uint(0); ; shift += 7 {
-			if shift >= 64 {
+			if m.Linux == nil {
+				m.Linux = &XattrData{}
+			}
+			if err := m.Linux.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Darwin", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthBep
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthBep
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Darwin == nil {
+				m.Darwin = &XattrData{}
+			}
+			if err := m.Darwin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field FreeBSD", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthBep
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthBep
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.FreeBSD == nil {
+				m.FreeBSD = &XattrData{}
+			}
+			if err := m.FreeBSD.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NetBSD", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthBep
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthBep
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.NetBSD == nil {
+				m.NetBSD = &XattrData{}
+			}
+			if err := m.NetBSD.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipBep(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthBep
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *UnixData) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
 				return ErrIntOverflowBep
 			}
 			if iNdEx >= l {
@@ -5185,6 +5625,206 @@ func (m *WindowsData) Unmarshal(dAtA []byte) error {
 	}
 	return nil
 }
+func (m *XattrData) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowBep
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: XattrData: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: XattrData: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Xattrs", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthBep
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthBep
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Xattrs = append(m.Xattrs, Xattr{})
+			if err := m.Xattrs[len(m.Xattrs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipBep(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthBep
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *Xattr) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowBep
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Xattr: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Xattr: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthBep
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthBep
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Name = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowBep
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthBep
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex < 0 {
+				return ErrInvalidLengthBep
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...)
+			if m.Value == nil {
+				m.Value = []byte{}
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipBep(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthBep
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func (m *Request) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
diff --git a/lib/protocol/bep_extensions.go b/lib/protocol/bep_extensions.go
index 706bab86158..a380bcfa196 100644
--- a/lib/protocol/bep_extensions.go
+++ b/lib/protocol/bep_extensions.go
@@ -44,6 +44,8 @@ type FileIntf interface {
 	FilePermissions() uint32
 	FileModifiedBy() ShortID
 	ModTime() time.Time
+	PlatformData() PlatformData
+	InodeChangeTime() time.Time
 }
 
 func (Hello) Magic() uint32 {
@@ -160,6 +162,14 @@ func (f FileInfo) FileModifiedBy() ShortID {
 	return f.ModifiedBy
 }
 
+func (f FileInfo) PlatformData() PlatformData {
+	return f.Platform
+}
+
+func (f FileInfo) InodeChangeTime() time.Time {
+	return time.Unix(0, f.InodeChangeNs)
+}
+
 // WinsConflict returns true if "f" is the one to choose when it is in
 // conflict with "other".
 func WinsConflict(f, other FileIntf) bool {
@@ -196,6 +206,7 @@ type FileInfoComparison struct {
 	IgnoreBlocks    bool
 	IgnoreFlags     uint32
 	IgnoreOwnership bool
+	IgnoreXattrs    bool
 }
 
 func (f FileInfo) IsEquivalent(other FileInfo, modTimeWindow time.Duration) bool {
@@ -233,6 +244,12 @@ func (f FileInfo) isEquivalent(other FileInfo, comp FileInfoComparison) bool {
 		return false
 	}
 
+	// If we are recording inode change times and it changed, they are not
+	// equal.
+	if f.InodeChangeNs != 0 && other.InodeChangeNs != 0 && f.InodeChangeNs != other.InodeChangeNs {
+		return false
+	}
+
 	// Mask out the ignored local flags before checking IsInvalid() below
 	f.LocalFlags &^= comp.IgnoreFlags
 	other.LocalFlags &^= comp.IgnoreFlags
@@ -252,11 +269,26 @@ func (f FileInfo) isEquivalent(other FileInfo, comp FileInfoComparison) bool {
 			}
 		}
 		if f.Platform.Windows != nil && other.Platform.Windows != nil {
-			if *f.Platform.Windows != *other.Platform.Windows {
+			if f.Platform.Windows.OwnerName != other.Platform.Windows.OwnerName ||
+				f.Platform.Windows.OwnerIsGroup != other.Platform.Windows.OwnerIsGroup {
 				return false
 			}
 		}
 	}
+	if !comp.IgnoreXattrs && f.Platform != other.Platform {
+		if !xattrsEqual(f.Platform.Linux, other.Platform.Linux) {
+			return false
+		}
+		if !xattrsEqual(f.Platform.Darwin, other.Platform.Darwin) {
+			return false
+		}
+		if !xattrsEqual(f.Platform.FreeBSD, other.Platform.FreeBSD) {
+			return false
+		}
+		if !xattrsEqual(f.Platform.NetBSD, other.Platform.NetBSD) {
+			return false
+		}
+	}
 
 	if !comp.IgnorePerms && !f.NoPermissions && !other.NoPermissions && !PermsEqual(f.Permissions, other.Permissions) {
 		return false
@@ -308,6 +340,76 @@ func (f FileInfo) BlocksEqual(other FileInfo) bool {
 	return blocksEqual(f.Blocks, other.Blocks)
 }
 
+// Xattrs is a convenience method to return the extended attributes of the
+// file for the current platform.
+func (f *PlatformData) Xattrs() []Xattr {
+	switch {
+	case build.IsLinux && f.Linux != nil:
+		return f.Linux.Xattrs
+	case build.IsDarwin && f.Darwin != nil:
+		return f.Darwin.Xattrs
+	case build.IsFreeBSD && f.FreeBSD != nil:
+		return f.FreeBSD.Xattrs
+	case build.IsNetBSD && f.NetBSD != nil:
+		return f.NetBSD.Xattrs
+	default:
+		return nil
+	}
+}
+
+// SetXattrs is a convenience method to set the extended attributes of the
+// file for the current platform.
+func (p *PlatformData) SetXattrs(xattrs []Xattr) {
+	switch {
+	case build.IsLinux:
+		if p.Linux == nil {
+			p.Linux = &XattrData{}
+		}
+		p.Linux.Xattrs = xattrs
+
+	case build.IsDarwin:
+		if p.Darwin == nil {
+			p.Darwin = &XattrData{}
+		}
+		p.Darwin.Xattrs = xattrs
+
+	case build.IsFreeBSD:
+		if p.FreeBSD == nil {
+			p.FreeBSD = &XattrData{}
+		}
+		p.FreeBSD.Xattrs = xattrs
+
+	case build.IsNetBSD:
+		if p.NetBSD == nil {
+			p.NetBSD = &XattrData{}
+		}
+		p.NetBSD.Xattrs = xattrs
+	}
+}
+
+// MergeWith copies platform data from other, for platforms where it's not
+// already set on p.
+func (p *PlatformData) MergeWith(other *PlatformData) {
+	if p.Unix == nil {
+		p.Unix = other.Unix
+	}
+	if p.Windows == nil {
+		p.Windows = other.Windows
+	}
+	if p.Linux == nil {
+		p.Linux = other.Linux
+	}
+	if p.Darwin == nil {
+		p.Darwin = other.Darwin
+	}
+	if p.FreeBSD == nil {
+		p.FreeBSD = other.FreeBSD
+	}
+	if p.NetBSD == nil {
+		p.NetBSD = other.NetBSD
+	}
+}
+
 // blocksEqual returns whether two slices of blocks are exactly the same hash
 // and index pair wise.
 func blocksEqual(a, b []BlockInfo) bool {
@@ -438,3 +540,23 @@ func (x *FileInfoType) UnmarshalJSON(data []byte) error {
 	*x = FileInfoType(n)
 	return nil
 }
+
+func xattrsEqual(a, b *XattrData) bool {
+	if a == nil || b == nil {
+		// Having no data on either side means we have nothing to compare
+		// to, and we consider that equal.
+		return true
+	}
+	if len(a.Xattrs) != len(b.Xattrs) {
+		return false
+	}
+	for i := range a.Xattrs {
+		if a.Xattrs[i].Name != b.Xattrs[i].Name {
+			return false
+		}
+		if !bytes.Equal(a.Xattrs[i].Value, b.Xattrs[i].Value) {
+			return false
+		}
+	}
+	return true
+}
diff --git a/lib/scanner/walk.go b/lib/scanner/walk.go
index cbd5ecaed92..7a782a21a90 100644
--- a/lib/scanner/walk.go
+++ b/lib/scanner/walk.go
@@ -42,8 +42,6 @@ type Config struct {
 	// If IgnorePerms is true, changes to permission bits will not be
 	// detected.
 	IgnorePerms bool
-	// If IgnoreOwnership is true, changes to ownership will not be detected.
-	IgnoreOwnership bool
 	// When AutoNormalize is set, file names that are in UTF8 but incorrect
 	// normalization form will be corrected.
 	AutoNormalize bool
@@ -62,6 +60,10 @@ type Config struct {
 	EventLogger events.Logger
 	// If ScanOwnership is true, we pick up ownership information on files while scanning.
 	ScanOwnership bool
+	// If ScanXattrs is true, we pick up extended attributes on files while scanning.
+	ScanXattrs bool
+	// Filter for extended attributes
+	XattrFilter XattrFilter
 }
 
 type CurrentFiler interface {
@@ -69,6 +71,12 @@ type CurrentFiler interface {
 	CurrentFile(name string) (protocol.FileInfo, bool)
 }
 
+type XattrFilter interface {
+	Permit(string) bool
+	GetMaxSingleEntrySize() int
+	GetMaxTotalSize() int
+}
+
 type ScanResult struct {
 	File protocol.FileInfo
 	Err  error
@@ -384,7 +392,7 @@ func (w *walker) walkRegular(ctx context.Context, relPath string, info fs.FileIn
 		}
 	}
 
-	f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership)
+	f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership, w.ScanXattrs, w.XattrFilter)
 	if err != nil {
 		return err
 	}
@@ -398,7 +406,8 @@ func (w *walker) walkRegular(ctx context.Context, relPath string, info fs.FileIn
 			IgnorePerms:     w.IgnorePerms,
 			IgnoreBlocks:    true,
 			IgnoreFlags:     w.LocalFlags,
-			IgnoreOwnership: w.IgnoreOwnership,
+			IgnoreOwnership: !w.ScanOwnership,
+			IgnoreXattrs:    !w.ScanXattrs,
 		}) {
 			l.Debugln(w, "unchanged:", curFile, info.ModTime().Unix(), info.Mode()&fs.ModePerm)
 			return nil
@@ -428,7 +437,7 @@ func (w *walker) walkRegular(ctx context.Context, relPath string, info fs.FileIn
 func (w *walker) walkDir(ctx context.Context, relPath string, info fs.FileInfo, finishedChan chan<- ScanResult) error {
 	curFile, hasCurFile := w.CurrentFiler.CurrentFile(relPath)
 
-	f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership)
+	f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership, w.ScanXattrs, w.XattrFilter)
 	if err != nil {
 		return err
 	}
@@ -441,7 +450,8 @@ func (w *walker) walkDir(ctx context.Context, relPath string, info fs.FileInfo,
 			IgnorePerms:     w.IgnorePerms,
 			IgnoreBlocks:    true,
 			IgnoreFlags:     w.LocalFlags,
-			IgnoreOwnership: w.IgnoreOwnership,
+			IgnoreOwnership: !w.ScanOwnership,
+			IgnoreXattrs:    !w.ScanXattrs,
 		}) {
 			l.Debugln(w, "unchanged:", curFile, info.ModTime().Unix(), info.Mode()&fs.ModePerm)
 			return nil
@@ -476,9 +486,9 @@ func (w *walker) walkSymlink(ctx context.Context, relPath string, info fs.FileIn
 		return nil
 	}
 
-	f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership)
+	f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership, w.ScanXattrs, w.XattrFilter)
 	if err != nil {
-		handleError(ctx, "reading link:", relPath, err, finishedChan)
+		handleError(ctx, "reading link", relPath, err, finishedChan)
 		return nil
 	}
 
@@ -492,7 +502,8 @@ func (w *walker) walkSymlink(ctx context.Context, relPath string, info fs.FileIn
 			IgnorePerms:     w.IgnorePerms,
 			IgnoreBlocks:    true,
 			IgnoreFlags:     w.LocalFlags,
-			IgnoreOwnership: w.IgnoreOwnership,
+			IgnoreOwnership: !w.ScanOwnership,
+			IgnoreXattrs:    !w.ScanXattrs,
 		}) {
 			l.Debugln(w, "unchanged:", curFile, info.ModTime().Unix(), info.Mode()&fs.ModePerm)
 			return nil
@@ -591,12 +602,7 @@ func (w *walker) updateFileInfo(dst, src protocol.FileInfo) protocol.FileInfo {
 	dst.LocalFlags = w.LocalFlags
 
 	// Copy OS data from src to dst, unless it was already set on dst.
-	if dst.Platform.Unix == nil {
-		dst.Platform.Unix = src.Platform.Unix
-	}
-	if dst.Platform.Windows == nil {
-		dst.Platform.Windows = src.Platform.Windows
-	}
+	dst.Platform.MergeWith(&src.Platform)
 
 	return dst
 }
@@ -668,10 +674,10 @@ func (noCurrentFiler) CurrentFile(_ string) (protocol.FileInfo, bool) {
 	return protocol.FileInfo{}, false
 }
 
-func CreateFileInfo(fi fs.FileInfo, name string, filesystem fs.Filesystem, scanOwnership bool) (protocol.FileInfo, error) {
+func CreateFileInfo(fi fs.FileInfo, name string, filesystem fs.Filesystem, scanOwnership bool, scanXattrs bool, xattrFilter XattrFilter) (protocol.FileInfo, error) {
 	f := protocol.FileInfo{Name: name}
-	if scanOwnership {
-		if plat, err := filesystem.PlatformData(name); err == nil {
+	if scanOwnership || scanXattrs {
+		if plat, err := filesystem.PlatformData(name, scanOwnership, scanXattrs, xattrFilter); err == nil {
 			f.Platform = plat
 		} else {
 			return protocol.FileInfo{}, fmt.Errorf("reading platform data: %w", err)
@@ -696,5 +702,10 @@ func CreateFileInfo(fi fs.FileInfo, name string, filesystem fs.Filesystem, scanO
 	}
 	f.Size = fi.Size()
 	f.Type = protocol.FileInfoTypeFile
+	if ct := fi.InodeChangeTime(); !ct.IsZero() {
+		f.InodeChangeNs = ct.UnixNano()
+	} else {
+		f.InodeChangeNs = 0
+	}
 	return f, nil
 }
diff --git a/proto/lib/config/folderconfiguration.proto b/proto/lib/config/folderconfiguration.proto
index 44e10f73f67..63326a31e9c 100644
--- a/proto/lib/config/folderconfiguration.proto
+++ b/proto/lib/config/folderconfiguration.proto
@@ -55,10 +55,31 @@ message FolderConfiguration {
     bool                               case_sensitive_fs          = 33 [(ext.goname) = "CaseSensitiveFS", (ext.xml) = "caseSensitiveFS", (ext.json) = "caseSensitiveFS"];
     bool                               follow_junctions           = 34 [(ext.goname) = "JunctionsAsDirs", (ext.xml) = "junctionsAsDirs", (ext.json) = "junctionsAsDirs"];
     bool                               sync_ownership             = 35;
-    bool                               scan_ownership             = 36;
+    bool                               send_ownership             = 36;
+    bool                               sync_xattrs                = 37;
+    bool                               send_xattrs                = 38;
+    XattrFilter                        xattr_filter               = 39;
 
     // Legacy deprecated
     bool   read_only         = 9000 [deprecated=true, (ext.xml) = "ro,attr,omitempty"];
     double min_disk_free_pct = 9001 [deprecated=true];
     int32  pullers           = 9002 [deprecated=true];
+    bool   scan_ownership    = 9003 [deprecated=true];
+}
+
+// Extended attribute filter. This is a list of patterns to match (glob
+// style), each with an action (permit or deny). First match is used. If the
+// filter is empty, all strings are permitted. If the filter is non-empty,
+// the default action becomes deny. To counter this, you can use the "*"
+// pattern to match all strings at the end of the filter. There are also
+// limits on the size of accepted attributes.
+message XattrFilter {
+    repeated XattrFilterEntry entries               = 1 [(ext.xml) = "entry"];
+    int32                     max_single_entry_size = 2 [(ext.xml) = "maxSingleEntrySize", (ext.default) = "1024"];
+    int32                     max_total_size        = 3 [(ext.xml) = "maxTotalSize", (ext.default) = "4096"];
+}
+
+message XattrFilterEntry {
+    string match  = 1 [(ext.xml) = "match,attr"];
+    bool   permit = 2 [(ext.xml) = "permit,attr"];
 }
diff --git a/proto/lib/db/structs.proto b/proto/lib/db/structs.proto
index 9bb8300aad7..7ea733c4aaf 100644
--- a/proto/lib/db/structs.proto
+++ b/proto/lib/db/structs.proto
@@ -39,8 +39,9 @@ message FileInfoTruncated {
     protocol.PlatformData platform       = 14;
 
     // see bep.proto
-    uint32 local_flags  = 1000;
-    bytes  version_hash = 1001;
+    uint32 local_flags     = 1000;
+    bytes  version_hash    = 1001;
+    int64  inode_change_ns = 1002;
 
     bool deleted        = 6;
     bool invalid        = 7 [(ext.goname) = "RawInvalid"];
diff --git a/proto/lib/protocol/bep.proto b/proto/lib/protocol/bep.proto
index 167cd22cf2a..4204387b732 100644
--- a/proto/lib/protocol/bep.proto
+++ b/proto/lib/protocol/bep.proto
@@ -114,10 +114,15 @@ message FileInfo {
     // received (we make sure to zero it), nonetheless we need it on our
     // struct and to be able to serialize it to/from the database.
     uint32 local_flags = 1000;
+
     // The version_hash is an implementation detail and not part of the wire
     // format.
     bytes version_hash = 1001;
 
+    // The time when the inode was last changed (i.e., permissions, xattrs
+    // etc changed). This is host-local, not sent over the wire.
+    int64 inode_change_ns = 1002;
+
     bool deleted        = 6;
     bool invalid        = 7 [(ext.goname) = "RawInvalid"];
     bool no_permissions = 8;
@@ -151,6 +156,10 @@ message Counter {
 message PlatformData {
     UnixData    unix    = 1 [(gogoproto.nullable) = true];
     WindowsData windows = 2 [(gogoproto.nullable) = true];
+    XattrData   linux   = 3 [(gogoproto.nullable) = true];
+    XattrData   darwin  = 4 [(gogoproto.nullable) = true];
+    XattrData   freebsd = 5 [(gogoproto.nullable) = true, (ext.goname) = "FreeBSD"];
+    XattrData   netbsd  = 6 [(gogoproto.nullable) = true, (ext.goname) = "NetBSD"];
 }
 
 message UnixData {
@@ -171,6 +180,15 @@ message WindowsData {
     bool   owner_is_group = 2;
 }
 
+message XattrData {
+    repeated Xattr xattrs = 1;
+}
+
+message Xattr {
+    string name  = 1;
+    bytes  value = 2;
+}
+
 // Request
 
 message Request {


Test patch:
diff --git a/lib/config/config_test.go b/lib/config/config_test.go
index b4c0fa51a48..bf3531d88b4 100644
--- a/lib/config/config_test.go
+++ b/lib/config/config_test.go
@@ -106,6 +106,11 @@ func TestDefaultValues(t *testing.T) {
 				WeakHashThresholdPct: 25,
 				MarkerName:           ".stfolder",
 				MaxConcurrentWrites:  2,
+				XattrFilter: XattrFilter{
+					Entries:            []XattrFilterEntry{},
+					MaxSingleEntrySize: 1024,
+					MaxTotalSize:       4096,
+				},
 			},
 			Device: DeviceConfiguration{
 				Addresses:       []string{"dynamic"},
@@ -177,6 +182,9 @@ func TestDeviceConfig(t *testing.T) {
 				MarkerName:           DefaultMarkerName,
 				JunctionsAsDirs:      true,
 				MaxConcurrentWrites:  maxConcurrentWritesDefault,
+				XattrFilter: XattrFilter{
+					Entries: []XattrFilterEntry{},
+				},
 			},
 		}
 
@@ -1420,3 +1428,43 @@ func TestReceiveEncryptedFolderFixed(t *testing.T) {
 		t.Error("IgnorePerms should be true")
 	}
 }
+
+func TestXattrFilter(t *testing.T) {
+	cases := []struct {
+		in     []string
+		filter []XattrFilterEntry
+		out    []string
+	}{
+		{in: nil, filter: nil, out: nil},
+		{in: []string{"foo", "bar", "baz"}, filter: nil, out: []string{"foo", "bar", "baz"}},
+		{
+			in:     []string{"foo", "bar", "baz"},
+			filter: []XattrFilterEntry{{Match: "b*", Permit: true}},
+			out:    []string{"bar", "baz"},
+		},
+		{
+			in:     []string{"foo", "bar", "baz"},
+			filter: []XattrFilterEntry{{Match: "b*", Permit: false}, {Match: "*", Permit: true}},
+			out:    []string{"foo"},
+		},
+		{
+			in:     []string{"foo", "bar", "baz"},
+			filter: []XattrFilterEntry{{Match: "yoink", Permit: true}},
+			out:    []string{},
+		},
+	}
+
+	for _, tc := range cases {
+		f := XattrFilter{Entries: tc.filter}
+		var out []string
+		for _, s := range tc.in {
+			if f.Permit(s) {
+				out = append(out, s)
+			}
+		}
+
+		if fmt.Sprint(out) != fmt.Sprint(tc.out) {
+			t.Errorf("Filter.Apply(%v, %v) == %v, expected %v", tc.in, tc.filter, out, tc.out)
+		}
+	}
+}
diff --git a/lib/fs/basicfs_test.go b/lib/fs/basicfs_test.go
index 467cbf719ab..36679500a57 100644
--- a/lib/fs/basicfs_test.go
+++ b/lib/fs/basicfs_test.go
@@ -7,6 +7,9 @@
 package fs
 
 import (
+	"bytes"
+	"errors"
+	"fmt"
 	"os"
 	"path/filepath"
 	"sort"
@@ -16,6 +19,7 @@ import (
 	"time"
 
 	"github.com/syncthing/syncthing/lib/build"
+	"github.com/syncthing/syncthing/lib/protocol"
 	"github.com/syncthing/syncthing/lib/rand"
 )
 
@@ -565,6 +569,87 @@ func TestRel(t *testing.T) {
 	}
 }
 
+func TestXattr(t *testing.T) {
+	tfs, _ := setup(t)
+	if err := tfs.Mkdir("/test", 0755); err != nil {
+		t.Fatal(err)
+	}
+
+	xattrSize := func() int { return 20 + rand.Intn(20) }
+
+	// Create a set of random attributes that we will set and read back
+	var attrs []protocol.Xattr
+	for i := 0; i < 10; i++ {
+		key := fmt.Sprintf("user.test-%d", i)
+		value := make([]byte, xattrSize())
+		rand.Read(value)
+		attrs = append(attrs, protocol.Xattr{
+			Name:  key,
+			Value: value,
+		})
+	}
+
+	// Set the xattrs, read them back and compare
+	if err := tfs.SetXattr("/test", attrs, noopXattrFilter{}); errors.Is(err, ErrXattrsNotSupported) {
+		t.Skip("xattrs not supported")
+	} else if err != nil {
+		t.Fatal(err)
+	}
+	res, err := tfs.GetXattr("/test", noopXattrFilter{})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(res) != len(attrs) {
+		t.Fatalf("length of returned xattrs does not match (%d != %d)", len(res), len(attrs))
+	}
+	for i, xa := range res {
+		if xa.Name != attrs[i].Name {
+			t.Errorf("xattr name %q != %q", xa.Name, attrs[i].Name)
+		}
+		if !bytes.Equal(xa.Value, attrs[i].Value) {
+			t.Errorf("xattr value %q != %q", xa.Value, attrs[i].Value)
+		}
+	}
+
+	// Remove a couple, change a couple, and add another couple of
+	// attributes. Replacing the xattrs again should work.
+	attrs = attrs[2:]
+	attrs[1].Value = make([]byte, xattrSize())
+	rand.Read(attrs[1].Value)
+	attrs[3].Value = make([]byte, xattrSize())
+	rand.Read(attrs[3].Value)
+	for i := 10; i < 12; i++ {
+		key := fmt.Sprintf("user.test-%d", i)
+		value := make([]byte, xattrSize())
+		rand.Read(value)
+		attrs = append(attrs, protocol.Xattr{
+			Name:  key,
+			Value: value,
+		})
+	}
+	sort.Slice(attrs, func(i, j int) bool { return attrs[i].Name < attrs[j].Name })
+
+	// Set the xattrs, read them back and compare
+	if err := tfs.SetXattr("/test", attrs, noopXattrFilter{}); err != nil {
+		t.Fatal(err)
+	}
+	res, err = tfs.GetXattr("/test", noopXattrFilter{})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(res) != len(attrs) {
+		t.Fatalf("length of returned xattrs does not match (%d != %d)", len(res), len(attrs))
+	}
+	for i, xa := range res {
+		if xa.Name != attrs[i].Name {
+			t.Errorf("xattr name %q != %q", xa.Name, attrs[i].Name)
+		}
+		if !bytes.Equal(xa.Value, attrs[i].Value) {
+			t.Errorf("xattr value %q != %q", xa.Value, attrs[i].Value)
+		}
+	}
+}
+
 func TestBasicWalkSkipSymlink(t *testing.T) {
 	_, dir := setup(t)
 	testWalkSkipSymlink(t, FilesystemTypeBasic, dir)
@@ -579,3 +664,9 @@ func TestWalkInfiniteRecursion(t *testing.T) {
 	_, dir := setup(t)
 	testWalkInfiniteRecursion(t, FilesystemTypeBasic, dir)
 }
+
+type noopXattrFilter struct{}
+
+func (noopXattrFilter) Permit(string) bool         { return true }
+func (noopXattrFilter) GetMaxSingleEntrySize() int { return 0 }
+func (noopXattrFilter) GetMaxTotalSize() int       { return 0 }
diff --git a/lib/model/folder_sendrecv_test.go b/lib/model/folder_sendrecv_test.go
index cdf38fdd4a1..bc8c14a69a4 100644
--- a/lib/model/folder_sendrecv_test.go
+++ b/lib/model/folder_sendrecv_test.go
@@ -21,6 +21,7 @@ import (
 	"time"
 
 	"github.com/syncthing/syncthing/lib/build"
+	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/events"
 	"github.com/syncthing/syncthing/lib/fs"
 	"github.com/syncthing/syncthing/lib/ignore"
@@ -83,7 +84,7 @@ func createEmptyFileInfo(t *testing.T, name string, fs fs.Filesystem) protocol.F
 	writeFile(t, fs, name, nil)
 	fi, err := fs.Stat(name)
 	must(t, err)
-	file, err := scanner.CreateFileInfo(fi, name, fs, false)
+	file, err := scanner.CreateFileInfo(fi, name, fs, false, false, config.XattrFilter{})
 	must(t, err)
 	return file
 }
@@ -777,9 +778,12 @@ func TestDeleteIgnorePerms(t *testing.T) {
 
 	stat, err := file.Stat()
 	must(t, err)
-	fi, err := scanner.CreateFileInfo(stat, name, ffs, false)
+	fi, err := scanner.CreateFileInfo(stat, name, ffs, false, false, config.XattrFilter{})
 	must(t, err)
 	ffs.Chmod(name, 0600)
+	if info, err := ffs.Stat(name); err == nil {
+		fi.InodeChangeNs = info.InodeChangeTime().UnixNano()
+	}
 	scanChan := make(chan string, 1)
 	err = f.checkToBeDeleted(fi, fi, true, scanChan)
 	must(t, err)
diff --git a/lib/model/model_test.go b/lib/model/model_test.go
index 37c7eeb61d0..725409d6e91 100644
--- a/lib/model/model_test.go
+++ b/lib/model/model_test.go
@@ -3216,10 +3216,28 @@ func TestConnCloseOnRestart(t *testing.T) {
 }
 
 func TestModTimeWindow(t *testing.T) {
+	// This test doesn't work any more, because changing the file like we do
+	// in the test below changes the inode time, which we detect
+	// (correctly). The test could be fixed by having a filesystem wrapper
+	// around fakeFs or basicFs that lies in the returned modtime (like FAT
+	// does...), but injecting such a wrapper isn't trivial. The filesystem
+	// is created by FolderConfiguration, so it would require a new
+	// filesystem type, which is really ugly, or creating a
+	// FilesystemFactory object that would create filesystems based on
+	// configs and would be injected into the model. But that's a major
+	// refactor. Adding a test-only override of the filesystem to the
+	// FolderConfiguration could be neat, but the FolderConfiguration is
+	// generated by protobuf so this is also a little tricky or at least
+	// ugly. I'm leaving it like this for now.
+	t.Skip("this test is currently broken")
+
 	w, fcfg, wCancel := tmpDefaultWrapper(t)
 	defer wCancel()
-	tfs := fcfg.Filesystem(nil)
-	fcfg.RawModTimeWindowS = 2
+	tfs := modtimeTruncatingFS{
+		trunc:      0,
+		Filesystem: fcfg.Filesystem(nil),
+	}
+	// fcfg.RawModTimeWindowS = 2
 	setFolder(t, w, fcfg)
 	m := setupModel(t, w)
 	defer cleanupModelAndRemoveDir(m, tfs.URI())
@@ -3243,10 +3261,12 @@ func TestModTimeWindow(t *testing.T) {
 	}
 	v := fi.Version
 
-	// Update time on disk 1s
+	// Change the filesystem to only return modtimes to the closest two
+	// seconds, like FAT.
 
-	err = tfs.Chtimes(name, time.Now(), modTime.Add(time.Second))
-	must(t, err)
+	tfs.trunc = 2 * time.Second
+
+	// Scan again
 
 	m.ScanFolders()
 
@@ -4305,3 +4325,41 @@ func equalStringsInAnyOrder(a, b []string) bool {
 	}
 	return true
 }
+
+// modtimeTruncatingFS is a FileSystem that returns modification times only
+// to the closest two `trunc` interval.
+type modtimeTruncatingFS struct {
+	trunc time.Duration
+	fs.Filesystem
+}
+
+func (f modtimeTruncatingFS) Lstat(name string) (fs.FileInfo, error) {
+	fmt.Println("lstat", name)
+	info, err := f.Filesystem.Lstat(name)
+	return modtimeTruncatingFileInfo{trunc: f.trunc, FileInfo: info}, err
+}
+
+func (f modtimeTruncatingFS) Stat(name string) (fs.FileInfo, error) {
+	fmt.Println("stat", name)
+	info, err := f.Filesystem.Stat(name)
+	return modtimeTruncatingFileInfo{trunc: f.trunc, FileInfo: info}, err
+}
+
+func (f modtimeTruncatingFS) Walk(root string, walkFn fs.WalkFunc) error {
+	return f.Filesystem.Walk(root, func(path string, info fs.FileInfo, err error) error {
+		if err != nil {
+			return walkFn(path, nil, err)
+		}
+		fmt.Println("walk", info.Name())
+		return walkFn(path, modtimeTruncatingFileInfo{trunc: f.trunc, FileInfo: info}, nil)
+	})
+}
+
+type modtimeTruncatingFileInfo struct {
+	trunc time.Duration
+	fs.FileInfo
+}
+
+func (fi modtimeTruncatingFileInfo) ModTime() time.Time {
+	return fi.FileInfo.ModTime().Truncate(fi.trunc)
+}
diff --git a/lib/scanner/virtualfs_test.go b/lib/scanner/virtualfs_test.go
index bd672bff0a2..4b97e2e5295 100644
--- a/lib/scanner/virtualfs_test.go
+++ b/lib/scanner/virtualfs_test.go
@@ -55,7 +55,7 @@ func (i infiniteFS) Open(name string) (fs.File, error) {
 	return &fakeFile{name, i.filesize, 0}, nil
 }
 
-func (infiniteFS) PlatformData(_ string) (protocol.PlatformData, error) {
+func (infiniteFS) PlatformData(_ string, _, _ bool, _ fs.XattrFilter) (protocol.PlatformData, error) {
 	return protocol.PlatformData{}, nil
 }
 
@@ -105,7 +105,7 @@ func (singleFileFS) Options() []fs.Option {
 	return nil
 }
 
-func (singleFileFS) PlatformData(_ string) (protocol.PlatformData, error) {
+func (singleFileFS) PlatformData(_ string, _, _ bool, _ fs.XattrFilter) (protocol.PlatformData, error) {
 	return protocol.PlatformData{}, nil
 }
 
@@ -121,10 +121,12 @@ func (fakeInfo) ModTime() time.Time { return time.Unix(1234567890, 0) }
 func (f fakeInfo) IsDir() bool {
 	return strings.Contains(filepath.Base(f.name), "dir") || f.name == "."
 }
-func (f fakeInfo) IsRegular() bool { return !f.IsDir() }
-func (fakeInfo) IsSymlink() bool   { return false }
-func (fakeInfo) Owner() int        { return 0 }
-func (fakeInfo) Group() int        { return 0 }
+func (f fakeInfo) IsRegular() bool          { return !f.IsDir() }
+func (fakeInfo) IsSymlink() bool            { return false }
+func (fakeInfo) Owner() int                 { return 0 }
+func (fakeInfo) Group() int                 { return 0 }
+func (fakeInfo) Sys() interface{}           { return nil }
+func (fakeInfo) InodeChangeTime() time.Time { return time.Time{} }
 
 type fakeFile struct {
 	name       string