all: Add configurable defaults (fixes #4224, fixes #6086) (#7131)

This commit is contained in:
Simon Frei 2021-02-04 21:10:41 +01:00 committed by GitHub
parent 31119ed61a
commit ffc14a77c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1708 additions and 1046 deletions

1
go.mod
View File

@ -17,6 +17,7 @@ require (
github.com/gobwas/glob v0.2.3
github.com/gogo/protobuf v1.3.1
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
github.com/golang/protobuf v1.4.3
github.com/greatroar/blobloom v0.5.0
github.com/hashicorp/golang-lru v0.5.1
github.com/jackpal/gateway v1.0.6

View File

@ -554,7 +554,7 @@
<button type="button" class="btn btn-sm btn-default" ng-click="rescanFolder(folder.id)" ng-disabled="['idle', 'stopped', 'unshared', 'outofsync', 'faileditems', 'localadditions'].indexOf(folderStatus(folder)) < 0">
<span class="fas fa-refresh"></span>&nbsp;<span translate>Rescan</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="editFolder(folder)">
<button type="button" class="btn btn-sm btn-default" ng-click="editFolderExisting(folder)">
<span class="fas fa-pencil-alt"></span>&nbsp;<span translate>Edit</span>
</button>
</span>
@ -821,7 +821,7 @@
<button ng-if="deviceCfg.paused" type="button" class="btn btn-sm btn-default" ng-click="setDevicePause(deviceCfg.deviceID, false)">
<span class="fas fa-play"></span>&nbsp;<span translate>Resume</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="editDevice(deviceCfg)">
<button type="button" class="btn btn-sm btn-default" ng-click="editDeviceExisting(deviceCfg)">
<span class="fas fa-pencil-alt"></span>&nbsp;<span translate>Edit</span>
</button>
</span>

View File

@ -52,6 +52,7 @@ angular.module('syncthing.core')
$scope.metricRates = false;
$scope.folderPathErrors = {};
$scope.currentFolder = {};
$scope.currentDevice = {};
$scope.ignores = {
text: '',
error: null,
@ -63,17 +64,8 @@ angular.module('syncthing.core')
$scope.metricRates = (window.localStorage["metricRates"] == "true");
} catch (exception) { }
$scope.folderDefaults = {
devices: [],
type: "sendreceive",
rescanIntervalS: 3600,
fsWatcherDelayS: 10,
fsWatcherEnabled: true,
minDiskFree: { value: 1, unit: "%" },
maxConflicts: 10,
fsync: true,
order: "random",
fileVersioningSelector: "none",
$scope.versioningDefaults = {
selector: "none",
trashcanClean: 0,
versioningCleanupIntervalS: 3600,
simpleKeep: 5,
@ -81,8 +73,6 @@ angular.module('syncthing.core')
staggeredCleanInterval: 3600,
staggeredVersionsPath: "",
externalCommand: "",
autoNormalize: true,
path: "",
};
$scope.localStateTotal = {
@ -727,7 +717,7 @@ angular.module('syncthing.core')
}
function shouldSetDefaultFolderPath() {
return $scope.config.options && $scope.config.options.defaultFolderPath && !$scope.editingExisting && $scope.folderEditor.folderPath.$pristine
return $scope.config.defaults.folder.path && !$scope.editingExisting && $scope.folderEditor.folderPath.$pristine && !$scope.editingDefaults;
}
function resetRemoteNeed() {
@ -769,8 +759,23 @@ angular.module('syncthing.core')
$scope.currentSharing.shared = [];
$scope.currentSharing.unrelated = [];
$scope.currentSharing.selected = {};
if (editing === 'folder') {
initShareEditingFolder();
}
};
function initShareEditingFolder() {
$scope.currentFolder.devices.forEach(function (n) {
if (n.deviceID !== $scope.myID) {
$scope.currentSharing.shared.push($scope.devices[n.deviceID]);
}
$scope.currentSharing.selected[n.deviceID] = true;
});
$scope.currentSharing.unrelated = $scope.deviceList().filter(function (n) {
return n.deviceID !== $scope.myID && !$scope.currentSharing.selected[n.deviceID];
});
}
$scope.refreshFailed = function (page, perpage) {
if (!$scope.failed || !$scope.failed.folder) {
return;
@ -1493,9 +1498,40 @@ angular.module('syncthing.core')
$scope.configInSync = true;
};
$scope.editDevice = function (deviceCfg) {
function editDeviceModal() {
$scope.currentDevice._addressesStr = $scope.currentDevice.addresses.join(', ');
$scope.deviceEditor.$setPristine();
$('#editDevice').modal();
}
$scope.editDeviceModalTitle = function() {
if ($scope.editingDefaults) {
return $translate.instant("Edit Device Defaults");
}
var title = '';
if ($scope.editingExisting) {
title += $translate.instant("Edit Device");
} else {
title += $translate.instant("Add Device");
}
var name = $scope.deviceName($scope.currentDevice);
if (name !== '') {
title += ' (' + name + ')';
}
return title;
};
$scope.editDeviceModalIcon = function() {
if ($scope.editingDefaults || $scope.editingExisting) {
return 'fas fa-pencil-alt';
}
return 'fas fa-desktop';
};
$scope.editDeviceExisting = function (deviceCfg) {
$scope.currentDevice = $.extend({}, deviceCfg);
$scope.editingExisting = true;
$scope.editingDefaults = false;
$scope.willBeReintroducedBy = undefined;
if (deviceCfg.introducedBy) {
var introducerDevice = $scope.devices[deviceCfg.introducedBy];
@ -1503,7 +1539,6 @@ angular.module('syncthing.core')
$scope.willBeReintroducedBy = $scope.deviceName(introducerDevice);
}
}
$scope.currentDevice._addressesStr = deviceCfg.addresses.join(', ');
initShareEditing('device');
$scope.deviceFolders($scope.currentDevice).forEach(function (folderID) {
$scope.currentSharing.shared.push($scope.folders[folderID]);
@ -1512,8 +1547,15 @@ angular.module('syncthing.core')
$scope.currentSharing.unrelated = $scope.folderList().filter(function (n) {
return !$scope.currentSharing.selected[n.id];
});
$scope.deviceEditor.$setPristine();
$('#editDevice').modal();
editDeviceModal();
};
$scope.editDeviceDefaults = function () {
$http.get(urlbase + '/config/defaults/device').then(function (p) {
$scope.currentDevice = p.data;
$scope.editingDefaults = true;
editDeviceModal();
}, $scope.emitHTTPError);
};
$scope.selectAllSharedFolders = function (state) {
@ -1545,19 +1587,16 @@ angular.module('syncthing.core')
}
})
.then(function () {
$scope.currentDevice = {
name: name,
deviceID: deviceID,
_addressesStr: 'dynamic',
compression: 'metadata',
introducer: false,
ignoredFolders: []
};
$scope.editingExisting = false;
initShareEditing('device');
$scope.currentSharing.unrelated = $scope.folderList();
$scope.deviceEditor.$setPristine();
$('#editDevice').modal();
$http.get(urlbase + '/config/defaults/device').then(function (p) {
$scope.currentDevice = p.data;
$scope.currentDevice.name = name;
$scope.currentDevice.deviceID = deviceID;
$scope.editingExisting = false;
$scope.editingDefaults = false;
initShareEditing('device');
$scope.currentSharing.unrelated = $scope.folderList();
editDeviceModal();
}, $scope.emitHTTPError);
});
};
@ -1582,22 +1621,30 @@ angular.module('syncthing.core')
$scope.saveDevice = function () {
$('#editDevice').modal('hide');
$scope.saveDeviceConfig($scope.currentDevice);
};
$scope.saveDeviceConfig = function (deviceCfg) {
deviceCfg.addresses = deviceCfg._addressesStr.split(',').map(function (x) {
$scope.currentDevice.addresses = $scope.currentDevice._addressesStr.split(',').map(function (x) {
return x.trim();
});
delete $scope.currentDevice._addressesStr;
if ($scope.editingDefaults) {
$scope.config.defaults.device = $scope.currentDevice;
} else {
setDeviceConfig();
}
delete $scope.currentSharing;
delete $scope.currentDevice;
$scope.saveConfig();
};
$scope.devices[deviceCfg.deviceID] = deviceCfg;
function setDeviceConfig() {
var currentID = $scope.currentDevice.DeviceID;
$scope.devices[currentID] = $scope.currentDevice;
$scope.config.devices = deviceList($scope.devices);
for (var id in $scope.currentSharing.selected) {
if ($scope.currentSharing.selected[id]) {
var found = false;
for (i = 0; i < $scope.folders[id].devices.length; i++) {
if ($scope.folders[id].devices[i].deviceID === deviceCfg.deviceID) {
if ($scope.folders[id].devices[i].deviceID === currentID) {
found = true;
break;
}
@ -1606,21 +1653,18 @@ angular.module('syncthing.core')
if (!found) {
// Add device to folder
$scope.folders[id].devices.push({
deviceID: deviceCfg.deviceID
deviceID: currentID,
});
}
} else {
// Remove device from folder
$scope.folders[id].devices = $scope.folders[id].devices.filter(function (n) {
return n.deviceID !== deviceCfg.deviceID;
return n.deviceID !== currentID;
});
}
}
delete $scope.currentSharing;
$scope.config.folders = folderList($scope.folders);
$scope.saveConfig();
};
$scope.ignoreDevice = function (deviceID, pendingDevice) {
@ -1757,14 +1801,14 @@ angular.module('syncthing.core')
if (!newvalue || !shouldSetDefaultFolderPath()) {
return;
}
$scope.currentFolder.path = pathJoin($scope.config.options.defaultFolderPath, newvalue);
$scope.currentFolder.path = pathJoin($scope.config.defaults.folder.path, newvalue);
});
$scope.$watch('currentFolder.id', function (newvalue) {
if (!newvalue || !shouldSetDefaultFolderPath() || $scope.currentFolder.label) {
return;
}
$scope.currentFolder.path = pathJoin($scope.config.options.defaultFolderPath, newvalue);
$scope.currentFolder.path = pathJoin($scope.config.defaults.folder.path, newvalue);
});
$scope.fsWatcherToggled = function () {
@ -1791,7 +1835,8 @@ angular.module('syncthing.core')
$('#globalChanges').modal();
};
$scope.editFolderModal = function () {
function editFolderModal() {
initVersioningEditing();
$scope.folderPathErrors = {};
$scope.folderEditor.$setPristine();
$('#editFolder').modal().one('shown.bs.tab', function (e) {
@ -1804,64 +1849,78 @@ angular.module('syncthing.core')
});
};
$scope.editFolder = function (folderCfg) {
$scope.editingExisting = true;
$scope.currentFolder = angular.copy(folderCfg);
$scope.editFolderModalTitle = function() {
if ($scope.editingDefaults) {
return $translate.instant("Edit Folder Defaults");
}
var title = '';
if ($scope.editingExisting) {
title += $translate.instant("Edit Folder");
} else {
title += $translate.instant("Add Folder");
}
if ($scope.currentFolder.id !== '') {
title += ' (' + $scope.folderLabel($scope.currentFolder.id) + ')';
}
return title;
};
$scope.editFolderModalIcon = function() {
if ($scope.editingDefaults || $scope.editingExisting) {
return 'fas fa-pencil-alt';
}
return 'fas fa-folder';
};
function editFolder() {
if ($scope.currentFolder.path.length > 1 && $scope.currentFolder.path.slice(-1) === $scope.system.pathSeparator) {
$scope.currentFolder.path = $scope.currentFolder.path.slice(0, -1);
} else if (!$scope.currentFolder.path) {
// undefined path leads to invalid input field
$scope.currentFolder.path = '';
}
// Cache complete device objects indexed by ID for lookups
initShareEditing('folder');
$scope.currentFolder.devices.forEach(function (n) {
if (n.deviceID !== $scope.myID) {
$scope.currentSharing.shared.push($scope.devices[n.deviceID]);
}
$scope.currentSharing.selected[n.deviceID] = true;
});
$scope.currentSharing.unrelated = $scope.deviceList().filter(function (n) {
return n.deviceID !== $scope.myID && !$scope.currentSharing.selected[n.deviceID];
});
if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "trashcan") {
$scope.currentFolder.trashcanFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "trashcan";
$scope.currentFolder.trashcanClean = +$scope.currentFolder.versioning.params.cleanoutDays;
$scope.currentFolder.versioningCleanupIntervalS = +$scope.currentFolder.versioning.cleanupIntervalS;
} else if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "simple") {
$scope.currentFolder.simpleFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "simple";
$scope.currentFolder.simpleKeep = +$scope.currentFolder.versioning.params.keep;
$scope.currentFolder.versioningCleanupIntervalS = +$scope.currentFolder.versioning.cleanupIntervalS;
$scope.currentFolder.trashcanClean = +$scope.currentFolder.versioning.params.cleanoutDays;
} else if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "staggered") {
$scope.currentFolder.staggeredFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "staggered";
$scope.currentFolder.staggeredMaxAge = Math.floor(+$scope.currentFolder.versioning.params.maxAge / 86400);
$scope.currentFolder.staggeredCleanInterval = +$scope.currentFolder.versioning.params.cleanInterval;
$scope.currentFolder.staggeredVersionsPath = $scope.currentFolder.versioning.params.versionsPath;
$scope.currentFolder.versioningCleanupIntervalS = +$scope.currentFolder.versioning.cleanupIntervalS;
} else if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "external") {
$scope.currentFolder.externalFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "external";
$scope.currentFolder.externalCommand = $scope.currentFolder.versioning.params.command;
} else {
$scope.currentFolder.fileVersioningSelector = "none";
}
$scope.currentFolder.trashcanClean = $scope.currentFolder.trashcanClean || 0; // weeds out nulls and undefineds
$scope.currentFolder.simpleKeep = $scope.currentFolder.simpleKeep || 5;
$scope.currentFolder.staggeredCleanInterval = $scope.currentFolder.staggeredCleanInterval || 3600;
$scope.currentFolder.staggeredVersionsPath = $scope.currentFolder.staggeredVersionsPath || "";
// Zero is a valid, non-default value (disabled)
if ($scope.currentFolder.versioningCleanupIntervalS !== 0) {
$scope.currentFolder.versioningCleanupIntervalS = $scope.currentFolder.versioningCleanupIntervalS || 3600;
editFolderModal();
}
function initVersioningEditing() {
$scope.currentFolder._guiVersioning = angular.copy($scope.versioningDefaults);
if (!$scope.currentFolder.versioning) {
return;
}
// staggeredMaxAge can validly be zero, which we should not replace
// with the default value of 365. So only set the default if it's
// actually undefined.
if (typeof $scope.currentFolder.staggeredMaxAge === 'undefined') {
$scope.currentFolder.staggeredMaxAge = 365;
var currentVersioning = $scope.currentFolder.versioning;
$scope.currentFolder._guiVersioning.cleanupIntervalS = +currentVersioning.cleanupIntervalS;
// Apply parameters currently in use
switch (currentVersioning.type) {
case "trashcan":
$scope.currentFolder._guiVersioning.selector = "trashcan";
$scope.currentFolder._guiVersioning.trashcanClean = +currentVersioning.params.cleanoutDays;
break;
case "simple":
$scope.currentFolder._guiVersioning.selector = "simple";
$scope.currentFolder._guiVersioning.simpleKeep = +currentVersioning.params.keep;
$scope.currentFolder._guiVersioning.trashcanClean = +currentVersioning.params.cleanoutDays;
break;
case "staggered":
$scope.currentFolder._guiVersioning.selector = "staggered";
$scope.currentFolder._guiVersioning.staggeredMaxAge = Math.floor(+currentVersioning.params.maxAge / 86400);
$scope.currentFolder._guiVersioning.staggeredCleanInterval = +currentVersioning.params.cleanInterval;
$scope.currentFolder._guiVersioning.staggeredVersionsPath = currentVersioning.params.versionsPath;
break;
case "external":
$scope.currentFolder._guiVersioning.selector = "external";
$scope.currentFolder.externalCommand = currentVersioning.params.command;
break;
}
$scope.currentFolder.externalCommand = $scope.currentFolder.externalCommand || "";
};
$scope.editFolderExisting = function(folderCfg) {
$scope.editingExisting = true;
$scope.currentFolder = angular.copy(folderCfg);
$scope.ignores.text = 'Loading...';
$scope.ignores.error = null;
@ -1878,7 +1937,18 @@ angular.module('syncthing.core')
$scope.emitHTTPError(err);
});
$scope.editFolderModal();
editFolder();
};
$scope.editFolderDefaults = function() {
$http.get(urlbase + '/config/defaults/folder')
.success(function (data) {
$scope.currentFolder = data;
$scope.editingExisting = false;
$scope.editingDefaults = true;
editFolder();
})
.error($scope.emitHTTPError);
};
$scope.selectAllSharedDevices = function (state) {
@ -1897,37 +1967,43 @@ angular.module('syncthing.core')
$scope.addFolder = function () {
$http.get(urlbase + '/svc/random/string?length=10').success(function (data) {
$scope.editingExisting = false;
$scope.currentFolder = angular.copy($scope.folderDefaults);
initShareEditing('folder');
$scope.currentFolder.id = (data.random.substr(0, 5) + '-' + data.random.substr(5, 5)).toLowerCase();
$scope.currentSharing.unrelated = $scope.otherDevices();
$scope.ignores.text = '';
$scope.ignores.error = null;
$scope.ignores.disabled = false;
$scope.editFolderModal();
var folderID = (data.random.substr(0, 5) + '-' + data.random.substr(5, 5)).toLowerCase();
addFolderInit(folderID).then(function() {
// Triggers the watch that sets the path
$scope.currentFolder.label = $scope.currentFolder.label;
editFolderModal();
});
});
};
$scope.addFolderAndShare = function (folder, folderLabel, device) {
$scope.editingExisting = false;
$scope.currentFolder = angular.copy($scope.folderDefaults);
$scope.currentFolder.id = folder;
$scope.currentFolder.label = folderLabel;
$scope.currentFolder.viewFlags = {
importFromOtherDevice: true
};
initShareEditing('folder');
$scope.currentSharing.selected[device] = true;
$scope.currentSharing.unrelated = $scope.deviceList().filter(function (n) {
return n.deviceID !== $scope.myID;
$scope.addFolderAndShare = function (folderID, folderLabel, device) {
addFolderInit(folderID).then(function() {
$scope.currentFolder.viewFlags = {
importFromOtherDevice: true
};
$scope.currentSharing.selected[device] = true;
$scope.currentFolder.label = folderLabel;
editFolderModal();
});
$scope.ignores.text = '';
$scope.ignores.error = null;
$scope.ignores.disabled = false;
$scope.editFolderModal();
};
function addFolderInit(folderID) {
$scope.editingExisting = false;
$scope.editingDefaults = false;
return $http.get(urlbase + '/config/defaults/folder').then(function(p) {
$scope.currentFolder = p.data;
$scope.currentFolder.id = folderID;
initShareEditing('folder');
$scope.currentSharing.unrelated = $scope.currentSharing.unrelated.concat($scope.currentSharing.shared);
$scope.currentSharing.shared = [];
$scope.ignores.text = '';
$scope.ignores.error = null;
$scope.ignores.disabled = false;
}, $scope.emitHTTPError);
}
$scope.shareFolderWithDevice = function (folder, device) {
$scope.folders[folder].devices.push({
deviceID: device
@ -1957,55 +2033,60 @@ angular.module('syncthing.core')
folderCfg.devices = newDevices;
delete $scope.currentSharing;
if (folderCfg.fileVersioningSelector === "trashcan") {
switch (folderCfg._guiVersioning.selector) {
case "trashcan":
folderCfg.versioning = {
'type': 'trashcan',
'params': {
'cleanoutDays': '' + folderCfg.trashcanClean
'cleanoutDays': '' + folderCfg._guiVersioning.trashcanClean
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.trashcanFileVersioning;
delete folderCfg.trashcanClean;
} else if (folderCfg.fileVersioningSelector === "simple") {
break;
case "simple":
folderCfg.versioning = {
'type': 'simple',
'params': {
'keep': '' + folderCfg.simpleKeep,
'cleanoutDays': '' + folderCfg.trashcanClean
'keep': '' + folderCfg._guiVersioning.simpleKeep,
'cleanoutDays': '' + folderCfg._guiVersioning.trashcanClean
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.simpleFileVersioning;
delete folderCfg.simpleKeep;
} else if (folderCfg.fileVersioningSelector === "staggered") {
break;
case "staggered":
folderCfg.versioning = {
'type': 'staggered',
'params': {
'maxAge': '' + (folderCfg.staggeredMaxAge * 86400),
'cleanInterval': '' + folderCfg.staggeredCleanInterval,
'versionsPath': '' + folderCfg.staggeredVersionsPath
'maxAge': '' + (folderCfg._guiVersioning.staggeredMaxAge * 86400),
'cleanInterval': '' + folderCfg._guiVersioning.staggeredCleanInterval,
'versionsPath': '' + folderCfg._guiVersioning.staggeredVersionsPath
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.staggeredFileVersioning;
delete folderCfg.staggeredMaxAge;
delete folderCfg.staggeredCleanInterval;
delete folderCfg.staggeredVersionsPath;
} else if (folderCfg.fileVersioningSelector === "external") {
break;
case "external":
folderCfg.versioning = {
'type': 'external',
'params': {
'command': '' + folderCfg.externalCommand
'command': '' + folderCfg._guiVersioning.externalCommand
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.externalFileVersioning;
delete folderCfg.externalCommand;
} else {
break;
default:
delete folderCfg.versioning;
}
delete folderCfg._guiVersioning;
if ($scope.editingDefaults) {
$scope.config.defaults.folder = folderCfg;
$scope.saveConfig();
} else {
saveFolderExisting(folderCfg);
}
};
function saveFolderExisting(folderCfg) {
var ignoresLoaded = !$scope.ignores.disabled;
var ignores = $scope.ignores.text.split('\n');
// Split always returns a minimum 1-length array even for no patterns

View File

@ -1,14 +1,14 @@
<modal id="editDevice" status="default" icon="{{editingExisting ? 'fas fa-pencil-alt' : 'fas fa-desktop'}}" heading="{{editingExisting ? 'Edit Device' : 'Add Device' | translate}} {{currentDevice.name}}" large="yes" closeable="yes">
<modal id="editDevice" status="default" icon="{{editDeviceModalIcon()}}" heading="{{editDeviceModalTitle()}}" large="yes" closeable="yes">
<div class="modal-body">
<form role="form" name="deviceEditor">
<ul class="nav nav-tabs" ng-init="loadFormIntoScope(deviceEditor)">
<li class="active"><a data-toggle="tab" href="#device-general"><span class="fas fa-cog"></span> <span translate>General</span></a></li>
<li><a data-toggle="tab" href="#device-sharing"><span class="fas fa-share-alt"></span> <span translate>Sharing</span></a></li>
<li ng-if="!editingDefaults"><a data-toggle="tab" href="#device-sharing"><span class="fas fa-share-alt"></span> <span translate>Sharing</span></a></li>
<li><a data-toggle="tab" href="#device-advanced"><span class="fas fa-cogs"></span> <span translate>Advanced</span></a></li>
</ul>
<div class="tab-content">
<div id="device-general" class="tab-pane in active">
<div class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}" ng-init="loadFormIntoScope(deviceEditor)">
<div ng-if="!editingDefaults" class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}" ng-init="loadFormIntoScope(deviceEditor)">
<label translate for="deviceID">Device ID</label>
<div ng-if="!editingExisting">
<input name="deviceID" id="deviceID" class="form-control text-monospace" type="text" ng-model="currentDevice.deviceID" required="" valid-deviceid list="discovery-list" aria-required="true" />
@ -38,7 +38,7 @@
<p translate ng-if="currentDevice.deviceID != myID" class="help-block">Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.</p>
</div>
</div>
<div id="device-sharing" class="tab-pane">
<div ng-if="!editingDefaults" id="device-sharing" class="tab-pane">
<div class="row">
<div class="col-md-6">
<div class="form-group">
@ -164,13 +164,13 @@
<button type="button" class="btn btn-primary btn-sm" ng-click="saveDevice()" ng-disabled="deviceEditor.$invalid">
<span class="fas fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#idqr" ng-if="editingExisting || deviceEditor.deviceID.$valid">
<button ng-if="!editingDefaults" type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#idqr" ng-if="editingExisting || deviceEditor.deviceID.$valid">
<span class="fas fa-qrcode"></span>&nbsp;<span translate>Show QR</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fas fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<div ng-if="editingExisting" class="pull-left">
<div ng-if="editingExisting && !editingDefaults" class="pull-left">
<button type="button" class="btn btn-warning btn-sm" data-toggle="modal" data-target="#remove-device-confirmation">
<span class="fas fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>

View File

@ -1,24 +1,24 @@
<modal id="editFolder" status="default" icon="{{editingExisting ? 'fas fa-pencil-alt' : 'fas fa-folder'}}" heading="{{editingExisting ? 'Edit Folder' : 'Add Folder' | translate}} ({{folderLabel(currentFolder.id)}})" large="yes" closeable="yes">
<modal id="editFolder" status="default" icon="{{editFolderModalIcon()}}" heading="{{editFolderModalTitle()}}" large="yes" closeable="yes">
<div class="modal-body">
<form role="form" name="folderEditor">
<ul class="nav nav-tabs" ng-init="loadFormIntoScope(folderEditor)">
<li class="active"><a data-toggle="tab" href="#folder-general"><span class="fas fa-cog"></span> <span translate>General</span></a></li>
<li><a data-toggle="tab" href="#folder-sharing"><span class="fas fa-share-alt"></span> <span translate>Sharing</span></a></li>
<li><a data-toggle="tab" href="#folder-versioning"><span class="fas fa-copy"></span> <span translate>File Versioning</span></a></li>
<li><a data-toggle="tab" href="#folder-ignores"><span class="fas fa-filter"></span> <span translate>Ignore Patterns</span></a></li>
<li ng-if="!editingDefaults"><a data-toggle="tab" href="#folder-ignores"><span class="fas fa-filter"></span> <span translate>Ignore Patterns</span></a></li>
<li><a data-toggle="tab" href="#folder-advanced"><span class="fas fa-cogs"></span> <span translate>Advanced</span></a></li>
</ul>
<div class="tab-content">
<div id="folder-general" class="tab-pane in active">
<div class="form-group" ng-class="{'has-error': folderEditor.folderLabel.$invalid && folderEditor.folderLabel.$dirty}">
<div class="form-group" ng-class="{'has-error': folderEditor.folderLabel.$invalid && folderEditor.folderLabel.$dirty && !editingDefaults}">
<label for="folderLabel"><span translate>Folder Label</span></label>
<input name="folderLabel" id="folderLabel" class="form-control" type="text" ng-model="currentFolder.label" value="{{currentFolder.label}}" />
<p class="help-block">
<span translate ng-if="folderEditor.folderLabel.$valid || folderEditor.folderLabel.$pristine">Optional descriptive label for the folder. Can be different on each device.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<div ng-if="!editingDefaults" class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<label for="folderID"><span translate>Folder ID</span></label>
<input name="folderID" ng-readonly="editingExisting || (!editingExisting && currentFolder.viewFlags.importFromOtherDevice)" id="folderID" class="form-control" type="text" ng-model="currentFolder.id" required="" aria-required="true" unique-folder value="{{currentFolder.id}}" />
<p class="help-block">
@ -28,19 +28,21 @@
<span translate ng-show="!editingExisting">When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderPath.$invalid && folderEditor.folderPath.$dirty}">
<div class="form-group" ng-class="{'has-error': folderEditor.folderPath.$invalid && folderEditor.folderPath.$dirty && !editingDefaults}">
<label translate for="folderPath">Folder Path</label>
<input name="folderPath" ng-readonly="editingExisting" id="folderPath" class="form-control" type="text" ng-model="currentFolder.path" list="directory-list" required="" aria-required="true" path-is-sub-dir />
<input name="folderPath" ng-readonly="editingExisting && !editingDefaults" id="folderPath" class="form-control" type="text" ng-model="currentFolder.path" list="directory-list" ng-required="!editingDefaults" ng-aria-required="!editingDefaults" path-is-sub-dir />
<datalist id="directory-list">
<option ng-repeat="directory in directoryList" value="{{ directory }}" />
</datalist>
<p class="help-block">
<span ng-if="folderEditor.folderPath.$valid || folderEditor.folderPath.$pristine"><span translate>Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for</span> <code>{{system.tilde}}</code>.</br></span>
<span translate ng-if="folderEditor.folderPath.$error.required && folderEditor.folderPath.$dirty">The folder path cannot be blank.</span>
<span translate ng-if="folderEditor.folderPath.$error.required && folderEditor.folderPath.$dirty && !editingDefaults">The folder path cannot be blank.</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" ng-if="folderPathErrors.isSub && folderPathErrors.otherLabel.length == 0">Warning, this path is a subdirectory of an existing folder "{%otherFolder%}".</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" translate-value-other-folder-label="{{folderPathErrors.otherLabel}}" ng-if="folderPathErrors.isSub && folderPathErrors.otherLabel.length != 0">Warning, this path is a subdirectory of an existing folder "{%otherFolderLabel%}" ({%otherFolder%}).</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" ng-if="folderPathErrors.isParent && folderPathErrors.otherLabel.length == 0">Warning, this path is a parent directory of an existing folder "{%otherFolder%}".</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" translate-value-other-folder-label="{{folderPathErrors.otherLabel}}" ng-if="folderPathErrors.isParent && folderPathErrors.otherLabel.length != 0">Warning, this path is a parent directory of an existing folder "{%otherFolderLabel%}" ({%otherFolder%}).</span>
<span ng-if="folderPathErrors.isParent && !editingDefaults">
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" ng-if="folderPathErrors.otherLabel.length == 0">Warning, this path is a parent directory of an existing folder "{%otherFolder%}".</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" translate-value-other-folder-label="{{folderPathErrors.otherLabel}}" ng-if="folderPathErrors.otherLabel.length != 0">Warning, this path is a parent directory of an existing folder "{%otherFolderLabel%}" ({%otherFolder%}).</span>
</span>
</p>
</div>
</div>
@ -88,7 +90,7 @@
<div id="folder-versioning" class="tab-pane">
<div class="form-group">
<label translate>File Versioning</label>&emsp;<a href="https://docs.syncthing.net/users/versioning.html" target="_blank"><span class="fas fa-question-circle"></span>&nbsp;<span translate>Help</span></a>
<select class="form-control" ng-model="currentFolder.fileVersioningSelector">
<select class="form-control" ng-model="currentFolder._guiVersioning.selector">
<option value="none" translate>No File Versioning</option>
<option value="trashcan" translate>Trash Can File Versioning</option>
<option value="simple" translate>Simple File Versioning</option>
@ -96,46 +98,46 @@
<option value="external" translate>External File Versioning</option>
</select>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='trashcan' || currentFolder.fileVersioningSelector=='simple'" ng-class="{'has-error': folderEditor.trashcanClean.$invalid && folderEditor.trashcanClean.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='trashcan' || currentFolder._guiVersioning.selectorector=='simple'" ng-class="{'has-error': folderEditor._guiVersioning.trashcanClean.$invalid && folderEditor._guiVersioning.trashcanClean.$dirty}">
<p translate class="help-block">Files are moved to .stversions directory when replaced or deleted by Syncthing.</p>
<label translate for="trashcanClean">Clean out after</label>
<div class="input-group">
<input name="trashcanClean" id="trashcanClean" class="form-control text-right" type="number" ng-model="currentFolder.trashcanClean" required="" aria-required="true" min="0" />
<input name="trashcanClean" id="trashcanClean" class="form-control text-right" type="number" ng-model="currentFolder._guiVersioning.trashcanClean" required="" aria-required="true" min="0" />
<div class="input-group-addon" translate>days</div>
</div>
<p class="help-block">
<span translate ng-if="folderEditor.trashcanClean.$valid || folderEditor.trashcanClean.$pristine">The number of days to keep files in the trash can. Zero means forever.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.required && folderEditor.trashcanClean.$dirty">The number of days must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.min && folderEditor.trashcanClean.$dirty">A negative number of days doesn't make sense.</span>
<span translate ng-if="folderEditor._guiVersioning.trashcanClean.$valid || folderEditor._guiVersioning.trashcanClean.$pristine">The number of days to keep files in the trash can. Zero means forever.</span>
<span translate ng-if="folderEditor._guiVersioning.trashcanClean.$error.required && folderEditor._guiVersioning.trashcanClean.$dirty">The number of days must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.trashcanClean.$error.min && folderEditor._guiVersioning.trashcanClean.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='simple'" ng-class="{'has-error': folderEditor.simpleKeep.$invalid && folderEditor.simpleKeep.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='simple'" ng-class="{'has-error': folderEditor._guiVersioning.simpleKeep.$invalid && folderEditor._guiVersioning.simpleKeep.$dirty}">
<p translate class="help-block">Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.</p>
<label translate for="simpleKeep">Keep Versions</label>
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentFolder.simpleKeep" required="" aria-required="true" min="1" />
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentFolder._guiVersioning.simpleKeep" required="" aria-required="true" min="1" />
<p class="help-block">
<span translate ng-if="folderEditor.simpleKeep.$valid || folderEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.required && folderEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.min && folderEditor.simpleKeep.$dirty">You must keep at least one version.</span>
<span translate ng-if="folderEditor._guiVersioning.simpleKeep.$valid || folderEditor._guiVersioning.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="folderEditor._guiVersioning.simpleKeep.$error.required && folderEditor._guiVersioning.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.simpleKeep.$error.min && folderEditor._guiVersioning.simpleKeep.$dirty">You must keep at least one version.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='staggered'" ng-class="{'has-error': folderEditor.staggeredMaxAge.$invalid && folderEditor.staggeredMaxAge.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='staggered'" ng-class="{'has-error': folderEditor._guiVersioning.staggeredMaxAge.$invalid && folderEditor._guiVersioning.staggeredMaxAge.$dirty}">
<p class="help-block"><span translate>Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.</span> <span translate>Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.</span></p>
<p translate class="help-block">The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.</p>
<label translate for="staggeredMaxAge">Maximum Age</label>
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentFolder.staggeredMaxAge" required="" aria-required="true" min="0" />
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentFolder._guiVersioning.staggeredMaxAge" required="" aria-required="true" min="0" />
<p class="help-block">
<span translate ng-if="folderEditor.staggeredMaxAge.$valid || folderEditor.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.required && folderEditor.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.min && folderEditor.staggeredMaxAge.$dirty">A negative number of days doesn't make sense.</span>
<span translate ng-if="folderEditor._guiVersioning.staggeredMaxAge.$valid || folderEditor._guiVersioning.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="folderEditor._guiVersioning.staggeredMaxAge.$error.required && folderEditor._guiVersioning.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.staggeredMaxAge.$error.min && folderEditor._guiVersioning.staggeredMaxAge.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector == 'staggered'">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector == 'staggered'">
<label translate for="staggeredVersionsPath">Versions Path</label>
<input name="staggeredVersionsPath" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentFolder.staggeredVersionsPath" />
<input name="staggeredVersionsPath" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentFolder._guiVersioning.staggeredVersionsPath" />
<p translate class="help-block">Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='external'" ng-class="{'has-error': folderEditor.externalCommand.$invalid && folderEditor.externalCommand.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='external'" ng-class="{'has-error': folderEditor.externalCommand.$invalid && folderEditor.externalCommand.$dirty}">
<p translate class="help-block">An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.</p>
<label translate for="externalCommand">Command</label>
<input name="externalCommand" id="externalCommand" class="form-control" type="text" ng-model="currentFolder.externalCommand" required="" aria-required="true" />
@ -144,21 +146,21 @@
<span translate ng-if="folderEditor.externalCommand.$error.required && folderEditor.externalCommand.$dirty">The path cannot be blank.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector != 'none'" ng-class="{'has-error': folderEditor.versioningCleanupIntervalS.$invalid && folderEditor.versioningCleanupIntervalS.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector != 'none'" ng-class="{'has-error': folderEditor._guiVersioning.cleanupIntervalS.$invalid && folderEditor._guiVersioning.cleanupIntervalS.$dirty}">
<label translate for="versioningCleanupIntervalS">Cleanup Interval</label>
<div class="input-group">
<input name="versioningCleanupIntervalS" id="versioningCleanupIntervalS" class="form-control text-right" type="number" ng-model="currentFolder.versioningCleanupIntervalS" required="" min="0" max="31536000" aria-required="true" />
<input name="versioningCleanupIntervalS" id="versioningCleanupIntervalS" class="form-control text-right" type="number" ng-model="currentFolder._guiVersioning.cleanupIntervalS" required="" min="0" max="31536000" aria-required="true" />
<div class="input-group-addon" translate>seconds</div>
</div>
<p class="help-block">
<span translate ng-if="folderEditor.versioningCleanupIntervalS.$valid || folderEditor.versioningCleanupIntervalS.$pristine"class="help-block">The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.</span>
<span translate ng-if="folderEditor.versioningCleanupIntervalS.$error.required && folderEditor.versioningCleanupIntervalS.$dirty">The cleanup interval cannot be blank.</span>
<span translate ng-if="folderEditor.versioningCleanupIntervalS.$error.min && folderEditor.versioningCleanupIntervalS.$dirty">The interval must be a positive number of seconds.</span>
<span translate ng-if="folderEditor._guiVersioning.cleanupIntervalS.$valid || folderEditor._guiVersioning.cleanupIntervalS.$pristine"class="help-block">The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.</span>
<span translate ng-if="folderEditor._guiVersioning.cleanupIntervalS.$error.required && folderEditor._guiVersioning.cleanupIntervalS.$dirty">The cleanup interval cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.cleanupIntervalS.$error.min && folderEditor._guiVersioning.cleanupIntervalS.$dirty">The interval must be a positive number of seconds.</span>
</p>
</div>
</div>
<div id="folder-ignores" class="tab-pane">
<div ng-if="!editingDefaults" id="folder-ignores" class="tab-pane">
<p translate>Enter ignore patterns, one per line.</p>
<div ng-class="{'has-error': ignores.error != null}">
<textarea class="form-control" rows="5" ng-model="ignores.text" ng-disabled="ignores.disabled"></textarea>
@ -280,7 +282,7 @@
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fas fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<button type="button" class="btn btn-warning pull-left btn-sm" data-toggle="modal" data-target="#remove-folder-confirmation" ng-if="editingExisting">
<button type="button" class="btn btn-warning pull-left btn-sm" data-toggle="modal" data-target="#remove-folder-confirmation" ng-if="editingExisting && !editingDefaults">
<span class="fas fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>
</div>

View File

@ -100,13 +100,15 @@
</div>
</div>
</div>
<div class="form-group">
<label translate for="urVersion">Default Folder Path</label>
<input id="DefaultFolderPath" class="form-control" type="text" ng-model="tmpOptions.defaultFolderPath" />
<p class="help-block">
<span translate translate-value-tilde="{{system.tilde}}">
Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.
</span>
<div>
<label translate>Default Configuration</label>
<p>
<button type="button" class="btn btn-default btn-secondary" ng-click="editFolderDefaults()">
<span translate>Edit Folder Defaults</span>
</button>
<button type="button" class="btn btn-default btn-secondary" ng-click="editDeviceDefaults()">
<span translate>Edit Device Defaults</span>
</button>
</p>
</div>
</div>

View File

@ -566,7 +566,7 @@
<button type="button" class="btn btn-sm btn-default" ng-click="rescanFolder(folder.id)" ng-disabled="['idle', 'stopped', 'unshared', 'outofsync', 'faileditems', 'localadditions'].indexOf(folderStatus(folder)) < 0">
<span class="fas fa-refresh"></span>&nbsp;<span translate>Rescan</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="editFolder(folder)">
<button type="button" class="btn btn-sm btn-default" ng-click="editFolderExisting(folder)">
<span class="fas fa-pencil-alt"></span>&nbsp;<span translate>Edit</span>
</button>
</span>
@ -833,7 +833,7 @@
<button ng-if="deviceCfg.paused" type="button" class="btn btn-sm btn-default" ng-click="setDevicePause(deviceCfg.deviceID, false)">
<span class="fas fa-play"></span>&nbsp;<span translate>Resume</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="editDevice(deviceCfg)">
<button type="button" class="btn btn-sm btn-default" ng-click="editDeviceExisting(deviceCfg)">
<span class="fas fa-pencil-alt"></span>&nbsp;<span translate>Edit</span>
</button>
</span>

View File

@ -52,6 +52,7 @@ angular.module('syncthing.core')
$scope.metricRates = false;
$scope.folderPathErrors = {};
$scope.currentFolder = {};
$scope.currentDevice = {};
$scope.ignores = {
text: '',
error: null,
@ -63,17 +64,8 @@ angular.module('syncthing.core')
$scope.metricRates = (window.localStorage["metricRates"] == "true");
} catch (exception) { }
$scope.folderDefaults = {
devices: [],
type: "sendreceive",
rescanIntervalS: 3600,
fsWatcherDelayS: 10,
fsWatcherEnabled: true,
minDiskFree: { value: 1, unit: "%" },
maxConflicts: 10,
fsync: true,
order: "random",
fileVersioningSelector: "none",
$scope.versioningDefaults = {
selector: "none",
trashcanClean: 0,
versioningCleanupIntervalS: 3600,
simpleKeep: 5,
@ -81,8 +73,6 @@ angular.module('syncthing.core')
staggeredCleanInterval: 3600,
staggeredVersionsPath: "",
externalCommand: "",
autoNormalize: true,
path: "",
};
$scope.localStateTotal = {
@ -727,7 +717,7 @@ angular.module('syncthing.core')
}
function shouldSetDefaultFolderPath() {
return $scope.config.options && $scope.config.options.defaultFolderPath && !$scope.editingExisting && $scope.folderEditor.folderPath.$pristine
return $scope.config.defaults.folder.path && !$scope.editingExisting && $scope.folderEditor.folderPath.$pristine && !$scope.editingDefaults;
}
function resetRemoteNeed() {
@ -770,8 +760,26 @@ angular.module('syncthing.core')
$scope.currentSharing.unrelated = [];
$scope.currentSharing.selected = {};
$scope.currentSharing.encryptionPasswords = {};
if (editing === 'folder') {
initShareEditingFolder();
}
};
function initShareEditingFolder() {
$scope.currentFolder.devices.forEach(function (n) {
if (n.deviceID !== $scope.myID) {
$scope.currentSharing.shared.push($scope.devices[n.deviceID]);
}
if (n.encryptionPassword !== '') {
$scope.currentSharing.encryptionPasswords[n.deviceID] = n.encryptionPassword;
}
$scope.currentSharing.selected[n.deviceID] = true;
});
$scope.currentSharing.unrelated = $scope.deviceList().filter(function (n) {
return n.deviceID !== $scope.myID && !$scope.currentSharing.selected[n.deviceID];
});
}
$scope.refreshFailed = function (page, perpage) {
if (!$scope.failed || !$scope.failed.folder) {
return;
@ -1239,6 +1247,7 @@ angular.module('syncthing.core')
}).error($scope.emitHTTPError);
},
show: function () {
$scope.logging.paused = false;
$scope.logging.refreshFacilities();
$scope.logging.timer = $timeout($scope.logging.fetch);
var textArea = $('#logViewerText');
@ -1496,9 +1505,40 @@ angular.module('syncthing.core')
$scope.configInSync = true;
};
$scope.editDevice = function (deviceCfg) {
function editDeviceModal() {
$scope.currentDevice._addressesStr = $scope.currentDevice.addresses.join(', ');
$scope.deviceEditor.$setPristine();
$('#editDevice').modal();
}
$scope.editDeviceModalTitle = function() {
if ($scope.editingDefaults) {
return $translate.instant("Edit Device Defaults");
}
var title = '';
if ($scope.editingExisting) {
title += $translate.instant("Edit Device");
} else {
title += $translate.instant("Add Device");
}
var name = $scope.deviceName($scope.currentDevice);
if (name !== '') {
title += ' (' + name + ')';
}
return title;
};
$scope.editDeviceModalIcon = function() {
if ($scope.editingDefaults || $scope.editingExisting) {
return 'fas fa-pencil-alt';
}
return 'fas fa-desktop';
};
$scope.editDeviceExisting = function (deviceCfg) {
$scope.currentDevice = $.extend({}, deviceCfg);
$scope.editingExisting = true;
$scope.editingDefaults = false;
$scope.willBeReintroducedBy = undefined;
if (deviceCfg.introducedBy) {
var introducerDevice = $scope.devices[deviceCfg.introducedBy];
@ -1506,7 +1546,6 @@ angular.module('syncthing.core')
$scope.willBeReintroducedBy = $scope.deviceName(introducerDevice);
}
}
$scope.currentDevice._addressesStr = deviceCfg.addresses.join(', ');
initShareEditing('device');
$scope.deviceFolders($scope.currentDevice).forEach(function (folderID) {
$scope.currentSharing.shared.push($scope.folders[folderID]);
@ -1522,8 +1561,15 @@ angular.module('syncthing.core')
$scope.currentSharing.unrelated = $scope.folderList().filter(function (n) {
return !$scope.currentSharing.selected[n.id];
});
$scope.deviceEditor.$setPristine();
$('#editDevice').modal();
editDeviceModal();
};
$scope.editDeviceDefaults = function () {
$http.get(urlbase + '/config/defaults/device').then(function (p) {
$scope.currentDevice = p.data;
$scope.editingDefaults = true;
editDeviceModal();
}, $scope.emitHTTPError);
};
$scope.selectAllSharedFolders = function (state) {
@ -1555,19 +1601,16 @@ angular.module('syncthing.core')
}
})
.then(function () {
$scope.currentDevice = {
name: name,
deviceID: deviceID,
_addressesStr: 'dynamic',
compression: 'metadata',
introducer: false,
ignoredFolders: []
};
$scope.editingExisting = false;
initShareEditing('device');
$scope.currentSharing.unrelated = $scope.folderList();
$scope.deviceEditor.$setPristine();
$('#editDevice').modal();
$http.get(urlbase + '/config/defaults/device').then(function (p) {
$scope.currentDevice = p.data;
$scope.currentDevice.name = name;
$scope.currentDevice.deviceID = deviceID;
$scope.editingExisting = false;
$scope.editingDefaults = false;
initShareEditing('device');
$scope.currentSharing.unrelated = $scope.folderList();
editDeviceModal();
}, $scope.emitHTTPError);
});
};
@ -1592,22 +1635,30 @@ angular.module('syncthing.core')
$scope.saveDevice = function () {
$('#editDevice').modal('hide');
$scope.saveDeviceConfig($scope.currentDevice);
};
$scope.saveDeviceConfig = function (deviceCfg) {
deviceCfg.addresses = deviceCfg._addressesStr.split(',').map(function (x) {
$scope.currentDevice.addresses = $scope.currentDevice._addressesStr.split(',').map(function (x) {
return x.trim();
});
delete $scope.currentDevice._addressesStr;
if ($scope.editingDefaults) {
$scope.config.defaults.device = $scope.currentDevice;
} else {
setDeviceConfig();
}
delete $scope.currentSharing;
delete $scope.currentDevice;
$scope.saveConfig();
};
$scope.devices[deviceCfg.deviceID] = deviceCfg;
function setDeviceConfig() {
var currentID = $scope.currentDevice.DeviceID;
$scope.devices[currentID] = $scope.currentDevice;
$scope.config.devices = deviceList($scope.devices);
for (var id in $scope.currentSharing.selected) {
if ($scope.currentSharing.selected[id]) {
var found = false;
for (i = 0; i < $scope.folders[id].devices.length; i++) {
if ($scope.folders[id].devices[i].deviceID === deviceCfg.deviceID) {
if ($scope.folders[id].devices[i].deviceID === currentID) {
found = true;
// Update encryption pw
$scope.folders[id].devices[i].encryptionPassword = $scope.currentSharing.encryptionPasswords[id];
@ -1618,22 +1669,19 @@ angular.module('syncthing.core')
if (!found) {
// Add device to folder
$scope.folders[id].devices.push({
deviceID: deviceCfg.deviceID,
encryptionPassword: $scope.currentSharing.encryptionPasswords[id]
deviceID: currentID,
encryptionPassword: $scope.currentSharing.encryptionPasswords[id],
});
}
} else {
// Remove device from folder
$scope.folders[id].devices = $scope.folders[id].devices.filter(function (n) {
return n.deviceID !== deviceCfg.deviceID;
return n.deviceID !== currentID;
});
}
}
delete $scope.currentSharing;
$scope.config.folders = folderList($scope.folders);
$scope.saveConfig();
};
$scope.ignoreDevice = function (deviceID, pendingDevice) {
@ -1770,14 +1818,14 @@ angular.module('syncthing.core')
if (!newvalue || !shouldSetDefaultFolderPath()) {
return;
}
$scope.currentFolder.path = pathJoin($scope.config.options.defaultFolderPath, newvalue);
$scope.currentFolder.path = pathJoin($scope.config.defaults.folder.path, newvalue);
});
$scope.$watch('currentFolder.id', function (newvalue) {
if (!newvalue || !shouldSetDefaultFolderPath() || $scope.currentFolder.label) {
return;
}
$scope.currentFolder.path = pathJoin($scope.config.options.defaultFolderPath, newvalue);
$scope.currentFolder.path = pathJoin($scope.config.defaults.folder.path, newvalue);
});
$scope.fsWatcherToggled = function () {
@ -1804,7 +1852,8 @@ angular.module('syncthing.core')
$('#globalChanges').modal();
};
$scope.editFolderModal = function () {
function editFolderModal() {
initVersioningEditing();
$scope.folderPathErrors = {};
$scope.folderEditor.$setPristine();
$('#editFolder').modal().one('shown.bs.tab', function (e) {
@ -1817,67 +1866,78 @@ angular.module('syncthing.core')
});
};
$scope.editFolder = function (folderCfg) {
$scope.editingExisting = true;
$scope.currentFolder = angular.copy(folderCfg);
$scope.editFolderModalTitle = function() {
if ($scope.editingDefaults) {
return $translate.instant("Edit Folder Defaults");
}
var title = '';
if ($scope.editingExisting) {
title += $translate.instant("Edit Folder");
} else {
title += $translate.instant("Add Folder");
}
if ($scope.currentFolder.id !== '') {
title += ' (' + $scope.folderLabel($scope.currentFolder.id) + ')';
}
return title;
};
$scope.editFolderModalIcon = function() {
if ($scope.editingDefaults || $scope.editingExisting) {
return 'fas fa-pencil-alt';
}
return 'fas fa-folder';
};
function editFolder() {
if ($scope.currentFolder.path.length > 1 && $scope.currentFolder.path.slice(-1) === $scope.system.pathSeparator) {
$scope.currentFolder.path = $scope.currentFolder.path.slice(0, -1);
} else if (!$scope.currentFolder.path) {
// undefined path leads to invalid input field
$scope.currentFolder.path = '';
}
// Cache complete device objects indexed by ID for lookups
initShareEditing('folder');
$scope.currentFolder.devices.forEach(function (n) {
if (n.deviceID !== $scope.myID) {
$scope.currentSharing.shared.push($scope.devices[n.deviceID]);
}
if (n.encryptionPassword !== '') {
$scope.currentSharing.encryptionPasswords[n.deviceID] = n.encryptionPassword;
}
$scope.currentSharing.selected[n.deviceID] = true;
});
$scope.currentSharing.unrelated = $scope.deviceList().filter(function (n) {
return n.deviceID !== $scope.myID && !$scope.currentSharing.selected[n.deviceID];
});
if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "trashcan") {
$scope.currentFolder.trashcanFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "trashcan";
$scope.currentFolder.trashcanClean = +$scope.currentFolder.versioning.params.cleanoutDays;
$scope.currentFolder.versioningCleanupIntervalS = +$scope.currentFolder.versioning.cleanupIntervalS;
} else if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "simple") {
$scope.currentFolder.simpleFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "simple";
$scope.currentFolder.simpleKeep = +$scope.currentFolder.versioning.params.keep;
$scope.currentFolder.versioningCleanupIntervalS = +$scope.currentFolder.versioning.cleanupIntervalS;
$scope.currentFolder.trashcanClean = +$scope.currentFolder.versioning.params.cleanoutDays;
} else if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "staggered") {
$scope.currentFolder.staggeredFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "staggered";
$scope.currentFolder.staggeredMaxAge = Math.floor(+$scope.currentFolder.versioning.params.maxAge / 86400);
$scope.currentFolder.staggeredCleanInterval = +$scope.currentFolder.versioning.params.cleanInterval;
$scope.currentFolder.staggeredVersionsPath = $scope.currentFolder.versioning.params.versionsPath;
$scope.currentFolder.versioningCleanupIntervalS = +$scope.currentFolder.versioning.cleanupIntervalS;
} else if ($scope.currentFolder.versioning && $scope.currentFolder.versioning.type === "external") {
$scope.currentFolder.externalFileVersioning = true;
$scope.currentFolder.fileVersioningSelector = "external";
$scope.currentFolder.externalCommand = $scope.currentFolder.versioning.params.command;
} else {
$scope.currentFolder.fileVersioningSelector = "none";
}
$scope.currentFolder.trashcanClean = $scope.currentFolder.trashcanClean || 0; // weeds out nulls and undefineds
$scope.currentFolder.simpleKeep = $scope.currentFolder.simpleKeep || 5;
$scope.currentFolder.staggeredCleanInterval = $scope.currentFolder.staggeredCleanInterval || 3600;
$scope.currentFolder.staggeredVersionsPath = $scope.currentFolder.staggeredVersionsPath || "";
// Zero is a valid, non-default value (disabled)
if ($scope.currentFolder.versioningCleanupIntervalS !== 0) {
$scope.currentFolder.versioningCleanupIntervalS = $scope.currentFolder.versioningCleanupIntervalS || 3600;
editFolderModal();
}
function initVersioningEditing() {
$scope.currentFolder._guiVersioning = angular.copy($scope.versioningDefaults);
if (!$scope.currentFolder.versioning) {
return;
}
// staggeredMaxAge can validly be zero, which we should not replace
// with the default value of 365. So only set the default if it's
// actually undefined.
if (typeof $scope.currentFolder.staggeredMaxAge === 'undefined') {
$scope.currentFolder.staggeredMaxAge = 365;
var currentVersioning = $scope.currentFolder.versioning;
$scope.currentFolder._guiVersioning.cleanupIntervalS = +currentVersioning.cleanupIntervalS;
// Apply parameters currently in use
switch (currentVersioning.type) {
case "trashcan":
$scope.currentFolder._guiVersioning.selector = "trashcan";
$scope.currentFolder._guiVersioning.trashcanClean = +currentVersioning.params.cleanoutDays;
break;
case "simple":
$scope.currentFolder._guiVersioning.selector = "simple";
$scope.currentFolder._guiVersioning.simpleKeep = +currentVersioning.params.keep;
$scope.currentFolder._guiVersioning.trashcanClean = +currentVersioning.params.cleanoutDays;
break;
case "staggered":
$scope.currentFolder._guiVersioning.selector = "staggered";
$scope.currentFolder._guiVersioning.staggeredMaxAge = Math.floor(+currentVersioning.params.maxAge / 86400);
$scope.currentFolder._guiVersioning.staggeredCleanInterval = +currentVersioning.params.cleanInterval;
$scope.currentFolder._guiVersioning.staggeredVersionsPath = currentVersioning.params.versionsPath;
break;
case "external":
$scope.currentFolder._guiVersioning.selector = "external";
$scope.currentFolder.externalCommand = currentVersioning.params.command;
break;
}
$scope.currentFolder.externalCommand = $scope.currentFolder.externalCommand || "";
};
$scope.editFolderExisting = function(folderCfg) {
$scope.editingExisting = true;
$scope.currentFolder = angular.copy(folderCfg);
$scope.ignores.text = 'Loading...';
$scope.ignores.error = null;
@ -1894,7 +1954,18 @@ angular.module('syncthing.core')
$scope.emitHTTPError(err);
});
$scope.editFolderModal();
editFolder();
};
$scope.editFolderDefaults = function() {
$http.get(urlbase + '/config/defaults/folder')
.success(function (data) {
$scope.currentFolder = data;
$scope.editingExisting = false;
$scope.editingDefaults = true;
editFolder();
})
.error($scope.emitHTTPError);
};
$scope.selectAllSharedDevices = function (state) {
@ -1913,37 +1984,43 @@ angular.module('syncthing.core')
$scope.addFolder = function () {
$http.get(urlbase + '/svc/random/string?length=10').success(function (data) {
$scope.editingExisting = false;
$scope.currentFolder = angular.copy($scope.folderDefaults);
initShareEditing('folder');
$scope.currentFolder.id = (data.random.substr(0, 5) + '-' + data.random.substr(5, 5)).toLowerCase();
$scope.currentSharing.unrelated = $scope.otherDevices();
$scope.ignores.text = '';
$scope.ignores.error = null;
$scope.ignores.disabled = false;
$scope.editFolderModal();
var folderID = (data.random.substr(0, 5) + '-' + data.random.substr(5, 5)).toLowerCase();
addFolderInit(folderID).then(function() {
// Triggers the watch that sets the path
$scope.currentFolder.label = $scope.currentFolder.label;
editFolderModal();
});
});
};
$scope.addFolderAndShare = function (folder, folderLabel, device) {
$scope.editingExisting = false;
$scope.currentFolder = angular.copy($scope.folderDefaults);
$scope.currentFolder.id = folder;
$scope.currentFolder.label = folderLabel;
$scope.currentFolder.viewFlags = {
importFromOtherDevice: true
};
initShareEditing('folder');
$scope.currentSharing.selected[device] = true;
$scope.currentSharing.unrelated = $scope.deviceList().filter(function (n) {
return n.deviceID !== $scope.myID;
$scope.addFolderAndShare = function (folderID, folderLabel, device) {
addFolderInit(folderID).then(function() {
$scope.currentFolder.viewFlags = {
importFromOtherDevice: true
};
$scope.currentSharing.selected[device] = true;
$scope.currentFolder.label = folderLabel;
editFolderModal();
});
$scope.ignores.text = '';
$scope.ignores.error = null;
$scope.ignores.disabled = false;
$scope.editFolderModal();
};
function addFolderInit(folderID) {
$scope.editingExisting = false;
$scope.editingDefaults = false;
return $http.get(urlbase + '/config/defaults/folder').then(function(p) {
$scope.currentFolder = p.data;
$scope.currentFolder.id = folderID;
initShareEditing('folder');
$scope.currentSharing.unrelated = $scope.currentSharing.unrelated.concat($scope.currentSharing.shared);
$scope.currentSharing.shared = [];
$scope.ignores.text = '';
$scope.ignores.error = null;
$scope.ignores.disabled = false;
}, $scope.emitHTTPError);
}
$scope.shareFolderWithDevice = function (folder, device) {
$scope.folders[folder].devices.push({
deviceID: device
@ -1975,55 +2052,60 @@ angular.module('syncthing.core')
folderCfg.devices = newDevices;
delete $scope.currentSharing;
if (folderCfg.fileVersioningSelector === "trashcan") {
switch (folderCfg._guiVersioning.selector) {
case "trashcan":
folderCfg.versioning = {
'type': 'trashcan',
'params': {
'cleanoutDays': '' + folderCfg.trashcanClean
'cleanoutDays': '' + folderCfg._guiVersioning.trashcanClean
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.trashcanFileVersioning;
delete folderCfg.trashcanClean;
} else if (folderCfg.fileVersioningSelector === "simple") {
break;
case "simple":
folderCfg.versioning = {
'type': 'simple',
'params': {
'keep': '' + folderCfg.simpleKeep,
'cleanoutDays': '' + folderCfg.trashcanClean
'keep': '' + folderCfg._guiVersioning.simpleKeep,
'cleanoutDays': '' + folderCfg._guiVersioning.trashcanClean
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.simpleFileVersioning;
delete folderCfg.simpleKeep;
} else if (folderCfg.fileVersioningSelector === "staggered") {
break;
case "staggered":
folderCfg.versioning = {
'type': 'staggered',
'params': {
'maxAge': '' + (folderCfg.staggeredMaxAge * 86400),
'cleanInterval': '' + folderCfg.staggeredCleanInterval,
'versionsPath': '' + folderCfg.staggeredVersionsPath
'maxAge': '' + (folderCfg._guiVersioning.staggeredMaxAge * 86400),
'cleanInterval': '' + folderCfg._guiVersioning.staggeredCleanInterval,
'versionsPath': '' + folderCfg._guiVersioning.staggeredVersionsPath
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.staggeredFileVersioning;
delete folderCfg.staggeredMaxAge;
delete folderCfg.staggeredCleanInterval;
delete folderCfg.staggeredVersionsPath;
} else if (folderCfg.fileVersioningSelector === "external") {
break;
case "external":
folderCfg.versioning = {
'type': 'external',
'params': {
'command': '' + folderCfg.externalCommand
'command': '' + folderCfg._guiVersioning.externalCommand
},
'cleanupIntervalS': folderCfg.versioningCleanupIntervalS
'cleanupIntervalS': folderCfg._guiVersioning.cleanupIntervalS
};
delete folderCfg.externalFileVersioning;
delete folderCfg.externalCommand;
} else {
break;
default:
delete folderCfg.versioning;
}
delete folderCfg._guiVersioning;
if ($scope.editingDefaults) {
$scope.config.defaults.folder = folderCfg;
$scope.saveConfig();
} else {
saveFolderExisting(folderCfg);
}
};
function saveFolderExisting(folderCfg) {
var ignoresLoaded = !$scope.ignores.disabled;
var ignores = $scope.ignores.text.split('\n');
// Split always returns a minimum 1-length array even for no patterns

View File

@ -1,14 +1,14 @@
<modal id="editDevice" status="default" icon="{{editingExisting ? 'fas fa-pencil-alt' : 'fas fa-desktop'}}" heading="{{editingExisting ? 'Edit Device' : 'Add Device' | translate}} {{currentDevice.name}}" large="yes" closeable="yes">
<modal id="editDevice" status="default" icon="{{editDeviceModalIcon()}}" heading="{{editDeviceModalTitle()}}" large="yes" closeable="yes">
<div class="modal-body">
<form role="form" name="deviceEditor">
<ul class="nav nav-tabs" ng-init="loadFormIntoScope(deviceEditor)">
<li class="active"><a data-toggle="tab" href="#device-general"><span class="fas fa-cog"></span> <span translate>General</span></a></li>
<li><a data-toggle="tab" href="#device-sharing"><span class="fas fa-share-alt"></span> <span translate>Sharing</span></a></li>
<li ng-if="!editingDefaults"><a data-toggle="tab" href="#device-sharing"><span class="fas fa-share-alt"></span> <span translate>Sharing</span></a></li>
<li><a data-toggle="tab" href="#device-advanced"><span class="fas fa-cogs"></span> <span translate>Advanced</span></a></li>
</ul>
<div class="tab-content">
<div id="device-general" class="tab-pane in active">
<div class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}" ng-init="loadFormIntoScope(deviceEditor)">
<div ng-if="!editingDefaults" class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}" ng-init="loadFormIntoScope(deviceEditor)">
<label translate for="deviceID">Device ID</label>
<div ng-if="!editingExisting">
<input name="deviceID" id="deviceID" class="form-control text-monospace" type="text" ng-model="currentDevice.deviceID" required="" valid-deviceid list="discovery-list" aria-required="true" />
@ -38,7 +38,7 @@
<p translate ng-if="currentDevice.deviceID != myID" class="help-block">Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.</p>
</div>
</div>
<div id="device-sharing" class="tab-pane">
<div ng-if="!editingDefaults" id="device-sharing" class="tab-pane">
<div class="row">
<div class="col-md-6">
<div class="form-group">
@ -151,13 +151,13 @@
<button type="button" class="btn btn-primary btn-sm" ng-click="saveDevice()" ng-disabled="deviceEditor.$invalid">
<span class="fas fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#idqr" ng-if="editingExisting || deviceEditor.deviceID.$valid">
<button ng-if="!editingDefaults" type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#idqr" ng-if="editingExisting || deviceEditor.deviceID.$valid">
<span class="fas fa-qrcode"></span>&nbsp;<span translate>Show QR</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fas fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<div ng-if="editingExisting" class="pull-left">
<div ng-if="editingExisting && !editingDefaults" class="pull-left">
<button type="button" class="btn btn-warning btn-sm" data-toggle="modal" data-target="#remove-device-confirmation">
<span class="fas fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>

View File

@ -1,24 +1,24 @@
<modal id="editFolder" status="default" icon="{{editingExisting ? 'fas fa-pencil-alt' : 'fas fa-folder'}}" heading="{{editingExisting ? 'Edit Folder' : 'Add Folder' | translate}} ({{folderLabel(currentFolder.id)}})" large="yes" closeable="yes">
<modal id="editFolder" status="default" icon="{{editFolderModalIcon()}}" heading="{{editFolderModalTitle()}}" large="yes" closeable="yes">
<div class="modal-body">
<form role="form" name="folderEditor">
<ul class="nav nav-tabs" ng-init="loadFormIntoScope(folderEditor)">
<li class="active"><a data-toggle="tab" href="#folder-general"><span class="fas fa-cog"></span> <span translate>General</span></a></li>
<li><a data-toggle="tab" href="#folder-sharing"><span class="fas fa-share-alt"></span> <span translate>Sharing</span></a></li>
<li><a data-toggle="tab" href="#folder-versioning"><span class="fas fa-copy"></span> <span translate>File Versioning</span></a></li>
<li><a data-toggle="tab" href="#folder-ignores"><span class="fas fa-filter"></span> <span translate>Ignore Patterns</span></a></li>
<li ng-if="!editingDefaults"><a data-toggle="tab" href="#folder-ignores"><span class="fas fa-filter"></span> <span translate>Ignore Patterns</span></a></li>
<li><a data-toggle="tab" href="#folder-advanced"><span class="fas fa-cogs"></span> <span translate>Advanced</span></a></li>
</ul>
<div class="tab-content">
<div id="folder-general" class="tab-pane in active">
<div class="form-group" ng-class="{'has-error': folderEditor.folderLabel.$invalid && folderEditor.folderLabel.$dirty}">
<div class="form-group" ng-class="{'has-error': folderEditor.folderLabel.$invalid && folderEditor.folderLabel.$dirty && !editingDefaults}">
<label for="folderLabel"><span translate>Folder Label</span></label>
<input name="folderLabel" id="folderLabel" class="form-control" type="text" ng-model="currentFolder.label" value="{{currentFolder.label}}" />
<p class="help-block">
<span translate ng-if="folderEditor.folderLabel.$valid || folderEditor.folderLabel.$pristine">Optional descriptive label for the folder. Can be different on each device.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<div ng-if="!editingDefaults" class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<label for="folderID"><span translate>Folder ID</span></label>
<input name="folderID" ng-readonly="editingExisting || (!editingExisting && currentFolder.viewFlags.importFromOtherDevice)" id="folderID" class="form-control" type="text" ng-model="currentFolder.id" required="" aria-required="true" unique-folder value="{{currentFolder.id}}" />
<p class="help-block">
@ -28,19 +28,21 @@
<span translate ng-show="!editingExisting">When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderPath.$invalid && folderEditor.folderPath.$dirty}">
<div class="form-group" ng-class="{'has-error': folderEditor.folderPath.$invalid && folderEditor.folderPath.$dirty && !editingDefaults}">
<label translate for="folderPath">Folder Path</label>
<input name="folderPath" ng-readonly="editingExisting" id="folderPath" class="form-control" type="text" ng-model="currentFolder.path" list="directory-list" required="" aria-required="true" path-is-sub-dir />
<input name="folderPath" ng-readonly="editingExisting && !editingDefaults" id="folderPath" class="form-control" type="text" ng-model="currentFolder.path" list="directory-list" ng-required="!editingDefaults" ng-aria-required="!editingDefaults" path-is-sub-dir />
<datalist id="directory-list">
<option ng-repeat="directory in directoryList" value="{{ directory }}" />
</datalist>
<p class="help-block">
<span ng-if="folderEditor.folderPath.$valid || folderEditor.folderPath.$pristine"><span translate>Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for</span> <code>{{system.tilde}}</code>.</br></span>
<span translate ng-if="folderEditor.folderPath.$error.required && folderEditor.folderPath.$dirty">The folder path cannot be blank.</span>
<span translate ng-if="folderEditor.folderPath.$error.required && folderEditor.folderPath.$dirty && !editingDefaults">The folder path cannot be blank.</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" ng-if="folderPathErrors.isSub && folderPathErrors.otherLabel.length == 0">Warning, this path is a subdirectory of an existing folder "{%otherFolder%}".</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" translate-value-other-folder-label="{{folderPathErrors.otherLabel}}" ng-if="folderPathErrors.isSub && folderPathErrors.otherLabel.length != 0">Warning, this path is a subdirectory of an existing folder "{%otherFolderLabel%}" ({%otherFolder%}).</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" ng-if="folderPathErrors.isParent && folderPathErrors.otherLabel.length == 0">Warning, this path is a parent directory of an existing folder "{%otherFolder%}".</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" translate-value-other-folder-label="{{folderPathErrors.otherLabel}}" ng-if="folderPathErrors.isParent && folderPathErrors.otherLabel.length != 0">Warning, this path is a parent directory of an existing folder "{%otherFolderLabel%}" ({%otherFolder%}).</span>
<span ng-if="folderPathErrors.isParent && !editingDefaults">
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" ng-if="folderPathErrors.otherLabel.length == 0">Warning, this path is a parent directory of an existing folder "{%otherFolder%}".</span>
<span class="text-danger" translate translate-value-other-folder="{{folderPathErrors.otherID}}" translate-value-other-folder-label="{{folderPathErrors.otherLabel}}" ng-if="folderPathErrors.otherLabel.length != 0">Warning, this path is a parent directory of an existing folder "{%otherFolderLabel%}" ({%otherFolder%}).</span>
</span>
</p>
</div>
</div>
@ -76,7 +78,7 @@
<div id="folder-versioning" class="tab-pane">
<div class="form-group">
<label translate>File Versioning</label>&emsp;<a href="https://docs.syncthing.net/users/versioning.html" target="_blank"><span class="fas fa-question-circle"></span>&nbsp;<span translate>Help</span></a>
<select class="form-control" ng-model="currentFolder.fileVersioningSelector">
<select class="form-control" ng-model="currentFolder._guiVersioning.selector">
<option value="none" translate>No File Versioning</option>
<option value="trashcan" translate>Trash Can File Versioning</option>
<option value="simple" translate>Simple File Versioning</option>
@ -84,46 +86,46 @@
<option value="external" translate>External File Versioning</option>
</select>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='trashcan' || currentFolder.fileVersioningSelector=='simple'" ng-class="{'has-error': folderEditor.trashcanClean.$invalid && folderEditor.trashcanClean.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='trashcan' || currentFolder._guiVersioning.selectorector=='simple'" ng-class="{'has-error': folderEditor._guiVersioning.trashcanClean.$invalid && folderEditor._guiVersioning.trashcanClean.$dirty}">
<p translate class="help-block">Files are moved to .stversions directory when replaced or deleted by Syncthing.</p>
<label translate for="trashcanClean">Clean out after</label>
<div class="input-group">
<input name="trashcanClean" id="trashcanClean" class="form-control text-right" type="number" ng-model="currentFolder.trashcanClean" required="" aria-required="true" min="0" />
<input name="trashcanClean" id="trashcanClean" class="form-control text-right" type="number" ng-model="currentFolder._guiVersioning.trashcanClean" required="" aria-required="true" min="0" />
<div class="input-group-addon" translate>days</div>
</div>
<p class="help-block">
<span translate ng-if="folderEditor.trashcanClean.$valid || folderEditor.trashcanClean.$pristine">The number of days to keep files in the trash can. Zero means forever.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.required && folderEditor.trashcanClean.$dirty">The number of days must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.min && folderEditor.trashcanClean.$dirty">A negative number of days doesn't make sense.</span>
<span translate ng-if="folderEditor._guiVersioning.trashcanClean.$valid || folderEditor._guiVersioning.trashcanClean.$pristine">The number of days to keep files in the trash can. Zero means forever.</span>
<span translate ng-if="folderEditor._guiVersioning.trashcanClean.$error.required && folderEditor._guiVersioning.trashcanClean.$dirty">The number of days must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.trashcanClean.$error.min && folderEditor._guiVersioning.trashcanClean.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='simple'" ng-class="{'has-error': folderEditor.simpleKeep.$invalid && folderEditor.simpleKeep.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='simple'" ng-class="{'has-error': folderEditor._guiVersioning.simpleKeep.$invalid && folderEditor._guiVersioning.simpleKeep.$dirty}">
<p translate class="help-block">Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.</p>
<label translate for="simpleKeep">Keep Versions</label>
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentFolder.simpleKeep" required="" aria-required="true" min="1" />
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentFolder._guiVersioning.simpleKeep" required="" aria-required="true" min="1" />
<p class="help-block">
<span translate ng-if="folderEditor.simpleKeep.$valid || folderEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.required && folderEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.min && folderEditor.simpleKeep.$dirty">You must keep at least one version.</span>
<span translate ng-if="folderEditor._guiVersioning.simpleKeep.$valid || folderEditor._guiVersioning.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="folderEditor._guiVersioning.simpleKeep.$error.required && folderEditor._guiVersioning.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.simpleKeep.$error.min && folderEditor._guiVersioning.simpleKeep.$dirty">You must keep at least one version.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='staggered'" ng-class="{'has-error': folderEditor.staggeredMaxAge.$invalid && folderEditor.staggeredMaxAge.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='staggered'" ng-class="{'has-error': folderEditor._guiVersioning.staggeredMaxAge.$invalid && folderEditor._guiVersioning.staggeredMaxAge.$dirty}">
<p class="help-block"><span translate>Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.</span> <span translate>Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.</span></p>
<p translate class="help-block">The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.</p>
<label translate for="staggeredMaxAge">Maximum Age</label>
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentFolder.staggeredMaxAge" required="" aria-required="true" min="0" />
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentFolder._guiVersioning.staggeredMaxAge" required="" aria-required="true" min="0" />
<p class="help-block">
<span translate ng-if="folderEditor.staggeredMaxAge.$valid || folderEditor.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.required && folderEditor.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.min && folderEditor.staggeredMaxAge.$dirty">A negative number of days doesn't make sense.</span>
<span translate ng-if="folderEditor._guiVersioning.staggeredMaxAge.$valid || folderEditor._guiVersioning.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="folderEditor._guiVersioning.staggeredMaxAge.$error.required && folderEditor._guiVersioning.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.staggeredMaxAge.$error.min && folderEditor._guiVersioning.staggeredMaxAge.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector == 'staggered'">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector == 'staggered'">
<label translate for="staggeredVersionsPath">Versions Path</label>
<input name="staggeredVersionsPath" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentFolder.staggeredVersionsPath" />
<input name="staggeredVersionsPath" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentFolder._guiVersioning.staggeredVersionsPath" />
<p translate class="help-block">Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='external'" ng-class="{'has-error': folderEditor.externalCommand.$invalid && folderEditor.externalCommand.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector=='external'" ng-class="{'has-error': folderEditor.externalCommand.$invalid && folderEditor.externalCommand.$dirty}">
<p translate class="help-block">An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.</p>
<label translate for="externalCommand">Command</label>
<input name="externalCommand" id="externalCommand" class="form-control" type="text" ng-model="currentFolder.externalCommand" required="" aria-required="true" />
@ -132,21 +134,21 @@
<span translate ng-if="folderEditor.externalCommand.$error.required && folderEditor.externalCommand.$dirty">The path cannot be blank.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector != 'none'" ng-class="{'has-error': folderEditor.versioningCleanupIntervalS.$invalid && folderEditor.versioningCleanupIntervalS.$dirty}">
<div class="form-group" ng-if="currentFolder._guiVersioning.selector != 'none'" ng-class="{'has-error': folderEditor._guiVersioning.cleanupIntervalS.$invalid && folderEditor._guiVersioning.cleanupIntervalS.$dirty}">
<label translate for="versioningCleanupIntervalS">Cleanup Interval</label>
<div class="input-group">
<input name="versioningCleanupIntervalS" id="versioningCleanupIntervalS" class="form-control text-right" type="number" ng-model="currentFolder.versioningCleanupIntervalS" required="" min="0" max="31536000" aria-required="true" />
<input name="versioningCleanupIntervalS" id="versioningCleanupIntervalS" class="form-control text-right" type="number" ng-model="currentFolder._guiVersioning.cleanupIntervalS" required="" min="0" max="31536000" aria-required="true" />
<div class="input-group-addon" translate>seconds</div>
</div>
<p class="help-block">
<span translate ng-if="folderEditor.versioningCleanupIntervalS.$valid || folderEditor.versioningCleanupIntervalS.$pristine"class="help-block">The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.</span>
<span translate ng-if="folderEditor.versioningCleanupIntervalS.$error.required && folderEditor.versioningCleanupIntervalS.$dirty">The cleanup interval cannot be blank.</span>
<span translate ng-if="folderEditor.versioningCleanupIntervalS.$error.min && folderEditor.versioningCleanupIntervalS.$dirty">The interval must be a positive number of seconds.</span>
<span translate ng-if="folderEditor._guiVersioning.cleanupIntervalS.$valid || folderEditor._guiVersioning.cleanupIntervalS.$pristine"class="help-block">The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.</span>
<span translate ng-if="folderEditor._guiVersioning.cleanupIntervalS.$error.required && folderEditor._guiVersioning.cleanupIntervalS.$dirty">The cleanup interval cannot be blank.</span>
<span translate ng-if="folderEditor._guiVersioning.cleanupIntervalS.$error.min && folderEditor._guiVersioning.cleanupIntervalS.$dirty">The interval must be a positive number of seconds.</span>
</p>
</div>
</div>
<div id="folder-ignores" class="tab-pane">
<div ng-if="!editingDefaults" id="folder-ignores" class="tab-pane">
<p translate>Enter ignore patterns, one per line.</p>
<div ng-class="{'has-error': ignores.error != null}">
<textarea class="form-control" rows="5" ng-model="ignores.text" ng-disabled="ignores.disabled"></textarea>
@ -271,7 +273,7 @@
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fas fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<button type="button" class="btn btn-warning pull-left btn-sm" data-toggle="modal" data-target="#remove-folder-confirmation" ng-if="editingExisting">
<button type="button" class="btn btn-warning pull-left btn-sm" data-toggle="modal" data-target="#remove-folder-confirmation" ng-if="editingExisting && !editingDefaults">
<span class="fas fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>
</div>

View File

@ -302,6 +302,8 @@ func (s *service) Serve(ctx context.Context) error {
configBuilder.registerDevices("/rest/config/devices")
configBuilder.registerFolder("/rest/config/folders/:id")
configBuilder.registerDevice("/rest/config/devices/:id")
configBuilder.registerDefaultFolder("/rest/config/defaults/folder")
configBuilder.registerDefaultDevice("/rest/config/defaults/device")
configBuilder.registerOptions("/rest/config/options")
configBuilder.registerLDAP("/rest/config/ldap")
configBuilder.registerGUI("/rest/config/gui")

View File

@ -73,7 +73,7 @@ func (c *configMuxBuilder) registerFolders(path string) {
})
c.HandlerFunc(http.MethodPost, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustFolder(w, r, config.FolderConfiguration{})
c.adjustFolder(w, r, config.FolderConfiguration{}, false)
})
}
@ -126,7 +126,7 @@ func (c *configMuxBuilder) registerFolder(path string) {
})
c.Handle(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
c.adjustFolder(w, r, config.FolderConfiguration{})
c.adjustFolder(w, r, config.FolderConfiguration{}, false)
})
c.Handle(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
@ -135,7 +135,7 @@ func (c *configMuxBuilder) registerFolder(path string) {
http.Error(w, "No folder with given ID", http.StatusNotFound)
return
}
c.adjustFolder(w, r, folder)
c.adjustFolder(w, r, folder, false)
})
c.Handle(http.MethodDelete, path, func(w http.ResponseWriter, _ *http.Request, p httprouter.Params) {
@ -170,12 +170,12 @@ func (c *configMuxBuilder) registerDevice(path string) {
})
c.Handle(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
c.adjustDevice(w, r, config.DeviceConfiguration{})
c.adjustDevice(w, r, config.DeviceConfiguration{}, false)
})
c.Handle(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
if device, ok := deviceFromParams(w, p); ok {
c.adjustDevice(w, r, device)
c.adjustDevice(w, r, device, false)
}
})
@ -190,6 +190,34 @@ func (c *configMuxBuilder) registerDevice(path string) {
})
}
func (c *configMuxBuilder) registerDefaultFolder(path string) {
c.HandlerFunc(http.MethodGet, path, func(w http.ResponseWriter, _ *http.Request) {
sendJSON(w, c.cfg.DefaultFolder())
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustFolder(w, r, config.FolderConfiguration{}, true)
})
c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustFolder(w, r, c.cfg.DefaultFolder(), true)
})
}
func (c *configMuxBuilder) registerDefaultDevice(path string) {
c.HandlerFunc(http.MethodGet, path, func(w http.ResponseWriter, _ *http.Request) {
sendJSON(w, c.cfg.DefaultDevice())
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustDevice(w, r, config.DeviceConfiguration{}, true)
})
c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustDevice(w, r, c.cfg.DefaultDevice(), true)
})
}
func (c *configMuxBuilder) registerOptions(path string) {
c.HandlerFunc(http.MethodGet, path, func(w http.ResponseWriter, _ *http.Request) {
sendJSON(w, c.cfg.Options())
@ -260,13 +288,17 @@ func (c *configMuxBuilder) adjustConfig(w http.ResponseWriter, r *http.Request)
c.finish(w, waiter)
}
func (c *configMuxBuilder) adjustFolder(w http.ResponseWriter, r *http.Request, folder config.FolderConfiguration) {
func (c *configMuxBuilder) adjustFolder(w http.ResponseWriter, r *http.Request, folder config.FolderConfiguration, defaults bool) {
if err := unmarshalTo(r.Body, &folder); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
waiter, err := c.cfg.Modify(func(cfg *config.Configuration) {
cfg.SetFolder(folder)
if defaults {
cfg.Defaults.Folder = folder
} else {
cfg.SetFolder(folder)
}
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
@ -275,13 +307,17 @@ func (c *configMuxBuilder) adjustFolder(w http.ResponseWriter, r *http.Request,
c.finish(w, waiter)
}
func (c *configMuxBuilder) adjustDevice(w http.ResponseWriter, r *http.Request, device config.DeviceConfiguration) {
func (c *configMuxBuilder) adjustDevice(w http.ResponseWriter, r *http.Request, device config.DeviceConfiguration, defaults bool) {
if err := unmarshalTo(r.Body, &device); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
waiter, err := c.cfg.Modify(func(cfg *config.Configuration) {
cfg.SetDevice(device)
if defaults {
cfg.Defaults.Device = device
} else {
cfg.SetDevice(device)
}
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)

View File

@ -91,7 +91,6 @@ func (c *mockedConfig) RemoveFolder(id string) (config.Waiter, error) {
func (c *mockedConfig) FolderPasswords(device protocol.DeviceID) map[string]string {
return nil
}
func (c *mockedConfig) Device(id protocol.DeviceID) (config.DeviceConfiguration, bool) {
return config.DeviceConfiguration{}, false
}
@ -112,6 +111,22 @@ func (c *mockedConfig) IgnoredFolder(device protocol.DeviceID, folder string) bo
return false
}
func (c *mockedConfig) DefaultFolder() config.FolderConfiguration {
return config.FolderConfiguration{}
}
func (c *mockedConfig) SetDefaultFolder(config.FolderConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (c *mockedConfig) DefaultDevice() config.DeviceConfiguration {
return config.DeviceConfiguration{}
}
func (c *mockedConfig) SetDefaultDevice(config.DeviceConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (c *mockedConfig) GlobalDiscoveryServers() []string {
return nil
}

View File

@ -30,7 +30,7 @@ import (
const (
OldestHandledVersion = 10
CurrentVersion = 33
CurrentVersion = 34
MaxRescanIntervalS = 365 * 24 * 60 * 60
)
@ -234,6 +234,8 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) error {
cfg.prepareIgnoredDevices(existingDevices)
cfg.Defaults.prepare(myID, existingDevices)
cfg.removeDeprecatedProtocols()
util.FillNilExceptDeprecated(cfg)
@ -245,7 +247,6 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) error {
}
func (cfg *Configuration) ensureMyDevice(myID protocol.DeviceID) {
// Ensure this device is present in the config
for _, device := range cfg.Devices {
if device.DeviceID == myID {
return
@ -586,3 +587,19 @@ func getFreePort(host string, ports ...int) (int, error) {
c.Close()
return addr.Port, nil
}
func (defaults *Defaults) prepare(myID protocol.DeviceID, existingDevices map[protocol.DeviceID]bool) {
ensureZeroForNodefault(&FolderConfiguration{}, &defaults.Folder)
ensureZeroForNodefault(&DeviceConfiguration{}, &defaults.Device)
defaults.Folder.prepare(myID, existingDevices)
defaults.Device.prepare(nil)
}
func ensureZeroForNodefault(empty interface{}, target interface{}) {
util.CopyMatchingTag(empty, target, "nodefault", func(v string) bool {
if len(v) > 0 && v != "true" {
panic(fmt.Sprintf(`unexpected tag value: %s. expected untagged or "true"`, v))
}
return len(v) > 0
})
}

View File

@ -32,6 +32,7 @@ type Configuration struct {
Options OptionsConfiguration `protobuf:"bytes,6,opt,name=options,proto3" json:"options" xml:"options"`
IgnoredDevices []ObservedDevice `protobuf:"bytes,7,rep,name=ignored_devices,json=ignoredDevices,proto3" json:"remoteIgnoredDevices" xml:"remoteIgnoredDevice"`
DeprecatedPendingDevices []ObservedDevice `protobuf:"bytes,8,rep,name=pending_devices,json=pendingDevices,proto3" json:"-" xml:"pendingDevice,omitempty"` // Deprecated: Do not use.
Defaults Defaults `protobuf:"bytes,9,opt,name=defaults,proto3" json:"defaults" xml:"defaults"`
}
func (m *Configuration) Reset() { *m = Configuration{} }
@ -67,50 +68,94 @@ func (m *Configuration) XXX_DiscardUnknown() {
var xxx_messageInfo_Configuration proto.InternalMessageInfo
type Defaults struct {
Folder FolderConfiguration `protobuf:"bytes,1,opt,name=folder,proto3" json:"folder" xml:"folder"`
Device DeviceConfiguration `protobuf:"bytes,2,opt,name=device,proto3" json:"device" xml:"device"`
}
func (m *Defaults) Reset() { *m = Defaults{} }
func (m *Defaults) String() string { return proto.CompactTextString(m) }
func (*Defaults) ProtoMessage() {}
func (*Defaults) Descriptor() ([]byte, []int) {
return fileDescriptor_baadf209193dc627, []int{1}
}
func (m *Defaults) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Defaults) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Defaults.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 *Defaults) XXX_Merge(src proto.Message) {
xxx_messageInfo_Defaults.Merge(m, src)
}
func (m *Defaults) XXX_Size() int {
return m.ProtoSize()
}
func (m *Defaults) XXX_DiscardUnknown() {
xxx_messageInfo_Defaults.DiscardUnknown(m)
}
var xxx_messageInfo_Defaults proto.InternalMessageInfo
func init() {
proto.RegisterType((*Configuration)(nil), "config.Configuration")
proto.RegisterType((*Defaults)(nil), "config.Defaults")
}
func init() { proto.RegisterFile("lib/config/config.proto", fileDescriptor_baadf209193dc627) }
var fileDescriptor_baadf209193dc627 = []byte{
// 575 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0x4d, 0x8b, 0xd3, 0x5e,
0x14, 0xc6, 0x93, 0x7f, 0x3b, 0xed, 0x7f, 0x32, 0x6f, 0x10, 0x45, 0x53, 0x5f, 0x72, 0x6b, 0xa8,
0x52, 0x65, 0xec, 0xc0, 0xb8, 0x11, 0x77, 0xd6, 0xe2, 0x58, 0x14, 0x1c, 0x02, 0x23, 0xea, 0x46,
0xda, 0xe6, 0x4e, 0x7a, 0xa1, 0xcd, 0x0d, 0xc9, 0x4d, 0x99, 0xf9, 0x08, 0xee, 0xc4, 0x4f, 0xe0,
0xd6, 0x6f, 0xd2, 0x5d, 0xbb, 0x70, 0xe1, 0xea, 0xc2, 0xb4, 0xbb, 0x2c, 0xb3, 0x74, 0x25, 0xf7,
0xad, 0x26, 0x10, 0x5d, 0x35, 0xe7, 0x3c, 0xcf, 0xf9, 0x9d, 0xc3, 0xd3, 0xc4, 0xb8, 0x39, 0x41,
0xc3, 0xa3, 0x11, 0x0e, 0xce, 0x91, 0x2f, 0x7f, 0x3a, 0x61, 0x84, 0x09, 0x36, 0x6b, 0xa2, 0xba,
0xd5, 0xca, 0x19, 0xce, 0xf1, 0xc4, 0x83, 0x91, 0x28, 0x92, 0x68, 0x40, 0x10, 0x0e, 0x84, 0xbb,
0xe0, 0xf2, 0xe0, 0x0c, 0x8d, 0x60, 0x99, 0xeb, 0x5e, 0xce, 0xe5, 0x27, 0xa8, 0xcc, 0xe2, 0xe4,
0x2c, 0x13, 0x6f, 0x10, 0x96, 0x79, 0xee, 0xe7, 0x3c, 0x38, 0x64, 0x42, 0x5c, 0x66, 0x6b, 0xe4,
0x6d, 0xc3, 0x18, 0x46, 0x33, 0xe8, 0x49, 0x69, 0x1b, 0x5e, 0x10, 0xf1, 0xe8, 0xfc, 0xa8, 0x19,
0x7b, 0x2f, 0xf2, 0xd3, 0xa6, 0x6b, 0xd4, 0x67, 0x30, 0x8a, 0x11, 0x0e, 0x2c, 0xbd, 0xa9, 0xb7,
0xb7, 0xba, 0x4f, 0x53, 0x0a, 0x54, 0x2b, 0xa3, 0xc0, 0xbc, 0x98, 0x4e, 0x9e, 0x39, 0xb2, 0x3e,
0x1c, 0x10, 0x12, 0x39, 0xbf, 0x28, 0xa8, 0xa0, 0x80, 0xa4, 0x8b, 0xd6, 0x6e, 0xbe, 0xef, 0xaa,
0x29, 0xf3, 0x9d, 0x51, 0x17, 0xe1, 0xc5, 0xd6, 0x7f, 0xcd, 0x4a, 0x7b, 0xe7, 0xf8, 0x76, 0x47,
0xa6, 0xfd, 0x92, 0xb7, 0x0b, 0x17, 0x74, 0xc1, 0x9c, 0x02, 0x8d, 0x2d, 0x95, 0x33, 0x19, 0x05,
0xbb, 0x7c, 0xa9, 0xa8, 0x1d, 0x57, 0x09, 0x8c, 0x2b, 0xe2, 0x8e, 0xad, 0x4a, 0x91, 0xdb, 0xe3,
0xed, 0xbf, 0x70, 0xe5, 0xcc, 0x86, 0x2b, 0x6a, 0xc7, 0x55, 0x82, 0xe9, 0x1a, 0x15, 0x3f, 0x41,
0x56, 0xb5, 0xa9, 0xb7, 0x77, 0x8e, 0x2d, 0xc5, 0x3c, 0x39, 0xeb, 0x17, 0x81, 0x0f, 0x18, 0x70,
0x45, 0x41, 0xe5, 0xe4, 0xac, 0x9f, 0x52, 0xc0, 0x66, 0x32, 0x0a, 0xb6, 0x39, 0xd3, 0x4f, 0x90,
0xf3, 0x75, 0xd9, 0x62, 0x92, 0xcb, 0x04, 0xf3, 0x83, 0x51, 0x65, 0xff, 0xa8, 0xb5, 0xc5, 0xa1,
0x0d, 0x05, 0x7d, 0xd3, 0x7b, 0x7e, 0x5a, 0xa4, 0x3e, 0x92, 0xd4, 0x2a, 0x93, 0x52, 0x0a, 0xf8,
0x58, 0x46, 0x81, 0xc1, 0xb9, 0xac, 0x60, 0x60, 0xae, 0xba, 0x5c, 0x33, 0xdf, 0x1b, 0x75, 0xf9,
0x22, 0x58, 0x35, 0x4e, 0xbf, 0xa3, 0xe8, 0x6f, 0x45, 0xbb, 0xb8, 0xa0, 0xa9, 0x72, 0x90, 0x43,
0x19, 0x05, 0x7b, 0x9c, 0x2d, 0x6b, 0xc7, 0x55, 0x8a, 0xf9, 0x5d, 0x37, 0x0e, 0x90, 0x1f, 0xe0,
0x08, 0x7a, 0x9f, 0x54, 0xd2, 0x75, 0x9e, 0xf4, 0x8d, 0xcd, 0x0a, 0xf9, 0x6e, 0x89, 0xc4, 0xbb,
0x63, 0x09, 0xbf, 0x1e, 0xc1, 0x29, 0x26, 0xb0, 0x2f, 0x86, 0x7b, 0x9b, 0xc4, 0x1b, 0x7c, 0x53,
0x89, 0xe8, 0xa4, 0x8b, 0xd6, 0xb5, 0x92, 0x7e, 0xb6, 0x68, 0x95, 0xb2, 0xdc, 0x7d, 0x54, 0xa8,
0xcd, 0xcf, 0xba, 0x71, 0x10, 0xc2, 0xc0, 0x43, 0x81, 0xbf, 0xb9, 0xf5, 0xff, 0x7f, 0xde, 0xfa,
0x4a, 0x26, 0x6d, 0xf5, 0x60, 0x18, 0xc1, 0xd1, 0x80, 0x40, 0xef, 0x54, 0x00, 0x24, 0x33, 0xa5,
0x40, 0x7f, 0x9c, 0x51, 0x70, 0x97, 0x1f, 0x1d, 0xe6, 0xb5, 0x43, 0x3c, 0x45, 0x04, 0x4e, 0x43,
0x72, 0xe9, 0x58, 0xba, 0xbb, 0x5f, 0xd0, 0xe2, 0xee, 0xeb, 0xf9, 0x95, 0xad, 0x2d, 0xaf, 0x6c,
0x6d, 0xbe, 0xb2, 0xf5, 0xe5, 0xca, 0xd6, 0xbf, 0xac, 0x6d, 0xed, 0xdb, 0xda, 0xd6, 0x97, 0x6b,
0x5b, 0xfb, 0xb9, 0xb6, 0xb5, 0x8f, 0x0f, 0x7d, 0x44, 0xc6, 0xc9, 0xb0, 0x33, 0xc2, 0xd3, 0xa3,
0xf8, 0x32, 0x18, 0x91, 0x31, 0x0a, 0xfc, 0xdc, 0xd3, 0x9f, 0xaf, 0x77, 0x58, 0xe3, 0x9f, 0xea,
0x93, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x97, 0x39, 0xe5, 0x72, 0xad, 0x04, 0x00, 0x00,
// 654 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xcd, 0x6e, 0xd3, 0x40,
0x10, 0xc7, 0xed, 0xa6, 0x4d, 0xda, 0xed, 0x17, 0x32, 0x08, 0x5c, 0x3e, 0xbc, 0x61, 0x15, 0x50,
0x41, 0xa5, 0x95, 0xca, 0x05, 0x71, 0x23, 0x44, 0x94, 0x0a, 0x24, 0x2a, 0xa3, 0x22, 0xe0, 0x82,
0x92, 0x78, 0xeb, 0xae, 0x94, 0xd8, 0x96, 0xbd, 0xae, 0xda, 0x47, 0xe0, 0x86, 0x78, 0x02, 0x4e,
0x48, 0xdc, 0x79, 0x88, 0xdc, 0x92, 0x23, 0xa7, 0x95, 0x9a, 0xdc, 0x7c, 0xf4, 0x91, 0x13, 0xda,
0x0f, 0xbb, 0xb6, 0x6a, 0xe0, 0x64, 0xcf, 0xfc, 0xff, 0xf3, 0x9b, 0xd5, 0x78, 0xc7, 0xe0, 0xc6,
0x80, 0xf4, 0x76, 0xfa, 0xbe, 0x77, 0x44, 0x5c, 0xf5, 0xd8, 0x0e, 0x42, 0x9f, 0xfa, 0x46, 0x5d,
0x46, 0x37, 0x5b, 0x05, 0xc3, 0x91, 0x3f, 0x70, 0x70, 0x28, 0x83, 0x38, 0xec, 0x52, 0xe2, 0x7b,
0xd2, 0x5d, 0x72, 0x39, 0xf8, 0x84, 0xf4, 0x71, 0x95, 0xeb, 0x6e, 0xc1, 0xe5, 0xc6, 0xa4, 0xca,
0x82, 0x0a, 0x96, 0x81, 0xd3, 0x0d, 0xaa, 0x3c, 0xf7, 0x0a, 0x1e, 0x3f, 0xe0, 0x42, 0x54, 0x65,
0xdb, 0x28, 0xda, 0x7a, 0x11, 0x0e, 0x4f, 0xb0, 0xa3, 0xa4, 0x25, 0x7c, 0x4a, 0xe5, 0x2b, 0xfa,
0xde, 0x00, 0xab, 0xcf, 0x8b, 0xd5, 0x86, 0x0d, 0x1a, 0x27, 0x38, 0x8c, 0x88, 0xef, 0x99, 0x7a,
0x53, 0xdf, 0x5c, 0x68, 0x3f, 0x49, 0x18, 0xcc, 0x52, 0x29, 0x83, 0xc6, 0xe9, 0x70, 0xf0, 0x14,
0xa9, 0x78, 0xab, 0x4b, 0x69, 0x88, 0x7e, 0x33, 0x58, 0x23, 0x1e, 0x4d, 0xc6, 0xad, 0x95, 0x62,
0xde, 0xce, 0xaa, 0x8c, 0x77, 0xa0, 0x21, 0x87, 0x17, 0x99, 0x73, 0xcd, 0xda, 0xe6, 0xf2, 0xee,
0xad, 0x6d, 0x35, 0xed, 0x17, 0x22, 0x5d, 0x3a, 0x41, 0x1b, 0x8e, 0x18, 0xd4, 0x78, 0x53, 0x55,
0x93, 0x32, 0xb8, 0x22, 0x9a, 0xca, 0x18, 0xd9, 0x99, 0xc0, 0xb9, 0x72, 0xdc, 0x91, 0x59, 0x2b,
0x73, 0x3b, 0x22, 0xfd, 0x17, 0xae, 0xaa, 0xc9, 0xb9, 0x32, 0x46, 0x76, 0x26, 0x18, 0x36, 0xa8,
0xb9, 0x31, 0x31, 0xe7, 0x9b, 0xfa, 0xe6, 0xf2, 0xae, 0x99, 0x31, 0xf7, 0x0e, 0xf7, 0xcb, 0xc0,
0xfb, 0x1c, 0x38, 0x65, 0xb0, 0xb6, 0x77, 0xb8, 0x9f, 0x30, 0xc8, 0x6b, 0x52, 0x06, 0x97, 0x04,
0xd3, 0x8d, 0x09, 0xfa, 0x3a, 0x69, 0x71, 0xc9, 0xe6, 0x82, 0xf1, 0x01, 0xcc, 0xf3, 0x2f, 0x6a,
0x2e, 0x08, 0xe8, 0x46, 0x06, 0x7d, 0xdd, 0x79, 0x76, 0x50, 0xa6, 0x3e, 0x54, 0xd4, 0x79, 0x2e,
0x25, 0x0c, 0x8a, 0xb2, 0x94, 0x41, 0x20, 0xb8, 0x3c, 0xe0, 0x60, 0xa1, 0xda, 0x42, 0x33, 0xde,
0x83, 0x86, 0xba, 0x08, 0x66, 0x5d, 0xd0, 0x6f, 0x67, 0xf4, 0x37, 0x32, 0x5d, 0x6e, 0xd0, 0xcc,
0xe6, 0xa0, 0x8a, 0x52, 0x06, 0x57, 0x05, 0x5b, 0xc5, 0xc8, 0xce, 0x14, 0xe3, 0x87, 0x0e, 0xd6,
0x89, 0xeb, 0xf9, 0x21, 0x76, 0x3e, 0x65, 0x93, 0x6e, 0x88, 0x49, 0x5f, 0xcf, 0x5b, 0xa8, 0xbb,
0x25, 0x27, 0xde, 0x3e, 0x56, 0xf0, 0x6b, 0x21, 0x1e, 0xfa, 0x14, 0xef, 0xcb, 0xe2, 0x4e, 0x3e,
0xf1, 0x0d, 0xd1, 0xa9, 0x42, 0x44, 0xc9, 0xb8, 0x75, 0xb5, 0x22, 0x9f, 0x8e, 0x5b, 0x95, 0x2c,
0x7b, 0x8d, 0x94, 0x62, 0xe3, 0xb3, 0x0e, 0xd6, 0x03, 0xec, 0x39, 0xc4, 0x73, 0xf3, 0xb3, 0x2e,
0xfe, 0xf3, 0xac, 0x2f, 0xd5, 0xa4, 0xcd, 0x0e, 0x0e, 0x42, 0xdc, 0xef, 0x52, 0xec, 0x1c, 0x48,
0x80, 0x62, 0x26, 0x0c, 0xea, 0x8f, 0x52, 0x06, 0xef, 0x88, 0x43, 0x07, 0x45, 0x6d, 0xcb, 0x1f,
0x12, 0x8a, 0x87, 0x01, 0x3d, 0x43, 0xa6, 0x6e, 0xaf, 0x95, 0xb4, 0xc8, 0x38, 0x00, 0x8b, 0x0e,
0x3e, 0xea, 0xc6, 0x03, 0x1a, 0x99, 0x4b, 0xe2, 0x93, 0x5c, 0xb9, 0xb8, 0x99, 0x32, 0xdf, 0x46,
0x6a, 0x52, 0xb9, 0x33, 0x65, 0x70, 0x4d, 0xdd, 0x47, 0x99, 0x40, 0x76, 0xae, 0xa1, 0x9f, 0x3a,
0x58, 0xcc, 0x4a, 0x8d, 0xb7, 0xa0, 0x2e, 0x57, 0x40, 0xac, 0xe8, 0x7f, 0xd6, 0xc9, 0x52, 0x7d,
0x54, 0xc9, 0xa5, 0x6d, 0x52, 0x79, 0x0e, 0x95, 0x63, 0x33, 0xe7, 0xca, 0xd0, 0xaa, 0x5d, 0xca,
0xa1, 0xb2, 0xe4, 0xd2, 0x2a, 0xa9, 0x7c, 0xfb, 0xd5, 0xe8, 0xdc, 0xd2, 0x26, 0xe7, 0x96, 0x36,
0x9a, 0x5a, 0xfa, 0x64, 0x6a, 0xe9, 0x5f, 0x66, 0x96, 0xf6, 0x6d, 0x66, 0xe9, 0x93, 0x99, 0xa5,
0xfd, 0x9a, 0x59, 0xda, 0xc7, 0x07, 0x2e, 0xa1, 0xc7, 0x71, 0x6f, 0xbb, 0xef, 0x0f, 0x77, 0xa2,
0x33, 0xaf, 0x4f, 0x8f, 0x89, 0xe7, 0x16, 0xde, 0x2e, 0x7e, 0x63, 0xbd, 0xba, 0xf8, 0x67, 0x3d,
0xfe, 0x13, 0x00, 0x00, 0xff, 0xff, 0x50, 0xe9, 0xd5, 0x50, 0xb6, 0x05, 0x00, 0x00,
}
func (m *Configuration) Marshal() (dAtA []byte, err error) {
@ -133,6 +178,16 @@ func (m *Configuration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
{
size, err := m.Defaults.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintConfig(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x4a
if len(m.DeprecatedPendingDevices) > 0 {
for iNdEx := len(m.DeprecatedPendingDevices) - 1; iNdEx >= 0; iNdEx-- {
{
@ -227,6 +282,49 @@ func (m *Configuration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *Defaults) 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 *Defaults) MarshalTo(dAtA []byte) (int, error) {
size := m.ProtoSize()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Defaults) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
{
size, err := m.Device.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintConfig(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
{
size, err := m.Folder.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintConfig(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
return len(dAtA) - i, nil
}
func encodeVarintConfig(dAtA []byte, offset int, v uint64) int {
offset -= sovConfig(v)
base := offset
@ -277,6 +375,21 @@ func (m *Configuration) ProtoSize() (n int) {
n += 1 + l + sovConfig(uint64(l))
}
}
l = m.Defaults.ProtoSize()
n += 1 + l + sovConfig(uint64(l))
return n
}
func (m *Defaults) ProtoSize() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = m.Folder.ProtoSize()
n += 1 + l + sovConfig(uint64(l))
l = m.Device.ProtoSize()
n += 1 + l + sovConfig(uint64(l))
return n
}
@ -569,6 +682,158 @@ func (m *Configuration) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Defaults", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConfig
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthConfig
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthConfig
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Defaults.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipConfig(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthConfig
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthConfig
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Defaults) 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 ErrIntOverflowConfig
}
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: Defaults: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Defaults: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Folder", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConfig
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthConfig
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthConfig
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Folder.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Device", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConfig
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthConfig
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthConfig
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Device.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipConfig(dAtA[iNdEx:])

View File

@ -40,52 +40,93 @@ func init() {
}
func TestDefaultValues(t *testing.T) {
expected := OptionsConfiguration{
RawListenAddresses: []string{"default"},
RawGlobalAnnServers: []string{"default"},
GlobalAnnEnabled: true,
LocalAnnEnabled: true,
LocalAnnPort: 21027,
LocalAnnMCAddr: "[ff12::8384]:21027",
MaxSendKbps: 0,
MaxRecvKbps: 0,
ReconnectIntervalS: 60,
RelaysEnabled: true,
RelayReconnectIntervalM: 10,
StartBrowser: true,
NATEnabled: true,
NATLeaseM: 60,
NATRenewalM: 30,
NATTimeoutS: 10,
RestartOnWakeup: true,
AutoUpgradeIntervalH: 12,
KeepTemporariesH: 24,
CacheIgnoredFiles: false,
ProgressUpdateIntervalS: 5,
LimitBandwidthInLan: false,
MinHomeDiskFree: Size{1, "%"},
URURL: "https://data.syncthing.net/newdata",
URInitialDelayS: 1800,
URPostInsecurely: false,
ReleasesURL: "https://upgrades.syncthing.net/meta.json",
AlwaysLocalNets: []string{},
OverwriteRemoteDevNames: false,
TempIndexMinBlocks: 10,
UnackedNotificationIDs: []string{"authenticationUserAndPassword"},
DefaultFolderPath: "~",
SetLowPriority: true,
CRURL: "https://crash.syncthing.net/newcrash",
CREnabled: true,
StunKeepaliveStartS: 180,
StunKeepaliveMinS: 20,
RawStunServers: []string{"default"},
AnnounceLANAddresses: true,
FeatureFlags: []string{},
size, err := ParseSize("1%")
if err != nil {
t.Fatal(err)
}
expected := Configuration{
Version: CurrentVersion,
Folders: []FolderConfiguration{},
Options: OptionsConfiguration{
RawListenAddresses: []string{"default"},
RawGlobalAnnServers: []string{"default"},
GlobalAnnEnabled: true,
LocalAnnEnabled: true,
LocalAnnPort: 21027,
LocalAnnMCAddr: "[ff12::8384]:21027",
MaxSendKbps: 0,
MaxRecvKbps: 0,
ReconnectIntervalS: 60,
RelaysEnabled: true,
RelayReconnectIntervalM: 10,
StartBrowser: true,
NATEnabled: true,
NATLeaseM: 60,
NATRenewalM: 30,
NATTimeoutS: 10,
RestartOnWakeup: true,
AutoUpgradeIntervalH: 12,
KeepTemporariesH: 24,
CacheIgnoredFiles: false,
ProgressUpdateIntervalS: 5,
LimitBandwidthInLan: false,
MinHomeDiskFree: Size{1, "%"},
URURL: "https://data.syncthing.net/newdata",
URInitialDelayS: 1800,
URPostInsecurely: false,
ReleasesURL: "https://upgrades.syncthing.net/meta.json",
AlwaysLocalNets: []string{},
OverwriteRemoteDevNames: false,
TempIndexMinBlocks: 10,
UnackedNotificationIDs: []string{"authenticationUserAndPassword"},
SetLowPriority: true,
CRURL: "https://crash.syncthing.net/newcrash",
CREnabled: true,
StunKeepaliveStartS: 180,
StunKeepaliveMinS: 20,
RawStunServers: []string{"default"},
AnnounceLANAddresses: true,
FeatureFlags: []string{},
},
Defaults: Defaults{
Folder: FolderConfiguration{
FilesystemType: fs.FilesystemTypeBasic,
Path: "~",
Type: FolderTypeSendReceive,
Devices: []FolderDeviceConfiguration{{DeviceID: device1}},
RescanIntervalS: 3600,
FSWatcherEnabled: true,
FSWatcherDelayS: 10,
IgnorePerms: false,
AutoNormalize: true,
MinDiskFree: size,
Versioning: VersioningConfiguration{
CleanupIntervalS: 3600,
Params: map[string]string{},
},
MaxConflicts: 10,
WeakHashThresholdPct: 25,
MarkerName: ".stfolder",
MaxConcurrentWrites: 2,
},
Device: DeviceConfiguration{
Addresses: []string{"dynamic"},
AllowedNetworks: []string{},
Compression: protocol.CompressionMetadata,
IgnoredFolders: []ObservedFolder{},
},
},
IgnoredDevices: []ObservedDevice{},
}
expected.Devices = []DeviceConfiguration{expected.Defaults.Device.Copy()}
expected.Devices[0].DeviceID = device1
expected.Devices[0].Name, _ = os.Hostname()
cfg := New(device1)
cfg.GUI = GUIConfiguration{}
cfg.LDAP = LDAPConfiguration{}
if diff, equal := messagediff.PrettyDiff(expected, cfg.Options); !equal {
if diff, equal := messagediff.PrettyDiff(expected, cfg); !equal {
t.Errorf("Default config differs. Diff:\n%s", diff)
}
}
@ -222,7 +263,6 @@ func TestOverriddenValues(t *testing.T) {
OverwriteRemoteDevNames: true,
TempIndexMinBlocks: 100,
UnackedNotificationIDs: []string{"asdfasdf"},
DefaultFolderPath: "/media/syncthing",
SetLowPriority: false,
CRURL: "https://localhost/newcrash",
CREnabled: false,
@ -231,6 +271,7 @@ func TestOverriddenValues(t *testing.T) {
RawStunServers: []string{"foo"},
FeatureFlags: []string{"feature"},
}
expectedPath := "/media/syncthing"
os.Unsetenv("STNOUPGRADE")
cfg, cfgCancel, err := copyAndLoad("testdata/overridenvalues.xml", device1)
@ -242,6 +283,10 @@ func TestOverriddenValues(t *testing.T) {
if diff, equal := messagediff.PrettyDiff(expected, cfg.Options()); !equal {
t.Errorf("Overridden config differs. Diff:\n%s", diff)
}
if path := cfg.DefaultFolder().Path; path != expectedPath {
t.Errorf("Default folder path is %v, expected %v", path, expectedPath)
}
}
func TestDeviceAddressesDynamic(t *testing.T) {
@ -1159,13 +1204,29 @@ func TestMaxConcurrentFolders(t *testing.T) {
}
}
func adjustDeviceConfiguration(cfg *DeviceConfiguration, id protocol.DeviceID, name string) {
cfg.DeviceID = id
cfg.Name = name
}
func adjustFolderConfiguration(cfg *FolderConfiguration, id, label string, fsType fs.FilesystemType, path string) {
cfg.ID = id
cfg.Label = label
cfg.FilesystemType = fsType
cfg.Path = path
}
// defaultConfigAsMap returns a valid default config as a JSON-decoded
// map[string]interface{}. This is useful to override random elements and
// re-encode into JSON.
func defaultConfigAsMap() map[string]interface{} {
cfg := New(device1)
cfg.Devices = append(cfg.Devices, NewDeviceConfiguration(device2, "name"))
cfg.Folders = append(cfg.Folders, NewFolderConfiguration(device1, "default", "default", fs.FilesystemTypeBasic, "/tmp"))
dev := cfg.Defaults.Device.Copy()
adjustDeviceConfiguration(&dev, device2, "name")
cfg.Devices = append(cfg.Devices, dev)
folder := cfg.Defaults.Folder.Copy()
adjustFolderConfiguration(&folder, "default", "default", fs.FilesystemTypeBasic, "/tmp")
cfg.Folders = append(cfg.Folders, folder)
bs, err := json.Marshal(cfg)
if err != nil {
// can't happen
@ -1260,7 +1321,9 @@ func TestInternalVersioningConfiguration(t *testing.T) {
// reasonable.
cfg := New(device1)
cfg.Folders = append(cfg.Folders, NewFolderConfiguration(device1, "default", "default", fs.FilesystemTypeBasic, "/tmp"))
folder := cfg.Defaults.Folder.Copy()
adjustFolderConfiguration(&folder, "default", "default", fs.FilesystemTypeBasic, "/tmp")
cfg.Folders = append(cfg.Folders, folder)
cfg.Folders[0].Versioning = VersioningConfiguration{
Type: "foo",
Params: map[string]string{"bar": "baz"},

View File

@ -8,23 +8,8 @@ package config
import (
"sort"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/util"
)
func NewDeviceConfiguration(id protocol.DeviceID, name string) DeviceConfiguration {
d := DeviceConfiguration{
DeviceID: id,
Name: name,
}
util.SetDefaults(&d)
d.prepare(nil)
return d
}
func (cfg DeviceConfiguration) Copy() DeviceConfiguration {
c := cfg
c.Addresses = make([]string, len(cfg.Addresses))
@ -40,9 +25,6 @@ func (cfg *DeviceConfiguration) prepare(sharedFolders []string) {
if len(cfg.Addresses) == 0 || len(cfg.Addresses) == 1 && cfg.Addresses[0] == "" {
cfg.Addresses = []string{"dynamic"}
}
if len(cfg.AllowedNetworks) == 0 {
cfg.AllowedNetworks = []string{}
}
ignoredFolders := deduplicateObservedFoldersToMap(cfg.IgnoredFolders)

View File

@ -26,14 +26,14 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type DeviceConfiguration struct {
DeviceID github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"deviceID" xml:"id,attr"`
DeviceID github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"deviceID" xml:"id,attr" nodefault:"true"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name" xml:"name,attr,omitempty"`
Addresses []string `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses" xml:"address,omitempty" default:"dynamic"`
Compression protocol.Compression `protobuf:"varint,4,opt,name=compression,proto3,enum=protocol.Compression" json:"compression" xml:"compression,attr"`
CertName string `protobuf:"bytes,5,opt,name=cert_name,json=certName,proto3" json:"certName" xml:"certName,attr,omitempty"`
Introducer bool `protobuf:"varint,6,opt,name=introducer,proto3" json:"introducer" xml:"introducer,attr"`
SkipIntroductionRemovals bool `protobuf:"varint,7,opt,name=skip_introduction_removals,json=skipIntroductionRemovals,proto3" json:"skipIntroductionRemovals" xml:"skipIntroductionRemovals,attr"`
IntroducedBy github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,8,opt,name=introduced_by,json=introducedBy,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"introducedBy" xml:"introducedBy,attr"`
IntroducedBy github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,8,opt,name=introduced_by,json=introducedBy,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"introducedBy" xml:"introducedBy,attr" nodefault:"true"`
Paused bool `protobuf:"varint,9,opt,name=paused,proto3" json:"paused" xml:"paused"`
AllowedNetworks []string `protobuf:"bytes,10,rep,name=allowed_networks,json=allowedNetworks,proto3" json:"allowedNetworks" xml:"allowedNetwork,omitempty"`
AutoAcceptFolders bool `protobuf:"varint,11,opt,name=auto_accept_folders,json=autoAcceptFolders,proto3" json:"autoAcceptFolders" xml:"autoAcceptFolders"`
@ -88,71 +88,72 @@ func init() {
}
var fileDescriptor_744b782bd13071dd = []byte{
// 1009 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xbd, 0x6f, 0xdb, 0x46,
0x1c, 0x15, 0xeb, 0xc4, 0xb6, 0xce, 0x96, 0x65, 0xd3, 0x88, 0xc3, 0x18, 0x88, 0x4e, 0x50, 0x35,
0x28, 0x68, 0x22, 0x17, 0x6e, 0x27, 0xa3, 0x2d, 0x50, 0xc6, 0x68, 0x63, 0x18, 0x4d, 0xdc, 0x2b,
0xba, 0x78, 0x61, 0x49, 0xde, 0x59, 0x39, 0x58, 0xfc, 0x28, 0x79, 0x54, 0x2c, 0xa0, 0x43, 0xc7,
0x16, 0xe8, 0x50, 0x64, 0xed, 0x52, 0x74, 0xe8, 0xd0, 0xff, 0xa3, 0x80, 0x37, 0x6b, 0x2c, 0x3a,
0x1c, 0x10, 0x7b, 0xe3, 0xc8, 0x31, 0x53, 0x71, 0x47, 0x8a, 0x3a, 0xca, 0x71, 0x50, 0x20, 0xdb,
0xdd, 0x7b, 0xef, 0xde, 0xef, 0x83, 0xbf, 0x3b, 0x82, 0xee, 0x90, 0x3a, 0x3b, 0x6e, 0xe0, 0x9f,
0xd0, 0xc1, 0x0e, 0x26, 0x23, 0xea, 0x92, 0x7c, 0x93, 0x44, 0x36, 0xa3, 0x81, 0xdf, 0x0f, 0xa3,
0x80, 0x05, 0xfa, 0x62, 0x0e, 0x6e, 0x6f, 0x09, 0xb5, 0x84, 0xdc, 0x60, 0xb8, 0xe3, 0x90, 0x30,
0xe7, 0xb7, 0xef, 0x29, 0x2e, 0x81, 0x13, 0x93, 0x68, 0x44, 0x70, 0x41, 0xd5, 0xc9, 0x19, 0xcb,
0x97, 0x9d, 0xbf, 0xd7, 0xc1, 0xe6, 0xbe, 0x8c, 0xf1, 0x58, 0x8d, 0xa1, 0xff, 0xa5, 0x81, 0x7a,
0x1e, 0xdb, 0xa2, 0xd8, 0xd0, 0xda, 0x5a, 0x6f, 0xd5, 0xfc, 0x45, 0x3b, 0xe7, 0xb0, 0xf6, 0x2f,
0x87, 0x1f, 0x0f, 0x28, 0x7b, 0x9e, 0x38, 0x7d, 0x37, 0xf0, 0x76, 0xe2, 0xb1, 0xef, 0xb2, 0xe7,
0xd4, 0x1f, 0x28, 0x2b, 0x35, 0xa3, 0x7e, 0xee, 0x7e, 0xb0, 0x7f, 0xc9, 0xe1, 0xf2, 0x74, 0x9d,
0x72, 0xb8, 0x8c, 0x8b, 0x75, 0xc6, 0x61, 0xe3, 0xcc, 0x1b, 0xee, 0x75, 0x28, 0x7e, 0x68, 0x33,
0x16, 0x75, 0xd2, 0x8b, 0xee, 0x52, 0xb1, 0xce, 0x2e, 0xba, 0xa5, 0xee, 0xa7, 0x49, 0x57, 0x7b,
0x39, 0xe9, 0x96, 0x1e, 0x68, 0xca, 0x60, 0xfd, 0x08, 0xdc, 0xf2, 0x6d, 0x8f, 0x18, 0xef, 0xb5,
0xb5, 0x5e, 0xdd, 0xfc, 0x24, 0xe5, 0x50, 0xee, 0x33, 0x0e, 0xef, 0x49, 0x67, 0xb1, 0x91, 0x7e,
0x0f, 0x03, 0x8f, 0x32, 0xe2, 0x85, 0x6c, 0x2c, 0xa2, 0x6c, 0xbe, 0x01, 0x47, 0xf2, 0xa4, 0x7e,
0x06, 0xea, 0x36, 0xc6, 0x11, 0x89, 0x63, 0x12, 0x1b, 0x0b, 0xed, 0x85, 0x5e, 0xdd, 0x3c, 0x4e,
0x39, 0x9c, 0x81, 0x19, 0x87, 0x0f, 0xa4, 0x77, 0x81, 0x28, 0xce, 0x6d, 0x4c, 0x4e, 0xec, 0x64,
0xc8, 0xf6, 0x3a, 0x78, 0xec, 0xdb, 0x1e, 0x75, 0x45, 0xac, 0x8d, 0x6b, 0xba, 0xd7, 0x17, 0xdd,
0xa5, 0x42, 0x80, 0x66, 0xbe, 0xfa, 0x08, 0xac, 0xb8, 0x81, 0x17, 0x8a, 0x1d, 0x0d, 0x7c, 0xe3,
0x56, 0x5b, 0xeb, 0xad, 0xed, 0xde, 0xe9, 0x97, 0xed, 0x7c, 0x3c, 0x23, 0xcd, 0x4f, 0x53, 0x0e,
0x55, 0x75, 0xc6, 0xe1, 0x96, 0x4c, 0x4a, 0xc1, 0xca, 0x9e, 0xae, 0xcf, 0x83, 0x48, 0x3d, 0xaa,
0x13, 0x50, 0x77, 0x49, 0xc4, 0x2c, 0xd9, 0xc8, 0xdb, 0xb2, 0x91, 0x4f, 0xc4, 0x67, 0x12, 0xe0,
0xd3, 0xbc, 0x99, 0xf7, 0x73, 0xef, 0x02, 0x78, 0x43, 0x43, 0xef, 0xde, 0xc0, 0xa1, 0xd2, 0x45,
0x3f, 0x06, 0x80, 0xfa, 0x2c, 0x0a, 0x70, 0xe2, 0x92, 0xc8, 0x58, 0x6c, 0x6b, 0xbd, 0x65, 0x73,
0x2f, 0xe5, 0x50, 0x41, 0x33, 0x0e, 0xef, 0xe4, 0x03, 0x51, 0x42, 0x65, 0x11, 0xcd, 0x39, 0x0c,
0x29, 0xe7, 0xf4, 0x3f, 0x34, 0xb0, 0x1d, 0x9f, 0xd2, 0xd0, 0x9a, 0x62, 0x62, 0x92, 0xad, 0x88,
0x78, 0xc1, 0xc8, 0x1e, 0xc6, 0xc6, 0x92, 0x0c, 0x86, 0x53, 0x0e, 0x0d, 0xa1, 0x3a, 0x50, 0x44,
0xa8, 0xd0, 0x64, 0x1c, 0xbe, 0x2f, 0x43, 0xdf, 0x24, 0x28, 0x13, 0xb9, 0xff, 0x56, 0x05, 0xba,
0x31, 0x82, 0xfe, 0xa7, 0x06, 0x1a, 0x65, 0xce, 0xd8, 0x72, 0xc6, 0xc6, 0xb2, 0xbc, 0x5c, 0x3f,
0xbe, 0xd3, 0xe5, 0x4a, 0x39, 0x5c, 0x9d, 0xb9, 0x9a, 0xe3, 0x8c, 0xc3, 0xbb, 0xd5, 0x1e, 0x62,
0x73, 0x5c, 0x26, 0xbf, 0x71, 0x0d, 0x15, 0x97, 0x0b, 0x55, 0x1c, 0xf4, 0x5d, 0xb0, 0x18, 0xda,
0x49, 0x4c, 0xb0, 0x51, 0x97, 0x8d, 0xdb, 0x4e, 0x39, 0x2c, 0x90, 0x8c, 0xc3, 0x55, 0xe9, 0x9e,
0x6f, 0x3b, 0xa8, 0xc0, 0xf5, 0x1f, 0xc0, 0xba, 0x3d, 0x1c, 0x06, 0x2f, 0x08, 0xb6, 0x7c, 0xc2,
0x5e, 0x04, 0xd1, 0x69, 0x6c, 0x00, 0x79, 0x7b, 0xbe, 0x4e, 0x39, 0x6c, 0x16, 0xdc, 0xd3, 0x82,
0xca, 0x38, 0x6c, 0xe5, 0x77, 0xa8, 0x82, 0x57, 0x67, 0xca, 0xb8, 0x89, 0x44, 0xf3, 0x76, 0xfa,
0x77, 0x60, 0xd3, 0x4e, 0x58, 0x60, 0xd9, 0xae, 0x4b, 0x42, 0x66, 0x9d, 0x04, 0x43, 0x4c, 0xa2,
0xd8, 0x58, 0x91, 0xe9, 0x7f, 0x98, 0x72, 0xb8, 0x21, 0xe8, 0xcf, 0x25, 0xfb, 0x45, 0x4e, 0x96,
0x7d, 0xba, 0xc6, 0x74, 0xd0, 0x75, 0xb5, 0xfe, 0x0c, 0x34, 0x3c, 0xfb, 0xcc, 0x8a, 0x89, 0x8f,
0xad, 0x53, 0x27, 0x8c, 0x8d, 0xd5, 0xb6, 0xd6, 0xbb, 0x6d, 0x7e, 0x20, 0xee, 0xa1, 0x67, 0x9f,
0x7d, 0x43, 0x7c, 0x7c, 0xe8, 0x84, 0xc2, 0x75, 0x43, 0xba, 0x2a, 0x58, 0xe7, 0x35, 0x87, 0x0b,
0xd4, 0x67, 0x48, 0x15, 0x4e, 0x0d, 0x23, 0xe2, 0x8e, 0x72, 0xc3, 0x46, 0xc5, 0x10, 0x11, 0x77,
0x34, 0x6f, 0x38, 0xc5, 0x2a, 0x86, 0x53, 0x50, 0xf7, 0x41, 0x93, 0x0e, 0xfc, 0x20, 0x22, 0xb8,
0xac, 0x7f, 0xad, 0xbd, 0xd0, 0x5b, 0xd9, 0xdd, 0xea, 0xe7, 0xff, 0x82, 0xfe, 0xb3, 0xe2, 0x5f,
0x90, 0xd7, 0x64, 0x3e, 0x12, 0x63, 0x97, 0x72, 0xb8, 0x56, 0x1c, 0x9b, 0x35, 0x66, 0x33, 0x1f,
0x20, 0x15, 0xee, 0xa0, 0x39, 0x99, 0xfe, 0xb3, 0x06, 0x9a, 0x21, 0xf1, 0x31, 0xf5, 0x07, 0x65,
0xc0, 0xe6, 0x5b, 0x03, 0x3e, 0x11, 0x01, 0x2f, 0x39, 0x34, 0xf6, 0x49, 0x18, 0x11, 0xd7, 0x66,
0x04, 0x1f, 0xe5, 0x06, 0x85, 0x67, 0xca, 0xa1, 0xf6, 0xa8, 0x7c, 0x6e, 0x42, 0x95, 0x53, 0x46,
0xc3, 0xd0, 0xd0, 0x5a, 0x85, 0x8b, 0xf5, 0xdf, 0x34, 0xd0, 0xcc, 0xbb, 0xf9, 0x7d, 0x42, 0x62,
0x66, 0x9d, 0x52, 0xc7, 0x58, 0x97, 0xfd, 0x8c, 0x2f, 0x39, 0x6c, 0x7c, 0x25, 0xda, 0x24, 0x99,
0x43, 0x6a, 0xa6, 0x1c, 0x36, 0x3c, 0x15, 0x28, 0x0b, 0xae, 0xa0, 0xd3, 0x26, 0xa7, 0x17, 0xdd,
0x39, 0xf9, 0x3c, 0xf0, 0x72, 0xd2, 0xad, 0x46, 0x40, 0x15, 0xde, 0xd1, 0x3f, 0x03, 0xf5, 0xc4,
0x67, 0x51, 0x12, 0x33, 0x82, 0x8d, 0x0d, 0x39, 0x93, 0x6d, 0xf1, 0x4b, 0x29, 0xc1, 0x8c, 0xc3,
0xa6, 0xcc, 0xa0, 0x44, 0x3a, 0x68, 0xc6, 0xca, 0xea, 0xc4, 0x5b, 0xc6, 0x88, 0x35, 0x48, 0xa8,
0x15, 0x06, 0x11, 0x33, 0xf4, 0x59, 0x75, 0x48, 0x52, 0x5f, 0x7e, 0x7b, 0x70, 0x14, 0x44, 0x4c,
0x54, 0x17, 0xa9, 0x40, 0x59, 0x5d, 0x05, 0x55, 0xab, 0xab, 0xca, 0xe7, 0x01, 0x51, 0x5d, 0x25,
0x02, 0x9a, 0xf2, 0x09, 0x15, 0x5b, 0xf3, 0xf0, 0xfc, 0x55, 0xab, 0x36, 0x79, 0xd5, 0xaa, 0x9d,
0x5f, 0xb6, 0xb4, 0xc9, 0x65, 0x4b, 0xfb, 0xf5, 0xaa, 0x55, 0xfb, 0xfd, 0xaa, 0xa5, 0x4d, 0xae,
0x5a, 0xb5, 0x7f, 0xae, 0x5a, 0xb5, 0xe3, 0x07, 0xff, 0xe3, 0x5d, 0xcb, 0x27, 0xc6, 0x59, 0x94,
0xef, 0xdb, 0x47, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x01, 0x84, 0xd4, 0x09, 0x09, 0x00,
0x00,
// 1026 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xbf, 0x6f, 0xdb, 0x46,
0x18, 0x15, 0xeb, 0xc4, 0xb6, 0xce, 0x3f, 0x64, 0xd3, 0x88, 0xc3, 0x18, 0x88, 0x4e, 0x50, 0x35,
0x28, 0x68, 0x22, 0x17, 0x6e, 0x27, 0xa3, 0x2d, 0x50, 0xc6, 0x68, 0x63, 0x18, 0x4d, 0x5c, 0x16,
0x5d, 0xbc, 0xb0, 0x24, 0xef, 0xac, 0x1c, 0x2c, 0xf2, 0x58, 0xf2, 0xa8, 0x58, 0x40, 0xff, 0x80,
0x76, 0x2b, 0x02, 0x74, 0xea, 0x92, 0xf6, 0xdf, 0xe8, 0xd0, 0xd5, 0x9b, 0x35, 0x16, 0x1d, 0x0e,
0x88, 0xbd, 0x71, 0x29, 0xc0, 0x31, 0x53, 0x71, 0x77, 0x14, 0x45, 0xca, 0x51, 0x50, 0xa0, 0x1b,
0xef, 0xbd, 0x77, 0xef, 0xdd, 0xf7, 0xe9, 0xbb, 0x13, 0xe8, 0x0c, 0x88, 0xbb, 0xeb, 0xd1, 0xe0,
0x94, 0xf4, 0x77, 0x11, 0x1e, 0x12, 0x0f, 0xab, 0x45, 0x12, 0x39, 0x8c, 0xd0, 0xa0, 0x17, 0x46,
0x94, 0x51, 0x7d, 0x51, 0x81, 0x3b, 0xdb, 0x42, 0x2d, 0x21, 0x8f, 0x0e, 0x76, 0x5d, 0x1c, 0x2a,
0x7e, 0xe7, 0x5e, 0xc9, 0x85, 0xba, 0x31, 0x8e, 0x86, 0x18, 0xe5, 0x54, 0x1d, 0x9f, 0x33, 0xf5,
0xd9, 0xfe, 0x67, 0x03, 0x6c, 0x1d, 0xc8, 0x8c, 0xc7, 0xe5, 0x0c, 0xfd, 0x4f, 0x0d, 0xd4, 0x55,
0xb6, 0x4d, 0x90, 0xa1, 0xb5, 0xb4, 0xee, 0xaa, 0xf9, 0x9b, 0x76, 0xc1, 0x61, 0xed, 0x6f, 0x0e,
0x3f, 0xee, 0x13, 0xf6, 0x3c, 0x71, 0x7b, 0x1e, 0xf5, 0x77, 0xe3, 0x51, 0xe0, 0xb1, 0xe7, 0x24,
0xe8, 0x97, 0xbe, 0xca, 0x27, 0xea, 0x29, 0xf7, 0xc3, 0x83, 0x2b, 0x0e, 0x97, 0x27, 0xdf, 0x29,
0x87, 0xcb, 0x28, 0xff, 0xce, 0x38, 0x6c, 0x9e, 0xfb, 0x83, 0xfd, 0x36, 0x41, 0x0f, 0x1d, 0xc6,
0xa2, 0x76, 0x2b, 0xa0, 0x08, 0x9f, 0x3a, 0xc9, 0x80, 0xed, 0xb7, 0x59, 0x94, 0xe0, 0x76, 0x7a,
0xd9, 0x59, 0xca, 0xc9, 0xec, 0xb2, 0x53, 0x6c, 0xfc, 0x71, 0xdc, 0xd1, 0x5e, 0x8e, 0x3b, 0x85,
0xe9, 0xab, 0x71, 0x47, 0xb3, 0x26, 0x2c, 0xd2, 0x8f, 0xc1, 0xad, 0xc0, 0xf1, 0xb1, 0xf1, 0x5e,
0x4b, 0xeb, 0xd6, 0xcd, 0x4f, 0x52, 0x0e, 0xe5, 0x3a, 0xe3, 0xf0, 0x9e, 0x8c, 0x13, 0x0b, 0xe9,
0xf9, 0x90, 0xfa, 0x84, 0x61, 0x3f, 0x64, 0x23, 0x91, 0xb4, 0xf5, 0x16, 0xdc, 0x92, 0x3b, 0xf5,
0x73, 0x50, 0x77, 0x10, 0x8a, 0x70, 0x1c, 0xe3, 0xd8, 0x58, 0x68, 0x2d, 0x74, 0xeb, 0xe6, 0x49,
0xca, 0xe1, 0x14, 0xcc, 0x38, 0x7c, 0x20, 0xbd, 0x73, 0xa4, 0xe4, 0xdc, 0x2a, 0x4a, 0x42, 0xa3,
0xc0, 0xf1, 0x89, 0x27, 0xb2, 0x36, 0x6f, 0xe8, 0xde, 0x5c, 0x76, 0x96, 0x72, 0x81, 0x35, 0xf5,
0xd5, 0x87, 0x60, 0xc5, 0xa3, 0x7e, 0x28, 0x56, 0x84, 0x06, 0xc6, 0xad, 0x96, 0xd6, 0x5d, 0xdf,
0xbb, 0xd3, 0x2b, 0x7a, 0xfc, 0x78, 0x4a, 0x9a, 0x9f, 0xa6, 0x1c, 0x96, 0xd5, 0x19, 0x87, 0xdb,
0xf2, 0x50, 0x25, 0x4c, 0x35, 0x3a, 0xbd, 0xec, 0x6c, 0xcc, 0x82, 0x56, 0x79, 0xab, 0x8e, 0x41,
0xdd, 0xc3, 0x11, 0xb3, 0x65, 0x23, 0x6f, 0xcb, 0x46, 0x3e, 0x11, 0xbf, 0x9d, 0x00, 0x9f, 0xaa,
0x66, 0xde, 0x57, 0xde, 0x39, 0xf0, 0x96, 0x86, 0xde, 0x9d, 0xc3, 0x59, 0x85, 0x8b, 0x7e, 0x02,
0x00, 0x09, 0x58, 0x44, 0x51, 0xe2, 0xe1, 0xc8, 0x58, 0x6c, 0x69, 0xdd, 0x65, 0x73, 0x3f, 0xe5,
0xb0, 0x84, 0x66, 0x1c, 0xde, 0x51, 0x53, 0x52, 0x40, 0x45, 0x11, 0x8d, 0x19, 0xcc, 0x2a, 0xed,
0xd3, 0x7f, 0xd7, 0xc0, 0x4e, 0x7c, 0x46, 0x42, 0x7b, 0x82, 0x89, 0xf1, 0xb6, 0x23, 0xec, 0xd3,
0xa1, 0x33, 0x88, 0x8d, 0x25, 0x19, 0x86, 0x52, 0x0e, 0x0d, 0xa1, 0x3a, 0x2c, 0x89, 0xac, 0x5c,
0x93, 0x71, 0xf8, 0xbe, 0x8c, 0x9e, 0x27, 0x28, 0x0e, 0x72, 0xff, 0x9d, 0x0a, 0x6b, 0x6e, 0x82,
0xfe, 0x87, 0x06, 0xd6, 0x8a, 0x33, 0x23, 0xdb, 0x1d, 0x19, 0xcb, 0xf2, 0xc6, 0xfd, 0xf2, 0xbf,
0x6e, 0x5c, 0xca, 0xe1, 0xea, 0xd4, 0xd5, 0x1c, 0x65, 0x1c, 0x76, 0xab, 0x3d, 0x44, 0xe6, 0x68,
0xfe, 0x9d, 0xdb, 0xbc, 0x21, 0x13, 0x37, 0x4e, 0xde, 0xb2, 0x8a, 0xad, 0xbe, 0x07, 0x16, 0x43,
0x27, 0x89, 0x31, 0x32, 0xea, 0xb2, 0x9b, 0x3b, 0x29, 0x87, 0x39, 0x92, 0x71, 0xb8, 0x2a, 0x23,
0xd5, 0xb2, 0x6d, 0xe5, 0xb8, 0xfe, 0x03, 0xd8, 0x70, 0x06, 0x03, 0xfa, 0x02, 0x23, 0x3b, 0xc0,
0xec, 0x05, 0x8d, 0xce, 0x62, 0x03, 0xc8, 0x2b, 0xf5, 0x75, 0xca, 0x61, 0x23, 0xe7, 0x9e, 0xe6,
0x54, 0xf1, 0x46, 0x54, 0xf1, 0xea, 0xa0, 0x19, 0xf3, 0x48, 0x6b, 0xd6, 0x4e, 0xff, 0x0e, 0x6c,
0x39, 0x09, 0xa3, 0xb6, 0xe3, 0x79, 0x38, 0x64, 0xf6, 0x29, 0x1d, 0x20, 0x1c, 0xc5, 0xc6, 0x8a,
0x3c, 0xfe, 0x87, 0x29, 0x87, 0x9b, 0x82, 0xfe, 0x5c, 0xb2, 0x5f, 0x28, 0x32, 0xe3, 0xf0, 0xae,
0x3a, 0xc2, 0x2c, 0xd3, 0xb6, 0x6e, 0xaa, 0xf5, 0x67, 0x60, 0xcd, 0x77, 0xce, 0xed, 0x18, 0x07,
0xc8, 0x3e, 0x73, 0xc3, 0xd8, 0x58, 0x6d, 0x69, 0xdd, 0xdb, 0xe6, 0x07, 0xe2, 0x72, 0xfa, 0xce,
0xf9, 0x37, 0x38, 0x40, 0x47, 0x6e, 0x28, 0x5c, 0x37, 0xa5, 0x6b, 0x09, 0x6b, 0xbf, 0xe1, 0x70,
0x81, 0x04, 0xcc, 0x2a, 0x0b, 0x27, 0x86, 0x11, 0xf6, 0x86, 0xca, 0x70, 0xad, 0x62, 0x68, 0x61,
0x6f, 0x38, 0x6b, 0x38, 0xc1, 0x2a, 0x86, 0x13, 0x50, 0x0f, 0x40, 0x83, 0xf4, 0x03, 0x1a, 0x61,
0x54, 0xd4, 0xbf, 0xde, 0x5a, 0xe8, 0xae, 0xec, 0x6d, 0xf7, 0xd4, 0xbf, 0x46, 0xef, 0x59, 0xfe,
0xaf, 0xa1, 0x6a, 0x32, 0x1f, 0x89, 0x59, 0x4c, 0x39, 0x5c, 0xcf, 0xb7, 0x4d, 0x1b, 0xb3, 0xa5,
0xa6, 0xaa, 0x0c, 0xb7, 0xad, 0x19, 0x99, 0xfe, 0x93, 0x06, 0x1a, 0x21, 0x0e, 0x10, 0x09, 0xfa,
0x45, 0x60, 0xe3, 0x9d, 0x81, 0x4f, 0x44, 0xe0, 0x15, 0x87, 0xc6, 0x01, 0x0e, 0x23, 0xec, 0x39,
0x0c, 0xa3, 0x63, 0x65, 0x90, 0x7b, 0xa6, 0x1c, 0x6a, 0x8f, 0x8a, 0x37, 0x28, 0x2c, 0x73, 0xa5,
0xd1, 0x30, 0x34, 0x6b, 0xbd, 0xc2, 0xc5, 0xfa, 0xaf, 0x1a, 0x68, 0xa8, 0x6e, 0x7e, 0x9f, 0xe0,
0x98, 0xd9, 0x67, 0xc4, 0x35, 0x36, 0x64, 0x3f, 0xe3, 0x2b, 0x0e, 0xd7, 0xbe, 0x12, 0x6d, 0x92,
0xcc, 0x11, 0x31, 0x53, 0x0e, 0xd7, 0xfc, 0x32, 0x50, 0x14, 0x5c, 0x41, 0x27, 0x4d, 0x4e, 0x2f,
0x3b, 0x33, 0xf2, 0x59, 0xe0, 0xe5, 0xb8, 0x53, 0x4d, 0xb0, 0x2a, 0xbc, 0xab, 0x7f, 0x06, 0xea,
0x49, 0xc0, 0xa2, 0x24, 0x66, 0x18, 0x19, 0x9b, 0x72, 0x26, 0x5b, 0xe2, 0x7f, 0xa6, 0x00, 0x33,
0x0e, 0x1b, 0xf2, 0x04, 0x05, 0xd2, 0xb6, 0xa6, 0xac, 0xac, 0x4e, 0x3c, 0x70, 0x0c, 0xdb, 0xfd,
0x84, 0xd8, 0x21, 0x8d, 0x98, 0xa1, 0x4f, 0xab, 0xb3, 0x24, 0xf5, 0xe5, 0xb7, 0x87, 0xc7, 0x34,
0x62, 0xa2, 0xba, 0xa8, 0x0c, 0x14, 0xd5, 0x55, 0xd0, 0x72, 0x75, 0x55, 0xf9, 0x2c, 0x20, 0xaa,
0xab, 0x24, 0x58, 0x13, 0x3e, 0x21, 0x62, 0x69, 0x1e, 0x5d, 0xbc, 0x6e, 0xd6, 0xc6, 0xaf, 0x9b,
0xb5, 0x8b, 0xab, 0xa6, 0x36, 0xbe, 0x6a, 0x6a, 0x3f, 0x5f, 0x37, 0x6b, 0xaf, 0xae, 0x9b, 0xda,
0xf8, 0xba, 0x59, 0xfb, 0xeb, 0xba, 0x59, 0x3b, 0x79, 0xf0, 0x1f, 0x1e, 0x3b, 0x35, 0x31, 0xee,
0xa2, 0x7c, 0xf4, 0x3e, 0xfa, 0x37, 0x00, 0x00, 0xff, 0xff, 0xbf, 0x4a, 0x4f, 0x60, 0x33, 0x09,
0x00, 0x00,
}
func (m *DeviceConfiguration) Marshal() (dAtA []byte, err error) {

View File

@ -33,21 +33,6 @@ const (
maxConcurrentWritesLimit = 64
)
func NewFolderConfiguration(myID protocol.DeviceID, id, label string, fsType fs.FilesystemType, path string) FolderConfiguration {
f := FolderConfiguration{
ID: id,
Label: label,
Devices: []FolderDeviceConfiguration{{DeviceID: myID}},
FilesystemType: fsType,
Path: path,
}
util.SetDefaults(&f)
f.prepare(myID, nil)
return f
}
func (f FolderConfiguration) Copy() FolderConfiguration {
c := f
c.Devices = make([]FolderDeviceConfiguration, len(f.Devices))

View File

@ -66,10 +66,10 @@ func (m *FolderDeviceConfiguration) XXX_DiscardUnknown() {
var xxx_messageInfo_FolderDeviceConfiguration proto.InternalMessageInfo
type FolderConfiguration struct {
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id" xml:"id,attr"`
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id" xml:"id,attr" nodefault:"true"`
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label" xml:"label,attr" restart:"false"`
FilesystemType fs.FilesystemType `protobuf:"varint,3,opt,name=filesystem_type,json=filesystemType,proto3,enum=fs.FilesystemType" json:"filesystemType" xml:"filesystemType"`
Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path" xml:"path,attr"`
Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path" xml:"path,attr" default:"~"`
Type FolderType `protobuf:"varint,5,opt,name=type,proto3,enum=config.FolderType" json:"type" xml:"type,attr"`
Devices []FolderDeviceConfiguration `protobuf:"bytes,6,rep,name=devices,proto3" json:"devices" xml:"device"`
RescanIntervalS int `protobuf:"varint,7,opt,name=rescan_interval_s,json=rescanIntervalS,proto3,casttype=int" json:"rescanIntervalS" xml:"rescanIntervalS,attr" default:"3600"`
@ -77,7 +77,7 @@ type FolderConfiguration struct {
FSWatcherDelayS int `protobuf:"varint,9,opt,name=fs_watcher_delay_s,json=fsWatcherDelayS,proto3,casttype=int" json:"fsWatcherDelayS" xml:"fsWatcherDelayS,attr" default:"10"`
IgnorePerms bool `protobuf:"varint,10,opt,name=ignore_perms,json=ignorePerms,proto3" json:"ignorePerms" xml:"ignorePerms,attr"`
AutoNormalize bool `protobuf:"varint,11,opt,name=auto_normalize,json=autoNormalize,proto3" json:"autoNormalize" xml:"autoNormalize,attr" default:"true"`
MinDiskFree Size `protobuf:"bytes,12,opt,name=min_disk_free,json=minDiskFree,proto3" json:"minDiskFree" xml:"minDiskFree"`
MinDiskFree Size `protobuf:"bytes,12,opt,name=min_disk_free,json=minDiskFree,proto3" json:"minDiskFree" xml:"minDiskFree" default:"1 %"`
Versioning VersioningConfiguration `protobuf:"bytes,13,opt,name=versioning,proto3" json:"versioning" xml:"versioning"`
Copiers int `protobuf:"varint,14,opt,name=copiers,proto3,casttype=int" json:"copiers" xml:"copiers"`
PullerMaxPendingKiB int `protobuf:"varint,15,opt,name=puller_max_pending_kib,json=pullerMaxPendingKib,proto3,casttype=int" json:"pullerMaxPendingKiB" xml:"pullerMaxPendingKiB"`
@ -86,7 +86,7 @@ type FolderConfiguration struct {
IgnoreDelete bool `protobuf:"varint,18,opt,name=ignore_delete,json=ignoreDelete,proto3" json:"ignoreDelete" xml:"ignoreDelete"`
ScanProgressIntervalS int `protobuf:"varint,19,opt,name=scan_progress_interval_s,json=scanProgressIntervalS,proto3,casttype=int" json:"scanProgressIntervalS" xml:"scanProgressIntervalS"`
PullerPauseS int `protobuf:"varint,20,opt,name=puller_pause_s,json=pullerPauseS,proto3,casttype=int" json:"pullerPauseS" xml:"pullerPauseS"`
MaxConflicts int `protobuf:"varint,21,opt,name=max_conflicts,json=maxConflicts,proto3,casttype=int" json:"maxConflicts" xml:"maxConflicts" default:"-1"`
MaxConflicts int `protobuf:"varint,21,opt,name=max_conflicts,json=maxConflicts,proto3,casttype=int" json:"maxConflicts" xml:"maxConflicts" default:"10"`
DisableSparseFiles bool `protobuf:"varint,22,opt,name=disable_sparse_files,json=disableSparseFiles,proto3" json:"disableSparseFiles" xml:"disableSparseFiles"`
DisableTempIndexes bool `protobuf:"varint,23,opt,name=disable_temp_indexes,json=disableTempIndexes,proto3" json:"disableTempIndexes" xml:"disableTempIndexes"`
Paused bool `protobuf:"varint,24,opt,name=paused,proto3" json:"paused" xml:"paused"`
@ -149,134 +149,135 @@ func init() {
}
var fileDescriptor_44a9785876ed3afa = []byte{
// 2018 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcd, 0x6f, 0x1c, 0x49,
0x15, 0x77, 0x3b, 0x5f, 0x76, 0xf9, 0xbb, 0x1c, 0x27, 0x15, 0x67, 0xd7, 0xe5, 0x6d, 0x86, 0xc5,
0xbb, 0xda, 0x38, 0x89, 0x17, 0x71, 0x88, 0x76, 0x17, 0x76, 0xe2, 0xb5, 0x08, 0x21, 0x9b, 0x51,
0x3b, 0x10, 0x11, 0x90, 0x9a, 0x76, 0x77, 0xcd, 0x4c, 0xad, 0xfb, 0x8b, 0xaa, 0x9e, 0xd8, 0x93,
0x53, 0xb8, 0x20, 0x10, 0x7b, 0x40, 0xe6, 0xc0, 0x15, 0x09, 0x84, 0x60, 0xff, 0x01, 0x24, 0xfe,
0x82, 0x5c, 0x90, 0xe7, 0x84, 0x10, 0x87, 0x92, 0xd6, 0xbe, 0xcd, 0xb1, 0x8f, 0x39, 0xa1, 0xaa,
0xea, 0xee, 0xe9, 0xee, 0x99, 0x45, 0x48, 0x7b, 0x9b, 0xfa, 0xfd, 0x7e, 0xf5, 0xde, 0xeb, 0x57,
0xf5, 0x5e, 0xbf, 0x1e, 0xd0, 0xf0, 0xe9, 0xc1, 0x6d, 0x37, 0x0a, 0xdb, 0xb4, 0x73, 0xbb, 0x1d,
0xf9, 0x1e, 0x61, 0x7a, 0xd1, 0x63, 0x4e, 0x42, 0xa3, 0x70, 0x3b, 0x66, 0x51, 0x12, 0xc1, 0xcb,
0x1a, 0x5c, 0xbf, 0x39, 0xa6, 0x4e, 0xfa, 0x31, 0xd1, 0xa2, 0xf5, 0xb5, 0x12, 0xc9, 0xe9, 0x8b,
0x1c, 0x5e, 0x2f, 0xc1, 0x71, 0xcf, 0xf7, 0x23, 0xe6, 0x11, 0x96, 0x71, 0x5b, 0x25, 0xee, 0x39,
0x61, 0x9c, 0x46, 0x21, 0x0d, 0x3b, 0x13, 0x22, 0x58, 0xc7, 0x25, 0xe5, 0x81, 0x1f, 0xb9, 0x87,
0x75, 0x53, 0x50, 0x0a, 0xda, 0xfc, 0xb6, 0x0c, 0x88, 0x67, 0xd8, 0x1b, 0x19, 0xe6, 0x46, 0x71,
0x9f, 0x39, 0x61, 0x87, 0x04, 0x24, 0xe9, 0x46, 0x5e, 0xc6, 0xce, 0x92, 0xe3, 0x44, 0xff, 0x34,
0xff, 0x75, 0x01, 0xdc, 0xd8, 0x53, 0xcf, 0xb3, 0x4b, 0x9e, 0x53, 0x97, 0xdc, 0x2f, 0x47, 0x00,
0xbf, 0x30, 0xc0, 0xac, 0xa7, 0x70, 0x9b, 0x7a, 0xc8, 0xd8, 0x34, 0xb6, 0xe6, 0x9b, 0x9f, 0x1b,
0xaf, 0x04, 0x9e, 0xfa, 0x8f, 0xc0, 0xdf, 0xee, 0xd0, 0xa4, 0xdb, 0x3b, 0xd8, 0x76, 0xa3, 0xe0,
0x36, 0xef, 0x87, 0x6e, 0xd2, 0xa5, 0x61, 0xa7, 0xf4, 0x4b, 0x86, 0xa0, 0x9c, 0xb8, 0x91, 0xbf,
0xad, 0xad, 0x3f, 0xd8, 0x3d, 0x13, 0x78, 0x26, 0xff, 0x3d, 0x14, 0x78, 0xc6, 0xcb, 0x7e, 0xa7,
0x02, 0x2f, 0x1c, 0x07, 0xfe, 0x3d, 0x93, 0x7a, 0xef, 0x39, 0x49, 0xc2, 0xcc, 0xe1, 0x69, 0xe3,
0x4a, 0xf6, 0x3b, 0x3d, 0x6d, 0x14, 0xba, 0x5f, 0x0f, 0x1a, 0xc6, 0xc9, 0xa0, 0x51, 0xd8, 0xb0,
0x72, 0xc6, 0x83, 0x7f, 0x31, 0xc0, 0x02, 0x0d, 0x13, 0x16, 0x79, 0x3d, 0x97, 0x78, 0xf6, 0x41,
0x1f, 0x4d, 0xab, 0x80, 0x5f, 0x7e, 0xad, 0x80, 0x87, 0x02, 0xcf, 0x8f, 0xac, 0x36, 0xfb, 0xa9,
0xc0, 0xd7, 0x75, 0xa0, 0x25, 0xb0, 0x08, 0x79, 0x65, 0x0c, 0x95, 0x01, 0x5b, 0x15, 0x0b, 0xd0,
0x05, 0xab, 0x24, 0x74, 0x59, 0x3f, 0x96, 0x39, 0xb6, 0x63, 0x87, 0xf3, 0xa3, 0x88, 0x79, 0xe8,
0xc2, 0xa6, 0xb1, 0x35, 0xdb, 0xdc, 0x19, 0x0a, 0x0c, 0x47, 0x74, 0x2b, 0x63, 0x53, 0x81, 0x91,
0x72, 0x3b, 0x4e, 0x99, 0xd6, 0x04, 0xbd, 0x79, 0x8e, 0xc1, 0xaa, 0x3e, 0xd8, 0xea, 0x91, 0x7e,
0x04, 0xa6, 0xb3, 0xa3, 0x9c, 0x6d, 0x6e, 0x9f, 0x09, 0x3c, 0xad, 0x1e, 0x71, 0x9a, 0x7a, 0xff,
0xeb, 0x04, 0x4e, 0x06, 0x8d, 0xe9, 0x07, 0xbb, 0xd6, 0x34, 0xf5, 0xe0, 0x8f, 0xc0, 0x25, 0xdf,
0x39, 0x20, 0xbe, 0x4a, 0xee, 0x6c, 0xf3, 0xbb, 0x43, 0x81, 0x35, 0x90, 0x0a, 0xbc, 0xa9, 0xf6,
0xab, 0x95, 0x36, 0xb1, 0xc9, 0x08, 0x4f, 0x1c, 0x96, 0xdc, 0x33, 0xdb, 0x8e, 0xcf, 0x89, 0x34,
0x09, 0x46, 0xf4, 0xcb, 0x41, 0x63, 0xca, 0xd2, 0x9b, 0x61, 0x07, 0x2c, 0xb5, 0xa9, 0x4f, 0x78,
0x9f, 0x27, 0x24, 0xb0, 0xe5, 0x55, 0x56, 0xf9, 0x58, 0xdc, 0x81, 0xdb, 0x6d, 0xbe, 0xbd, 0x57,
0x50, 0x4f, 0xfa, 0x31, 0x69, 0xbe, 0x3b, 0x14, 0x78, 0xb1, 0x5d, 0xc1, 0x52, 0x81, 0xaf, 0x2a,
0xef, 0x55, 0xd8, 0xb4, 0x6a, 0x3a, 0xf8, 0x01, 0xb8, 0x18, 0x3b, 0x49, 0x17, 0x5d, 0x54, 0xe1,
0x6f, 0x0d, 0x05, 0x56, 0xeb, 0x54, 0xe0, 0x25, 0xb5, 0x5f, 0x2e, 0x8a, 0xe7, 0x9f, 0x2d, 0x56,
0x96, 0x52, 0xc1, 0x16, 0xb8, 0xa8, 0x62, 0xbb, 0x94, 0xc5, 0xa6, 0xeb, 0x72, 0x5b, 0x27, 0x5a,
0xc5, 0xa6, 0x2c, 0x26, 0x3a, 0x22, 0x6d, 0x51, 0x2e, 0x46, 0x16, 0x8b, 0x95, 0xa5, 0x54, 0xf0,
0x67, 0xe0, 0x8a, 0xbe, 0xc1, 0x1c, 0x5d, 0xde, 0xbc, 0xb0, 0x35, 0xb7, 0xf3, 0x56, 0xd5, 0xe8,
0x84, 0xb2, 0x6c, 0x62, 0x79, 0xa1, 0x87, 0x02, 0xe7, 0x3b, 0x53, 0x81, 0xe7, 0x95, 0x2b, 0xbd,
0x36, 0xad, 0x9c, 0x80, 0xbf, 0x37, 0xc0, 0x0a, 0x23, 0xdc, 0x75, 0x42, 0x9b, 0x86, 0x09, 0x61,
0xcf, 0x1d, 0xdf, 0xe6, 0xe8, 0xca, 0xa6, 0xb1, 0x75, 0xa9, 0xd9, 0x19, 0x0a, 0xbc, 0xa4, 0xc9,
0x07, 0x19, 0xb7, 0x9f, 0x0a, 0xfc, 0x8e, 0xb2, 0x54, 0xc3, 0xb3, 0xe3, 0xf4, 0x48, 0xdb, 0xe9,
0xf9, 0xc9, 0x3d, 0xf3, 0xfd, 0xef, 0xdc, 0xb9, 0x63, 0xbe, 0x16, 0xf8, 0x02, 0x0d, 0x93, 0xe1,
0x69, 0xe3, 0xea, 0x24, 0xf9, 0xeb, 0xd3, 0xc6, 0x45, 0xa9, 0xb3, 0xea, 0x4e, 0xe0, 0x3f, 0x0c,
0x00, 0xdb, 0xdc, 0x3e, 0x72, 0x12, 0xb7, 0x4b, 0x98, 0x4d, 0x42, 0xe7, 0xc0, 0x27, 0x1e, 0x9a,
0xd9, 0x34, 0xb6, 0x66, 0x9a, 0xbf, 0x35, 0xce, 0x04, 0x5e, 0xde, 0xdb, 0x7f, 0xaa, 0xd9, 0x4f,
0x34, 0x39, 0x14, 0x78, 0xb9, 0xcd, 0xab, 0x58, 0x2a, 0xf0, 0xbb, 0xfa, 0xcc, 0x6b, 0x44, 0x3d,
0xda, 0x84, 0xf5, 0xd4, 0xdd, 0x5b, 0x9b, 0x28, 0x94, 0x71, 0x4a, 0xc5, 0xc9, 0xa0, 0x31, 0xe6,
0xd6, 0x1a, 0x73, 0x0a, 0xff, 0x5e, 0x0d, 0xde, 0x23, 0xbe, 0xd3, 0xb7, 0x39, 0x9a, 0x55, 0x39,
0xfd, 0x8d, 0x0c, 0x7e, 0xa9, 0xb0, 0xb2, 0x2b, 0xc9, 0x7d, 0x99, 0xe7, 0xc2, 0x8c, 0x86, 0x52,
0x81, 0xbf, 0x55, 0x0d, 0x5d, 0xe3, 0xf5, 0xc8, 0xef, 0x56, 0xb2, 0x3c, 0x49, 0xfc, 0xfa, 0xb4,
0x31, 0x7d, 0xf7, 0xce, 0xc9, 0xa0, 0x51, 0xf7, 0x6a, 0xd5, 0x7d, 0xc2, 0x9f, 0x83, 0x79, 0xda,
0x09, 0x23, 0x46, 0xec, 0x98, 0xb0, 0x80, 0x23, 0xa0, 0xf2, 0xfd, 0xe1, 0x50, 0xe0, 0x39, 0x8d,
0xb7, 0x24, 0x9c, 0x0a, 0x7c, 0x4d, 0xf7, 0x81, 0x11, 0x56, 0x5c, 0xdf, 0xe5, 0x3a, 0x68, 0x95,
0xb7, 0xc2, 0x5f, 0x1a, 0x60, 0xd1, 0xe9, 0x25, 0x91, 0x1d, 0x46, 0x2c, 0x70, 0x7c, 0xfa, 0x82,
0xa0, 0x39, 0xe5, 0xe4, 0xd9, 0x50, 0xe0, 0x05, 0xc9, 0x7c, 0x9a, 0x13, 0x45, 0x06, 0x2a, 0xe8,
0x57, 0x9d, 0x1c, 0x1c, 0x57, 0xe5, 0xc7, 0x66, 0x55, 0xed, 0xc2, 0x67, 0x60, 0x21, 0xa0, 0xa1,
0xed, 0x51, 0x7e, 0x68, 0xb7, 0x19, 0x21, 0x68, 0x7e, 0xd3, 0xd8, 0x9a, 0xdb, 0x99, 0xcf, 0xcb,
0x6a, 0x9f, 0xbe, 0x20, 0xcd, 0xad, 0xac, 0x82, 0xe6, 0x02, 0x1a, 0xee, 0x52, 0x7e, 0xb8, 0xc7,
0x88, 0x8c, 0x68, 0x45, 0x45, 0x54, 0xc2, 0x4c, 0xab, 0xac, 0x80, 0x1d, 0x00, 0x46, 0x2f, 0x6b,
0xb4, 0xa0, 0x0c, 0xe3, 0xdc, 0xf0, 0x8f, 0x0b, 0xa6, 0x5a, 0xad, 0x6f, 0x67, 0xbe, 0x4a, 0x5b,
0x53, 0x81, 0x97, 0x95, 0xab, 0x11, 0x64, 0x5a, 0x25, 0x1e, 0x7e, 0x08, 0xae, 0xb8, 0x51, 0x4c,
0x09, 0xe3, 0x68, 0x51, 0x5d, 0xac, 0x6f, 0xc8, 0x72, 0xcf, 0xa0, 0xa2, 0x53, 0x67, 0xeb, 0xfc,
0x8a, 0x58, 0xb9, 0x00, 0xfe, 0xd3, 0x00, 0xd7, 0xe4, 0x98, 0x40, 0x98, 0x1d, 0x38, 0xc7, 0x76,
0x4c, 0x42, 0x8f, 0x86, 0x1d, 0xfb, 0x90, 0x1e, 0xa0, 0x25, 0x65, 0xee, 0x0f, 0xf2, 0x9e, 0xae,
0xb6, 0x94, 0xe4, 0x91, 0x73, 0xdc, 0xd2, 0x82, 0x87, 0xb4, 0x39, 0x14, 0x78, 0x35, 0x1e, 0x87,
0x53, 0x81, 0x6f, 0xe8, 0xf6, 0x38, 0xce, 0x95, 0x6e, 0xe8, 0xc4, 0xad, 0x93, 0xe1, 0x93, 0x41,
0x63, 0x92, 0x7f, 0x6b, 0x82, 0xf6, 0x40, 0xa6, 0xa3, 0xeb, 0xf0, 0xae, 0x4c, 0xc7, 0xf2, 0x28,
0x1d, 0x19, 0x54, 0xa4, 0x23, 0x5b, 0x8f, 0xd2, 0x91, 0x01, 0xf0, 0x63, 0x70, 0x49, 0x0d, 0x4c,
0x68, 0x45, 0xb5, 0xed, 0x95, 0xfc, 0xc4, 0xa4, 0xff, 0xc7, 0x92, 0x68, 0x22, 0xf9, 0x1a, 0x53,
0x9a, 0x54, 0xe0, 0x39, 0x65, 0x4d, 0xad, 0x4c, 0x4b, 0xa3, 0xf0, 0x21, 0x58, 0xc8, 0x6a, 0xc7,
0x23, 0x3e, 0x49, 0x08, 0x82, 0xea, 0x5e, 0xbf, 0xad, 0xc6, 0x03, 0x45, 0xec, 0x2a, 0x3c, 0x15,
0x18, 0x96, 0xaa, 0x47, 0x83, 0xa6, 0x55, 0xd1, 0xc0, 0x63, 0x80, 0x54, 0x4b, 0x8e, 0x59, 0xd4,
0x61, 0x84, 0xf3, 0x72, 0x6f, 0x5e, 0x55, 0xcf, 0x27, 0x5f, 0xab, 0x6b, 0x52, 0xd3, 0xca, 0x24,
0xe5, 0x0e, 0x7d, 0x53, 0x39, 0x98, 0xc8, 0x16, 0xcf, 0x3e, 0x79, 0x33, 0xdc, 0x07, 0x8b, 0xd9,
0xbd, 0x88, 0x9d, 0x1e, 0x27, 0x36, 0x47, 0x57, 0x95, 0xbf, 0x5b, 0xf2, 0x39, 0x34, 0xd3, 0x92,
0xc4, 0x7e, 0xf1, 0x1c, 0x65, 0xb0, 0xb0, 0x5e, 0x91, 0x42, 0x02, 0x16, 0xe4, 0x2d, 0x93, 0x49,
0xf5, 0xa9, 0x9b, 0x70, 0xb4, 0xa6, 0x6c, 0x7e, 0x4f, 0xda, 0x0c, 0x9c, 0xe3, 0xfb, 0x39, 0x9e,
0x0a, 0x8c, 0x75, 0x81, 0x95, 0xc0, 0x52, 0xb1, 0xdf, 0xba, 0x9b, 0x3b, 0x90, 0x4d, 0xed, 0xd6,
0x5d, 0xab, 0xb2, 0x1b, 0x7a, 0xe0, 0xaa, 0x47, 0xb9, 0x6c, 0xc2, 0x36, 0x8f, 0x1d, 0xc6, 0x89,
0xad, 0x5e, 0xed, 0xe8, 0x9a, 0x3a, 0x09, 0x35, 0x37, 0x65, 0xfc, 0xbe, 0xa2, 0xd5, 0xd0, 0x50,
0xcc, 0x4d, 0xe3, 0x94, 0x69, 0x4d, 0xd0, 0x97, 0xbd, 0x24, 0x24, 0x88, 0x6d, 0x1a, 0x7a, 0xe4,
0x98, 0x70, 0x74, 0x7d, 0xcc, 0xcb, 0x13, 0x12, 0xc4, 0x0f, 0x34, 0x5b, 0xf7, 0x52, 0xa2, 0x46,
0x5e, 0x4a, 0x20, 0xdc, 0x01, 0x97, 0xd5, 0x01, 0x78, 0x08, 0x29, 0xbb, 0xeb, 0x43, 0x81, 0x33,
0xa4, 0x78, 0x99, 0xeb, 0xa5, 0x69, 0x65, 0x38, 0x4c, 0xc0, 0xf5, 0x23, 0xe2, 0x1c, 0xda, 0xf2,
0x56, 0xdb, 0x49, 0x97, 0x11, 0xde, 0x8d, 0x7c, 0xcf, 0x8e, 0xdd, 0x04, 0xdd, 0x50, 0x09, 0x97,
0x9d, 0xfc, 0xaa, 0x94, 0x7c, 0xdf, 0xe1, 0xdd, 0x27, 0xb9, 0xa0, 0xe5, 0x26, 0xa9, 0xc0, 0xeb,
0xca, 0xe4, 0x24, 0xb2, 0x38, 0xd4, 0x89, 0x5b, 0xe1, 0x7d, 0x30, 0x17, 0x38, 0xec, 0x90, 0x30,
0x3b, 0x74, 0x02, 0x82, 0xd6, 0xd5, 0xd8, 0x64, 0xca, 0x76, 0xa6, 0xe1, 0x4f, 0x9d, 0x80, 0x14,
0xed, 0x6c, 0x04, 0x99, 0x56, 0x89, 0x87, 0x7d, 0xb0, 0x2e, 0xbf, 0x44, 0xec, 0xe8, 0x28, 0x24,
0x8c, 0x77, 0x69, 0x6c, 0xb7, 0x59, 0x14, 0xd8, 0xb1, 0xc3, 0x48, 0x98, 0xa0, 0x9b, 0x2a, 0x05,
0x1f, 0x0c, 0x05, 0xbe, 0x2e, 0x55, 0x8f, 0x73, 0xd1, 0x1e, 0x8b, 0x82, 0x96, 0x92, 0xa4, 0x02,
0xbf, 0x99, 0x77, 0xbc, 0x49, 0xbc, 0x69, 0x7d, 0xd5, 0x4e, 0xf8, 0x2b, 0x03, 0xac, 0x04, 0x91,
0x67, 0x27, 0x34, 0x20, 0xf6, 0x11, 0x0d, 0xbd, 0xe8, 0xc8, 0xe6, 0xe8, 0x0d, 0x95, 0xb0, 0x9f,
0x9e, 0x09, 0xbc, 0x62, 0x39, 0x47, 0x8f, 0x22, 0xef, 0x09, 0x0d, 0xc8, 0x53, 0xc5, 0xca, 0xd7,
0xf5, 0x62, 0x50, 0x41, 0x8a, 0xe1, 0xb2, 0x0a, 0xe7, 0x99, 0x3b, 0x19, 0x34, 0xc6, 0xad, 0x58,
0x35, 0x1b, 0xf0, 0xa5, 0x01, 0xd6, 0xb2, 0x32, 0x71, 0x7b, 0x4c, 0xc6, 0x66, 0x1f, 0x31, 0x9a,
0x10, 0x8e, 0xde, 0x54, 0xc1, 0xfc, 0x50, 0xb6, 0x5e, 0x7d, 0xe1, 0x33, 0xfe, 0xa9, 0xa2, 0x53,
0x81, 0xbf, 0x59, 0xaa, 0x9a, 0x0a, 0x57, 0x2a, 0x9e, 0x9d, 0x52, 0xed, 0x18, 0x3b, 0xd6, 0x24,
0x4b, 0xb2, 0x89, 0xe5, 0x77, 0xbb, 0x2d, 0x3f, 0x7b, 0xd0, 0xc6, 0xa8, 0x89, 0x65, 0xc4, 0x9e,
0xc4, 0x8b, 0xe2, 0x2f, 0x83, 0xa6, 0x55, 0xd1, 0x40, 0x1f, 0x2c, 0xab, 0xcf, 0x51, 0x5b, 0xf6,
0x02, 0x5b, 0xf7, 0x57, 0xac, 0xfa, 0xeb, 0xb5, 0xbc, 0xbf, 0x36, 0x25, 0x3f, 0x6a, 0xb2, 0x6a,
0x6c, 0x3f, 0xa8, 0x60, 0x45, 0x66, 0xab, 0xb0, 0x69, 0xd5, 0x74, 0xf0, 0x73, 0x03, 0xac, 0xa8,
0x2b, 0xa4, 0xbe, 0x66, 0x6d, 0xfd, 0x39, 0x8b, 0x36, 0x95, 0xbf, 0x55, 0xf9, 0x89, 0x70, 0x3f,
0x8a, 0xfb, 0x96, 0xe4, 0x1e, 0x29, 0xaa, 0xf9, 0x50, 0x4e, 0x5d, 0x6e, 0x15, 0x4c, 0x05, 0xde,
0x2a, 0xae, 0x51, 0x09, 0x2f, 0xa5, 0x91, 0x27, 0x4e, 0xe8, 0x39, 0xcc, 0x33, 0x5f, 0x9f, 0x36,
0x66, 0xf2, 0x85, 0x55, 0x37, 0x04, 0xff, 0x2c, 0xc3, 0x71, 0x64, 0x03, 0x25, 0x21, 0xa7, 0x09,
0x7d, 0x2e, 0x33, 0x8a, 0xde, 0x52, 0xe9, 0x3c, 0x96, 0x23, 0xe0, 0x7d, 0x87, 0x93, 0xfd, 0x9c,
0xdb, 0x53, 0x23, 0xa0, 0x5b, 0x85, 0x52, 0x81, 0xd7, 0x74, 0x30, 0x55, 0x5c, 0x8e, 0x3b, 0x63,
0xda, 0x71, 0x48, 0x4e, 0x7c, 0x35, 0x27, 0x56, 0x4d, 0xc3, 0xe1, 0x9f, 0x0c, 0xb0, 0xdc, 0x8e,
0x7c, 0x3f, 0x3a, 0xb2, 0x3f, 0xeb, 0x85, 0xae, 0x1c, 0x47, 0x38, 0x32, 0x47, 0x51, 0xfe, 0x20,
0x07, 0x3f, 0xe6, 0xbb, 0x94, 0x71, 0x19, 0xe5, 0x67, 0x55, 0xa8, 0x88, 0xb2, 0x86, 0xab, 0x28,
0xeb, 0xda, 0x71, 0x48, 0x46, 0x59, 0x73, 0x62, 0x2d, 0xe9, 0x88, 0x0a, 0x18, 0x1e, 0x82, 0x59,
0x46, 0x1c, 0xcf, 0x8e, 0x42, 0xbf, 0x8f, 0xfe, 0xba, 0xa7, 0xc2, 0x7b, 0x74, 0x26, 0x30, 0xdc,
0x25, 0x31, 0x23, 0xae, 0x93, 0x10, 0xcf, 0x22, 0x8e, 0xf7, 0x38, 0xf4, 0xfb, 0x43, 0x81, 0x8d,
0x5b, 0xc5, 0x27, 0x38, 0x8b, 0xd4, 0x24, 0xf8, 0x5e, 0x14, 0x50, 0xd9, 0xab, 0x93, 0xbe, 0xfa,
0x04, 0x1f, 0x43, 0x91, 0x61, 0xcd, 0xb0, 0xcc, 0x00, 0xfc, 0x05, 0x58, 0xa9, 0x8c, 0x87, 0xaa,
0x7f, 0xfe, 0x4d, 0x3a, 0x35, 0x9a, 0x9f, 0x9c, 0x09, 0x8c, 0x46, 0x4e, 0x1f, 0x8d, 0x26, 0xbf,
0x96, 0x9b, 0xe4, 0xae, 0x37, 0xea, 0x33, 0x62, 0xcb, 0x4d, 0x4a, 0x11, 0x20, 0xc3, 0x5a, 0xac,
0x92, 0xf0, 0x27, 0xe0, 0x8a, 0x7e, 0x5f, 0x72, 0xf4, 0xc5, 0x9e, 0xaa, 0xf5, 0x8f, 0x64, 0xe3,
0x19, 0x39, 0xd2, 0x73, 0x10, 0xaf, 0x3e, 0x5c, 0xb6, 0xa5, 0x64, 0x3a, 0x2b, 0x70, 0x64, 0x58,
0xb9, 0xbd, 0xe6, 0xc3, 0x57, 0x5f, 0x6e, 0x4c, 0x0d, 0xbe, 0xdc, 0x98, 0x7a, 0x75, 0xb6, 0x61,
0x0c, 0xce, 0x36, 0x8c, 0xdf, 0x9d, 0x6f, 0x4c, 0xfd, 0xf1, 0x7c, 0xc3, 0x18, 0x9c, 0x6f, 0x4c,
0xfd, 0xfb, 0x7c, 0x63, 0xea, 0xd9, 0x3b, 0xff, 0xc7, 0x9f, 0x1e, 0xba, 0x5c, 0x0f, 0x2e, 0xab,
0x3f, 0x3f, 0xde, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe5, 0x04, 0x99, 0x1a, 0x13,
0x00, 0x00,
// 2043 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcd, 0x6f, 0x24, 0x47,
0x15, 0x77, 0x7b, 0xbf, 0xec, 0xf2, 0x77, 0x79, 0xbd, 0xdb, 0xf1, 0x26, 0x53, 0x93, 0x66, 0x36,
0x38, 0x51, 0xe2, 0xdd, 0x75, 0x10, 0x12, 0x2b, 0x16, 0xc8, 0xd8, 0xb1, 0x58, 0x16, 0x67, 0x47,
0xed, 0x85, 0x15, 0x01, 0xa9, 0xe9, 0xe9, 0xae, 0x99, 0xa9, 0xb8, 0xbf, 0xa8, 0xea, 0x59, 0x7b,
0xf6, 0x10, 0x2d, 0x17, 0x04, 0x22, 0x07, 0x64, 0x0e, 0xdc, 0x50, 0x24, 0x10, 0x82, 0xfc, 0x03,
0x48, 0xfc, 0x05, 0x7b, 0x41, 0x9e, 0x13, 0x42, 0x1c, 0x4a, 0x8a, 0xf7, 0x36, 0xc7, 0x3e, 0xfa,
0x84, 0xaa, 0xaa, 0xbb, 0xa7, 0xbb, 0x67, 0x22, 0x21, 0x71, 0x9b, 0xfa, 0xfd, 0x5e, 0xbd, 0xf7,
0xeb, 0x57, 0xaf, 0x5e, 0xbf, 0x1e, 0xd0, 0xf0, 0x48, 0xfb, 0x8e, 0x13, 0x06, 0x1d, 0xd2, 0xbd,
0xd3, 0x09, 0x3d, 0x17, 0x53, 0xb5, 0xe8, 0x53, 0x3b, 0x26, 0x61, 0xb0, 0x1d, 0xd1, 0x30, 0x0e,
0xe1, 0x55, 0x05, 0x6e, 0xde, 0x9a, 0xb0, 0x8e, 0x07, 0x11, 0x56, 0x46, 0x9b, 0x1b, 0x05, 0x92,
0x91, 0xe7, 0x19, 0xbc, 0x59, 0x80, 0xa3, 0xbe, 0xe7, 0x85, 0xd4, 0xc5, 0x34, 0xe5, 0xb6, 0x0a,
0xdc, 0x33, 0x4c, 0x19, 0x09, 0x03, 0x12, 0x74, 0xa7, 0x28, 0xd8, 0x44, 0x05, 0xcb, 0xb6, 0x17,
0x3a, 0x47, 0x55, 0x57, 0x50, 0x18, 0x74, 0xd8, 0x1d, 0x21, 0x88, 0xa5, 0xd8, 0xeb, 0x29, 0xe6,
0x84, 0xd1, 0x80, 0xda, 0x41, 0x17, 0xfb, 0x38, 0xee, 0x85, 0x6e, 0xca, 0xce, 0xe3, 0x93, 0x58,
0xfd, 0x34, 0xfe, 0x75, 0x09, 0xbc, 0xb6, 0x2f, 0x9f, 0x67, 0x0f, 0x3f, 0x23, 0x0e, 0xde, 0x2d,
0x2a, 0x80, 0x5f, 0x68, 0x60, 0xde, 0x95, 0xb8, 0x45, 0x5c, 0x5d, 0xab, 0x6b, 0x5b, 0x8b, 0xcd,
0xcf, 0xb4, 0x97, 0x1c, 0xcd, 0xfc, 0x87, 0xa3, 0x6f, 0x74, 0x49, 0xdc, 0xeb, 0xb7, 0xb7, 0x9d,
0xd0, 0xbf, 0xc3, 0x06, 0x81, 0x13, 0xf7, 0x48, 0xd0, 0x2d, 0xfc, 0x12, 0x12, 0x64, 0x10, 0x27,
0xf4, 0xb6, 0x95, 0xf7, 0x87, 0x7b, 0xe7, 0x1c, 0xcd, 0x65, 0xbf, 0x47, 0x1c, 0xcd, 0xb9, 0xe9,
0xef, 0x84, 0xa3, 0xa5, 0x13, 0xdf, 0xbb, 0x6f, 0x10, 0xf7, 0x5d, 0x3b, 0x8e, 0xa9, 0x31, 0x3a,
0x6b, 0x5c, 0x4b, 0x7f, 0x27, 0x67, 0x8d, 0xdc, 0xee, 0xd7, 0xc3, 0x86, 0x76, 0x3a, 0x6c, 0xe4,
0x3e, 0xcc, 0x8c, 0x71, 0xe1, 0x5f, 0x34, 0xb0, 0x44, 0x82, 0x98, 0x86, 0x6e, 0xdf, 0xc1, 0xae,
0xd5, 0x1e, 0xe8, 0xb3, 0x52, 0xf0, 0x8b, 0xff, 0x4b, 0xf0, 0x88, 0xa3, 0xc5, 0xb1, 0xd7, 0xe6,
0x20, 0xe1, 0xe8, 0xa6, 0x12, 0x5a, 0x00, 0x73, 0xc9, 0x6b, 0x13, 0xa8, 0x10, 0x6c, 0x96, 0x3c,
0x40, 0x07, 0xac, 0xe3, 0xc0, 0xa1, 0x83, 0x48, 0xe4, 0xd8, 0x8a, 0x6c, 0xc6, 0x8e, 0x43, 0xea,
0xea, 0x97, 0xea, 0xda, 0xd6, 0x7c, 0x73, 0x67, 0xc4, 0x11, 0x1c, 0xd3, 0xad, 0x94, 0x4d, 0x38,
0xd2, 0x65, 0xd8, 0x49, 0xca, 0x30, 0xa7, 0xd8, 0x1b, 0x7f, 0xac, 0x83, 0x75, 0x75, 0xb0, 0xe5,
0x23, 0x3d, 0x04, 0xb3, 0xe9, 0x51, 0xce, 0x37, 0x77, 0xcf, 0x39, 0x9a, 0x95, 0x8f, 0x38, 0x4b,
0x44, 0x84, 0x5a, 0xe9, 0x04, 0xea, 0x41, 0xe8, 0xe2, 0x8e, 0xdd, 0xf7, 0xe2, 0xfb, 0x46, 0x4c,
0xfb, 0xb8, 0x78, 0x24, 0xa7, 0xc3, 0xc6, 0xec, 0xc3, 0xbd, 0xcf, 0xc5, 0xb3, 0xcd, 0x12, 0x17,
0xfe, 0x08, 0x5c, 0xf1, 0xec, 0x36, 0xf6, 0x64, 0xc6, 0xe7, 0x9b, 0xdf, 0x1d, 0x71, 0xa4, 0x80,
0x84, 0xa3, 0xba, 0x74, 0x2a, 0x57, 0xa9, 0x5f, 0x8a, 0x59, 0x6c, 0xd3, 0xf8, 0xbe, 0xd1, 0xb1,
0x3d, 0x26, 0xdd, 0x82, 0x31, 0xfd, 0x62, 0xd8, 0x98, 0x31, 0xd5, 0x66, 0xd8, 0x05, 0x2b, 0x1d,
0xe2, 0x61, 0x36, 0x60, 0x31, 0xf6, 0x2d, 0x51, 0xdf, 0x32, 0x49, 0xcb, 0x3b, 0x70, 0xbb, 0xc3,
0xb6, 0xf7, 0x73, 0xea, 0xc9, 0x20, 0xc2, 0xcd, 0x77, 0x46, 0x1c, 0x2d, 0x77, 0x4a, 0x58, 0xc2,
0xd1, 0x75, 0x19, 0xbd, 0x0c, 0x1b, 0x66, 0xc5, 0x0e, 0x1e, 0x80, 0xcb, 0x91, 0x1d, 0xf7, 0xf4,
0xcb, 0x52, 0xfe, 0xb7, 0x46, 0x1c, 0xc9, 0x75, 0xc2, 0xd1, 0x2d, 0xb9, 0x5f, 0x2c, 0x52, 0xf1,
0x79, 0x4a, 0x3e, 0x15, 0xc2, 0xe7, 0x73, 0xe6, 0xe2, 0xac, 0xa1, 0x7d, 0x6a, 0xca, 0x6d, 0xb0,
0x05, 0x2e, 0x4b, 0xb1, 0x57, 0x52, 0xb1, 0xea, 0xf6, 0x6e, 0xab, 0xe3, 0x90, 0x62, 0xb7, 0x44,
0x88, 0x58, 0x49, 0x5c, 0x91, 0x21, 0xc4, 0x22, 0x2f, 0xa3, 0xf9, 0x7c, 0x65, 0x4a, 0x2b, 0xf8,
0x33, 0x70, 0x4d, 0xd5, 0x39, 0xd3, 0xaf, 0xd6, 0x2f, 0x6d, 0x2d, 0xec, 0xbc, 0x59, 0x76, 0x3a,
0xe5, 0xf2, 0x36, 0x91, 0x28, 0xfb, 0x11, 0x47, 0xd9, 0xce, 0x84, 0xa3, 0x45, 0x19, 0x4a, 0xad,
0x0d, 0x33, 0x23, 0xe0, 0xef, 0x35, 0xb0, 0x46, 0x31, 0x73, 0xec, 0xc0, 0x22, 0x41, 0x8c, 0xe9,
0x33, 0xdb, 0xb3, 0x98, 0x7e, 0xad, 0xae, 0x6d, 0x5d, 0x69, 0x76, 0x47, 0x1c, 0xad, 0x28, 0xf2,
0x61, 0xca, 0x1d, 0x26, 0x1c, 0xbd, 0x2d, 0x3d, 0x55, 0xf0, 0x6a, 0x8a, 0xde, 0xff, 0xe6, 0xdd,
0xbb, 0xc6, 0x05, 0x47, 0x97, 0x48, 0x10, 0x8f, 0xce, 0x1a, 0xd7, 0xa7, 0x99, 0x5f, 0x9c, 0x35,
0x2e, 0x0b, 0x3b, 0xb3, 0x1a, 0x04, 0xfe, 0x43, 0x03, 0xb0, 0xc3, 0xac, 0x63, 0x3b, 0x76, 0x7a,
0x98, 0x5a, 0x38, 0xb0, 0xdb, 0x1e, 0x76, 0xf5, 0xb9, 0xba, 0xb6, 0x35, 0xd7, 0xfc, 0xad, 0x76,
0xce, 0xd1, 0xea, 0xfe, 0xe1, 0x53, 0xc5, 0x7e, 0xa8, 0xc8, 0x11, 0x47, 0xab, 0x1d, 0x56, 0xc6,
0x12, 0x8e, 0xde, 0x51, 0x45, 0x50, 0x21, 0xaa, 0x6a, 0xb3, 0x1a, 0xdf, 0x98, 0x6a, 0x28, 0x74,
0x0a, 0x8b, 0xd3, 0x61, 0x63, 0x22, 0xac, 0x39, 0x11, 0x14, 0xfe, 0xbd, 0x2c, 0xde, 0xc5, 0x9e,
0x3d, 0xb0, 0x98, 0x3e, 0x2f, 0x73, 0xfa, 0x1b, 0x21, 0x7e, 0x25, 0xf7, 0xb2, 0x27, 0xc8, 0x43,
0x91, 0xe7, 0xdc, 0x8d, 0x82, 0x12, 0x8e, 0xbe, 0x5e, 0x96, 0xae, 0xf0, 0xaa, 0xf2, 0x7b, 0xa5,
0x2c, 0x4f, 0x33, 0xbe, 0x38, 0x6b, 0xcc, 0xde, 0xbb, 0x7b, 0x3a, 0x6c, 0x54, 0xa3, 0x9a, 0xd5,
0x98, 0xf0, 0xe7, 0x60, 0x91, 0x74, 0x83, 0x90, 0x62, 0x2b, 0xc2, 0xd4, 0x67, 0x3a, 0x90, 0xf9,
0x7e, 0x30, 0xe2, 0x68, 0x41, 0xe1, 0x2d, 0x01, 0x27, 0x1c, 0xdd, 0x50, 0xdd, 0x62, 0x8c, 0xe5,
0xe5, 0xbb, 0x5a, 0x05, 0xcd, 0xe2, 0x56, 0xf8, 0x4b, 0x0d, 0x2c, 0xdb, 0xfd, 0x38, 0xb4, 0x82,
0x90, 0xfa, 0xb6, 0x47, 0x9e, 0x63, 0x7d, 0x41, 0x06, 0xf9, 0x78, 0xc4, 0xd1, 0x92, 0x60, 0x3e,
0xca, 0x88, 0x3c, 0x03, 0x25, 0xf4, 0xab, 0x4e, 0x0e, 0x4e, 0x5a, 0x65, 0xc7, 0x66, 0x96, 0xfd,
0xc2, 0x10, 0x2c, 0xf9, 0x24, 0xb0, 0x5c, 0xc2, 0x8e, 0xac, 0x0e, 0xc5, 0x58, 0x5f, 0xac, 0x6b,
0x5b, 0x0b, 0x3b, 0x8b, 0xd9, 0xb5, 0x3a, 0x24, 0xcf, 0x71, 0xf3, 0x41, 0x7a, 0x83, 0x16, 0x7c,
0x12, 0xec, 0x11, 0x76, 0xb4, 0x4f, 0xb1, 0x50, 0x84, 0xa4, 0xa2, 0x02, 0x56, 0x3c, 0x8a, 0xfa,
0x6d, 0xe3, 0xe2, 0xac, 0x71, 0xe9, 0x5e, 0xfd, 0xb6, 0x59, 0xdc, 0x06, 0xbb, 0x00, 0x8c, 0xdf,
0xf3, 0xfa, 0x92, 0x8c, 0x86, 0xb2, 0x68, 0x3f, 0xce, 0x99, 0xf2, 0x15, 0x7e, 0x2b, 0x15, 0x50,
0xd8, 0x9a, 0x70, 0xb4, 0x2a, 0xe3, 0x8f, 0x21, 0xc3, 0x2c, 0xf0, 0xf0, 0x01, 0xb8, 0xe6, 0x84,
0x11, 0xc1, 0x94, 0xe9, 0xcb, 0xb2, 0xda, 0xbe, 0x26, 0x7a, 0x40, 0x0a, 0xe5, 0xaf, 0xd9, 0x74,
0x9d, 0xd5, 0x8d, 0x99, 0x19, 0xc0, 0x7f, 0x6a, 0xe0, 0x86, 0x98, 0x30, 0x30, 0xb5, 0x7c, 0xfb,
0xc4, 0x8a, 0x70, 0xe0, 0x92, 0xa0, 0x6b, 0x1d, 0x91, 0xb6, 0xbe, 0x22, 0xdd, 0xfd, 0x41, 0x14,
0xef, 0x7a, 0x4b, 0x9a, 0x1c, 0xd8, 0x27, 0x2d, 0x65, 0xf0, 0x88, 0x34, 0x47, 0x1c, 0xad, 0x47,
0x93, 0x70, 0xc2, 0xd1, 0x6b, 0xaa, 0x89, 0x4e, 0x72, 0x85, 0xb2, 0x9d, 0xba, 0x75, 0x3a, 0x7c,
0x3a, 0x6c, 0x4c, 0x8b, 0x6f, 0x4e, 0xb1, 0x6d, 0x8b, 0x74, 0xf4, 0x6c, 0xd6, 0x13, 0xe9, 0x58,
0x1d, 0xa7, 0x23, 0x85, 0xf2, 0x74, 0xa4, 0xeb, 0x71, 0x3a, 0x52, 0x00, 0x7e, 0x00, 0xae, 0xc8,
0x59, 0x4b, 0x5f, 0x93, 0xbd, 0x7c, 0x2d, 0x3b, 0x31, 0x11, 0xff, 0xb1, 0x20, 0x9a, 0xba, 0x78,
0xd9, 0x49, 0x9b, 0x84, 0xa3, 0x05, 0xe9, 0x4d, 0xae, 0x0c, 0x53, 0xa1, 0xf0, 0x11, 0x58, 0x4a,
0x2f, 0x94, 0x8b, 0x3d, 0x1c, 0x63, 0x1d, 0xca, 0x62, 0x7f, 0x4b, 0x4e, 0x16, 0x92, 0xd8, 0x93,
0x78, 0xc2, 0x11, 0x2c, 0x5c, 0x29, 0x05, 0x1a, 0x66, 0xc9, 0x06, 0x9e, 0x00, 0x5d, 0xf6, 0xe9,
0x88, 0x86, 0x5d, 0x8a, 0x19, 0x2b, 0x36, 0xec, 0x75, 0xf9, 0x7c, 0xe2, 0xe5, 0xbb, 0x21, 0x6c,
0x5a, 0xa9, 0x49, 0xb1, 0x6d, 0xab, 0xd7, 0xd9, 0x54, 0x36, 0x7f, 0xf6, 0xe9, 0x9b, 0xe1, 0x21,
0x58, 0x4e, 0xeb, 0x22, 0xb2, 0xfb, 0x0c, 0x5b, 0x4c, 0xbf, 0x2e, 0xe3, 0xbd, 0x27, 0x9e, 0x43,
0x31, 0x2d, 0x41, 0x1c, 0xe6, 0xcf, 0x51, 0x04, 0x73, 0xef, 0x25, 0x53, 0x88, 0xc1, 0x92, 0xa8,
0x32, 0x91, 0x54, 0x8f, 0x38, 0x31, 0xd3, 0x37, 0xa4, 0xcf, 0xef, 0x09, 0x9f, 0xbe, 0x7d, 0xb2,
0x9b, 0xe1, 0xe3, 0x5b, 0x57, 0x00, 0xa7, 0x76, 0x40, 0xd5, 0xe9, 0xcc, 0xd2, 0x6e, 0xe8, 0x82,
0xeb, 0x2e, 0x61, 0xa2, 0x33, 0x5b, 0x2c, 0xb2, 0x29, 0xc3, 0x96, 0x1c, 0x00, 0xf4, 0x1b, 0xf2,
0x24, 0xe4, 0xc8, 0x95, 0xf2, 0x87, 0x92, 0x96, 0xa3, 0x45, 0x3e, 0x72, 0x4d, 0x52, 0x86, 0x39,
0xc5, 0xbe, 0x18, 0x25, 0xc6, 0x7e, 0x64, 0x91, 0xc0, 0xc5, 0x27, 0x98, 0xe9, 0x37, 0x27, 0xa2,
0x3c, 0xc1, 0x7e, 0xf4, 0x50, 0xb1, 0xd5, 0x28, 0x05, 0x6a, 0x1c, 0xa5, 0x00, 0xc2, 0x1d, 0x70,
0x55, 0x1e, 0x80, 0xab, 0xeb, 0xd2, 0xef, 0xe6, 0x88, 0xa3, 0x14, 0xc9, 0xdf, 0xf0, 0x6a, 0x69,
0x98, 0x29, 0x0e, 0x63, 0x70, 0xf3, 0x18, 0xdb, 0x47, 0x96, 0xa8, 0x6a, 0x2b, 0xee, 0x51, 0xcc,
0x7a, 0xa1, 0xe7, 0x5a, 0x91, 0x13, 0xeb, 0xaf, 0xc9, 0x84, 0x8b, 0xf6, 0x7e, 0x5d, 0x98, 0x7c,
0xdf, 0x66, 0xbd, 0x27, 0x99, 0x41, 0xcb, 0x89, 0x13, 0x8e, 0x36, 0xa5, 0xcb, 0x69, 0x64, 0x7e,
0xa8, 0x53, 0xb7, 0xc2, 0x5d, 0xb0, 0xe0, 0xdb, 0xf4, 0x08, 0x53, 0x2b, 0xb0, 0x7d, 0xac, 0x6f,
0xca, 0xe1, 0xca, 0x10, 0xed, 0x4c, 0xc1, 0x1f, 0xd9, 0x3e, 0xce, 0xdb, 0xd9, 0x18, 0x32, 0xcc,
0x02, 0x0f, 0x07, 0x60, 0x53, 0x7c, 0xc4, 0x58, 0xe1, 0x71, 0x80, 0x29, 0xeb, 0x91, 0xc8, 0xea,
0xd0, 0xd0, 0xb7, 0x22, 0x9b, 0xe2, 0x20, 0xd6, 0x6f, 0xc9, 0x14, 0x7c, 0x7b, 0xc4, 0xd1, 0x4d,
0x61, 0xf5, 0x38, 0x33, 0xda, 0xa7, 0xa1, 0xdf, 0x92, 0x26, 0x09, 0x47, 0x6f, 0x64, 0x1d, 0x6f,
0x1a, 0x6f, 0x98, 0x5f, 0xb5, 0x13, 0xfe, 0x4a, 0x03, 0x6b, 0x7e, 0xe8, 0x5a, 0x31, 0xf1, 0xb1,
0x75, 0x4c, 0x02, 0x37, 0x3c, 0xb6, 0x98, 0xfe, 0xba, 0x4c, 0xd8, 0x4f, 0xcf, 0x39, 0x5a, 0x33,
0xed, 0xe3, 0x83, 0xd0, 0x7d, 0x42, 0x7c, 0xfc, 0x54, 0xb2, 0xe2, 0x1d, 0xbe, 0xec, 0x97, 0x90,
0x7c, 0x04, 0x2d, 0xc3, 0x59, 0xe6, 0x4e, 0x87, 0x8d, 0x49, 0x2f, 0x66, 0xc5, 0x07, 0x7c, 0xa1,
0x81, 0x8d, 0xf4, 0x9a, 0x38, 0x7d, 0x2a, 0xb4, 0x59, 0xc7, 0x94, 0xc4, 0x98, 0xe9, 0x6f, 0x48,
0x31, 0x3f, 0x14, 0xad, 0x57, 0x15, 0x7c, 0xca, 0x3f, 0x95, 0x74, 0xc2, 0xd1, 0xed, 0xc2, 0xad,
0x29, 0x71, 0x85, 0xcb, 0xb3, 0x53, 0xb8, 0x3b, 0xda, 0x8e, 0x39, 0xcd, 0x93, 0x68, 0x62, 0x59,
0x6d, 0x77, 0xc4, 0x17, 0x93, 0x5e, 0x1b, 0x37, 0xb1, 0x94, 0xd8, 0x17, 0x78, 0x7e, 0xf9, 0x8b,
0xa0, 0x61, 0x96, 0x6c, 0xa0, 0x07, 0x56, 0xe5, 0x97, 0xac, 0x25, 0x7a, 0x81, 0xa5, 0xfa, 0x2b,
0x92, 0xfd, 0xf5, 0x46, 0xd6, 0x5f, 0x9b, 0x82, 0x1f, 0x37, 0x59, 0x39, 0xdc, 0xb7, 0x4b, 0x58,
0x9e, 0xd9, 0x32, 0x6c, 0x98, 0x15, 0x3b, 0xf8, 0x99, 0x06, 0xd6, 0x64, 0x09, 0xc9, 0x0f, 0x61,
0x4b, 0x7d, 0x09, 0xeb, 0x75, 0x19, 0x6f, 0x5d, 0x7c, 0x48, 0xec, 0x86, 0xd1, 0xc0, 0x14, 0xdc,
0x81, 0xa4, 0x9a, 0x8f, 0xc4, 0x28, 0xe6, 0x94, 0xc1, 0x84, 0xa3, 0xad, 0xbc, 0x8c, 0x0a, 0x78,
0x21, 0x8d, 0x2c, 0xb6, 0x03, 0xd7, 0xa6, 0xae, 0x78, 0xff, 0xcf, 0x65, 0x0b, 0xb3, 0xea, 0x08,
0xfe, 0x59, 0xc8, 0xb1, 0x45, 0x03, 0xc5, 0x01, 0x23, 0x31, 0x79, 0x26, 0x32, 0xaa, 0xbf, 0x29,
0xd3, 0x79, 0x22, 0xe6, 0xc2, 0x5d, 0x9b, 0xe1, 0xc3, 0x8c, 0xdb, 0x97, 0x73, 0xa1, 0x53, 0x86,
0x12, 0x8e, 0x36, 0x94, 0x98, 0x32, 0x2e, 0x66, 0xa0, 0x09, 0xdb, 0x49, 0x48, 0x8c, 0x81, 0x95,
0x20, 0x66, 0xc5, 0x86, 0xc1, 0x3f, 0x69, 0x60, 0xb5, 0x13, 0x7a, 0x5e, 0x78, 0x6c, 0x7d, 0xd2,
0x0f, 0x1c, 0x31, 0x8e, 0x30, 0xdd, 0x18, 0xab, 0xfc, 0x41, 0x06, 0x7e, 0xc0, 0xf6, 0x08, 0x65,
0x42, 0xe5, 0x27, 0x65, 0x28, 0x57, 0x59, 0xc1, 0xa5, 0xca, 0xaa, 0xed, 0x24, 0x24, 0x54, 0x56,
0x82, 0x98, 0x2b, 0x4a, 0x51, 0x0e, 0xc3, 0x23, 0x30, 0x4f, 0xb1, 0xed, 0x5a, 0x61, 0xe0, 0x0d,
0xf4, 0xbf, 0xee, 0x4b, 0x79, 0x07, 0xe7, 0x1c, 0xc1, 0x3d, 0x1c, 0x51, 0xec, 0xd8, 0x31, 0x76,
0x4d, 0x6c, 0xbb, 0x8f, 0x03, 0x6f, 0x30, 0xe2, 0x48, 0x7b, 0x2f, 0xff, 0x7a, 0xa7, 0xa1, 0x1c,
0x0f, 0xdf, 0x0d, 0x7d, 0x22, 0x7a, 0x75, 0x3c, 0x90, 0x5f, 0xef, 0x13, 0xa8, 0xae, 0x99, 0x73,
0x34, 0x75, 0x00, 0x7f, 0x01, 0xd6, 0x4a, 0x33, 0xa3, 0xec, 0x9f, 0x7f, 0x13, 0x41, 0xb5, 0xe6,
0x87, 0xe7, 0x1c, 0xe9, 0xe3, 0xa0, 0x07, 0xe3, 0xc9, 0xaf, 0xe5, 0xc4, 0x59, 0xe8, 0x5a, 0x75,
0x70, 0x6c, 0x39, 0x71, 0x41, 0x81, 0xae, 0x99, 0xcb, 0x65, 0x12, 0xfe, 0x04, 0x5c, 0x53, 0xef,
0x4b, 0xa6, 0x7f, 0xb1, 0x2f, 0xef, 0xfa, 0x77, 0x44, 0xe3, 0x19, 0x07, 0x52, 0x73, 0x10, 0x2b,
0x3f, 0x5c, 0xba, 0xa5, 0xe0, 0x3a, 0xbd, 0xe0, 0xba, 0x66, 0x66, 0xfe, 0x9a, 0x8f, 0x5e, 0x7e,
0x59, 0x9b, 0x19, 0x7e, 0x59, 0x9b, 0x79, 0x79, 0x5e, 0xd3, 0x86, 0xe7, 0x35, 0xed, 0x77, 0xaf,
0x6a, 0x33, 0x9f, 0xbf, 0xaa, 0x69, 0xc3, 0x57, 0xb5, 0x99, 0x7f, 0xbf, 0xaa, 0xcd, 0x7c, 0xfc,
0xf6, 0xff, 0xf0, 0x7f, 0x89, 0xba, 0xae, 0xed, 0xab, 0xf2, 0x7f, 0x93, 0xf7, 0xff, 0x1b, 0x00,
0x00, 0xff, 0xff, 0x3e, 0xb6, 0x85, 0xe6, 0x55, 0x13, 0x00, 0x00,
}
func (m *FolderDeviceConfiguration) Marshal() (dAtA []byte, err error) {

View File

@ -27,6 +27,7 @@ import (
// put the newest on top for readability.
var (
migrations = migrationSet{
{34, migrateToConfigV34},
{33, migrateToConfigV33},
{32, migrateToConfigV32},
{31, migrateToConfigV31},
@ -92,6 +93,11 @@ func (m migration) apply(cfg *Configuration) {
cfg.Version = m.targetVersion
}
func migrateToConfigV34(cfg *Configuration) {
cfg.Defaults.Folder.Path = cfg.Options.DeprecatedDefaultFolderPath
cfg.Options.DeprecatedDefaultFolderPath = ""
}
func migrateToConfigV33(cfg *Configuration) {
for i := range cfg.Devices {
cfg.Devices[i].DeprecatedPendingFolders = nil

View File

@ -7,9 +7,9 @@ import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
_ "github.com/golang/protobuf/ptypes/timestamp"
github_com_syncthing_syncthing_lib_protocol "github.com/syncthing/syncthing/lib/protocol"
_ "github.com/syncthing/syncthing/proto/ext"
_ "google.golang.org/protobuf/types/known/timestamppb"
io "io"
math "math"
math_bits "math/bits"

View File

@ -25,55 +25,55 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type OptionsConfiguration struct {
RawListenAddresses []string `protobuf:"bytes,1,rep,name=listen_addresses,json=listenAddresses,proto3" json:"listenAddresses" xml:"listenAddress" default:"default"`
RawGlobalAnnServers []string `protobuf:"bytes,2,rep,name=global_discovery_servers,json=globalDiscoveryServers,proto3" json:"globalAnnounceServers" xml:"globalAnnounceServer" default:"default"`
GlobalAnnEnabled bool `protobuf:"varint,3,opt,name=global_discovery_enabled,json=globalDiscoveryEnabled,proto3" json:"globalAnnounceEnabled" xml:"globalAnnounceEnabled" default:"true"`
LocalAnnEnabled bool `protobuf:"varint,4,opt,name=local_discovery_enabled,json=localDiscoveryEnabled,proto3" json:"localAnnounceEnabled" xml:"localAnnounceEnabled" default:"true"`
LocalAnnPort int `protobuf:"varint,5,opt,name=local_announce_port,json=localAnnouncePort,proto3,casttype=int" json:"localAnnouncePort" xml:"localAnnouncePort" default:"21027"`
LocalAnnMCAddr string `protobuf:"bytes,6,opt,name=local_announce_multicast_address,json=localAnnounceMulticastAddress,proto3" json:"localAnnounceMCAddr" xml:"localAnnounceMCAddr" default:"[ff12::8384]:21027"`
MaxSendKbps int `protobuf:"varint,7,opt,name=max_send_kbps,json=maxSendKbps,proto3,casttype=int" json:"maxSendKbps" xml:"maxSendKbps"`
MaxRecvKbps int `protobuf:"varint,8,opt,name=max_recv_kbps,json=maxRecvKbps,proto3,casttype=int" json:"maxRecvKbps" xml:"maxRecvKbps"`
ReconnectIntervalS int `protobuf:"varint,9,opt,name=reconnection_interval_s,json=reconnectionIntervalS,proto3,casttype=int" json:"reconnectionIntervalS" xml:"reconnectionIntervalS" default:"60"`
RelaysEnabled bool `protobuf:"varint,10,opt,name=relays_enabled,json=relaysEnabled,proto3" json:"relaysEnabled" xml:"relaysEnabled" default:"true"`
RelayReconnectIntervalM int `protobuf:"varint,11,opt,name=relays_reconnect_interval_m,json=relaysReconnectIntervalM,proto3,casttype=int" json:"relayReconnectIntervalM" xml:"relayReconnectIntervalM" default:"10"`
StartBrowser bool `protobuf:"varint,12,opt,name=start_browser,json=startBrowser,proto3" json:"startBrowser" xml:"startBrowser" default:"true"`
NATEnabled bool `protobuf:"varint,14,opt,name=nat_traversal_enabled,json=natTraversalEnabled,proto3" json:"natEnabled" xml:"natEnabled" default:"true"`
NATLeaseM int `protobuf:"varint,15,opt,name=nat_traversal_lease_m,json=natTraversalLeaseM,proto3,casttype=int" json:"natLeaseMinutes" xml:"natLeaseMinutes" default:"60"`
NATRenewalM int `protobuf:"varint,16,opt,name=nat_traversal_renewal_m,json=natTraversalRenewalM,proto3,casttype=int" json:"natRenewalMinutes" xml:"natRenewalMinutes" default:"30"`
NATTimeoutS int `protobuf:"varint,17,opt,name=nat_traversal_timeout_s,json=natTraversalTimeoutS,proto3,casttype=int" json:"natTimeoutSeconds" xml:"natTimeoutSeconds" default:"10"`
URAccepted int `protobuf:"varint,18,opt,name=usage_reporting_accepted,json=usageReportingAccepted,proto3,casttype=int" json:"urAccepted" xml:"urAccepted"`
URSeen int `protobuf:"varint,19,opt,name=usage_reporting_seen,json=usageReportingSeen,proto3,casttype=int" json:"urSeen" xml:"urSeen"`
URUniqueID string `protobuf:"bytes,20,opt,name=usage_reporting_unique_id,json=usageReportingUniqueId,proto3" json:"urUniqueId" xml:"urUniqueID"`
URURL string `protobuf:"bytes,21,opt,name=usage_reporting_url,json=usageReportingUrl,proto3" json:"urURL" xml:"urURL" default:"https://data.syncthing.net/newdata"`
URPostInsecurely bool `protobuf:"varint,22,opt,name=usage_reporting_post_insecurely,json=usageReportingPostInsecurely,proto3" json:"urPostInsecurely" xml:"urPostInsecurely" default:"false"`
URInitialDelayS int `protobuf:"varint,23,opt,name=usage_reporting_initial_delay_s,json=usageReportingInitialDelayS,proto3,casttype=int" json:"urInitialDelayS" xml:"urInitialDelayS" default:"1800"`
RestartOnWakeup bool `protobuf:"varint,24,opt,name=restart_on_wakeup,json=restartOnWakeup,proto3" json:"restartOnWakeup" xml:"restartOnWakeup" default:"true"`
AutoUpgradeIntervalH int `protobuf:"varint,25,opt,name=auto_upgrade_interval_h,json=autoUpgradeIntervalH,proto3,casttype=int" json:"autoUpgradeIntervalH" xml:"autoUpgradeIntervalH" default:"12"`
UpgradeToPreReleases bool `protobuf:"varint,26,opt,name=upgrade_to_pre_releases,json=upgradeToPreReleases,proto3" json:"upgradeToPreReleases" xml:"upgradeToPreReleases"`
KeepTemporariesH int `protobuf:"varint,27,opt,name=keep_temporaries_h,json=keepTemporariesH,proto3,casttype=int" json:"keepTemporariesH" xml:"keepTemporariesH" default:"24"`
CacheIgnoredFiles bool `protobuf:"varint,28,opt,name=cache_ignored_files,json=cacheIgnoredFiles,proto3" json:"cacheIgnoredFiles" xml:"cacheIgnoredFiles" default:"false"`
ProgressUpdateIntervalS int `protobuf:"varint,29,opt,name=progress_update_interval_s,json=progressUpdateIntervalS,proto3,casttype=int" json:"progressUpdateIntervalS" xml:"progressUpdateIntervalS" default:"5"`
LimitBandwidthInLan bool `protobuf:"varint,30,opt,name=limit_bandwidth_in_lan,json=limitBandwidthInLan,proto3" json:"limitBandwidthInLan" xml:"limitBandwidthInLan" default:"false"`
MinHomeDiskFree Size `protobuf:"bytes,31,opt,name=min_home_disk_free,json=minHomeDiskFree,proto3" json:"minHomeDiskFree" xml:"minHomeDiskFree" default:"1 %"`
ReleasesURL string `protobuf:"bytes,32,opt,name=releases_url,json=releasesUrl,proto3" json:"releasesURL" xml:"releasesURL" default:"https://upgrades.syncthing.net/meta.json"`
AlwaysLocalNets []string `protobuf:"bytes,33,rep,name=always_local_nets,json=alwaysLocalNets,proto3" json:"alwaysLocalNets" xml:"alwaysLocalNet"`
OverwriteRemoteDevNames bool `protobuf:"varint,34,opt,name=overwrite_remote_device_names_on_connect,json=overwriteRemoteDeviceNamesOnConnect,proto3" json:"overwriteRemoteDeviceNamesOnConnect" xml:"overwriteRemoteDeviceNamesOnConnect" default:"false"`
TempIndexMinBlocks int `protobuf:"varint,35,opt,name=temp_index_min_blocks,json=tempIndexMinBlocks,proto3,casttype=int" json:"tempIndexMinBlocks" xml:"tempIndexMinBlocks" default:"10"`
UnackedNotificationIDs []string `protobuf:"bytes,36,rep,name=unacked_notification_ids,json=unackedNotificationIds,proto3" json:"unackedNotificationIDs" xml:"unackedNotificationID"`
TrafficClass int `protobuf:"varint,37,opt,name=traffic_class,json=trafficClass,proto3,casttype=int" json:"trafficClass" xml:"trafficClass"`
DefaultFolderPath string `protobuf:"bytes,38,opt,name=default_folder_path,json=defaultFolderPath,proto3" json:"defaultFolderPath" xml:"defaultFolderPath" default:"~"`
SetLowPriority bool `protobuf:"varint,39,opt,name=set_low_priority,json=setLowPriority,proto3" json:"setLowPriority" xml:"setLowPriority" default:"true"`
RawMaxFolderConcurrency int `protobuf:"varint,40,opt,name=max_folder_concurrency,json=maxFolderConcurrency,proto3,casttype=int" json:"maxFolderConcurrency" xml:"maxFolderConcurrency"`
CRURL string `protobuf:"bytes,41,opt,name=crash_reporting_url,json=crashReportingUrl,proto3" json:"crURL" xml:"crashReportingURL" default:"https://crash.syncthing.net/newcrash"`
CREnabled bool `protobuf:"varint,42,opt,name=crash_reporting_enabled,json=crashReportingEnabled,proto3" json:"crashReportingEnabled" xml:"crashReportingEnabled" default:"true"`
StunKeepaliveStartS int `protobuf:"varint,43,opt,name=stun_keepalive_start_s,json=stunKeepaliveStartS,proto3,casttype=int" json:"stunKeepaliveStartS" xml:"stunKeepaliveStartS" default:"180"`
StunKeepaliveMinS int `protobuf:"varint,44,opt,name=stun_keepalive_min_s,json=stunKeepaliveMinS,proto3,casttype=int" json:"stunKeepaliveMinS" xml:"stunKeepaliveMinS" default:"20"`
RawStunServers []string `protobuf:"bytes,45,rep,name=stun_servers,json=stunServers,proto3" json:"stunServers" xml:"stunServer" default:"default"`
DatabaseTuning Tuning `protobuf:"varint,46,opt,name=database_tuning,json=databaseTuning,proto3,enum=config.Tuning" json:"databaseTuning" xml:"databaseTuning" restart:"true"`
RawMaxCIRequestKiB int `protobuf:"varint,47,opt,name=max_concurrent_incoming_request_kib,json=maxConcurrentIncomingRequestKib,proto3,casttype=int" json:"maxConcurrentIncomingRequestKiB" xml:"maxConcurrentIncomingRequestKiB"`
AnnounceLANAddresses bool `protobuf:"varint,48,opt,name=announce_lan_addresses,json=announceLanAddresses,proto3" json:"announceLANAddresses" xml:"announceLANAddresses" default:"true"`
SendFullIndexOnUpgrade bool `protobuf:"varint,49,opt,name=send_full_index_on_upgrade,json=sendFullIndexOnUpgrade,proto3" json:"sendFullIndexOnUpgrade" xml:"sendFullIndexOnUpgrade"`
FeatureFlags []string `protobuf:"bytes,50,rep,name=feature_flags,json=featureFlags,proto3" json:"featureFlags" xml:"featureFlag"`
RawListenAddresses []string `protobuf:"bytes,1,rep,name=listen_addresses,json=listenAddresses,proto3" json:"listenAddresses" xml:"listenAddress" default:"default"`
RawGlobalAnnServers []string `protobuf:"bytes,2,rep,name=global_discovery_servers,json=globalDiscoveryServers,proto3" json:"globalAnnounceServers" xml:"globalAnnounceServer" default:"default"`
GlobalAnnEnabled bool `protobuf:"varint,3,opt,name=global_discovery_enabled,json=globalDiscoveryEnabled,proto3" json:"globalAnnounceEnabled" xml:"globalAnnounceEnabled" default:"true"`
LocalAnnEnabled bool `protobuf:"varint,4,opt,name=local_discovery_enabled,json=localDiscoveryEnabled,proto3" json:"localAnnounceEnabled" xml:"localAnnounceEnabled" default:"true"`
LocalAnnPort int `protobuf:"varint,5,opt,name=local_announce_port,json=localAnnouncePort,proto3,casttype=int" json:"localAnnouncePort" xml:"localAnnouncePort" default:"21027"`
LocalAnnMCAddr string `protobuf:"bytes,6,opt,name=local_announce_multicast_address,json=localAnnounceMulticastAddress,proto3" json:"localAnnounceMCAddr" xml:"localAnnounceMCAddr" default:"[ff12::8384]:21027"`
MaxSendKbps int `protobuf:"varint,7,opt,name=max_send_kbps,json=maxSendKbps,proto3,casttype=int" json:"maxSendKbps" xml:"maxSendKbps"`
MaxRecvKbps int `protobuf:"varint,8,opt,name=max_recv_kbps,json=maxRecvKbps,proto3,casttype=int" json:"maxRecvKbps" xml:"maxRecvKbps"`
ReconnectIntervalS int `protobuf:"varint,9,opt,name=reconnection_interval_s,json=reconnectionIntervalS,proto3,casttype=int" json:"reconnectionIntervalS" xml:"reconnectionIntervalS" default:"60"`
RelaysEnabled bool `protobuf:"varint,10,opt,name=relays_enabled,json=relaysEnabled,proto3" json:"relaysEnabled" xml:"relaysEnabled" default:"true"`
RelayReconnectIntervalM int `protobuf:"varint,11,opt,name=relays_reconnect_interval_m,json=relaysReconnectIntervalM,proto3,casttype=int" json:"relayReconnectIntervalM" xml:"relayReconnectIntervalM" default:"10"`
StartBrowser bool `protobuf:"varint,12,opt,name=start_browser,json=startBrowser,proto3" json:"startBrowser" xml:"startBrowser" default:"true"`
NATEnabled bool `protobuf:"varint,14,opt,name=nat_traversal_enabled,json=natTraversalEnabled,proto3" json:"natEnabled" xml:"natEnabled" default:"true"`
NATLeaseM int `protobuf:"varint,15,opt,name=nat_traversal_lease_m,json=natTraversalLeaseM,proto3,casttype=int" json:"natLeaseMinutes" xml:"natLeaseMinutes" default:"60"`
NATRenewalM int `protobuf:"varint,16,opt,name=nat_traversal_renewal_m,json=natTraversalRenewalM,proto3,casttype=int" json:"natRenewalMinutes" xml:"natRenewalMinutes" default:"30"`
NATTimeoutS int `protobuf:"varint,17,opt,name=nat_traversal_timeout_s,json=natTraversalTimeoutS,proto3,casttype=int" json:"natTimeoutSeconds" xml:"natTimeoutSeconds" default:"10"`
URAccepted int `protobuf:"varint,18,opt,name=usage_reporting_accepted,json=usageReportingAccepted,proto3,casttype=int" json:"urAccepted" xml:"urAccepted"`
URSeen int `protobuf:"varint,19,opt,name=usage_reporting_seen,json=usageReportingSeen,proto3,casttype=int" json:"urSeen" xml:"urSeen"`
URUniqueID string `protobuf:"bytes,20,opt,name=usage_reporting_unique_id,json=usageReportingUniqueId,proto3" json:"urUniqueId" xml:"urUniqueID"`
URURL string `protobuf:"bytes,21,opt,name=usage_reporting_url,json=usageReportingUrl,proto3" json:"urURL" xml:"urURL" default:"https://data.syncthing.net/newdata"`
URPostInsecurely bool `protobuf:"varint,22,opt,name=usage_reporting_post_insecurely,json=usageReportingPostInsecurely,proto3" json:"urPostInsecurely" xml:"urPostInsecurely" default:"false"`
URInitialDelayS int `protobuf:"varint,23,opt,name=usage_reporting_initial_delay_s,json=usageReportingInitialDelayS,proto3,casttype=int" json:"urInitialDelayS" xml:"urInitialDelayS" default:"1800"`
RestartOnWakeup bool `protobuf:"varint,24,opt,name=restart_on_wakeup,json=restartOnWakeup,proto3" json:"restartOnWakeup" xml:"restartOnWakeup" default:"true"`
AutoUpgradeIntervalH int `protobuf:"varint,25,opt,name=auto_upgrade_interval_h,json=autoUpgradeIntervalH,proto3,casttype=int" json:"autoUpgradeIntervalH" xml:"autoUpgradeIntervalH" default:"12"`
UpgradeToPreReleases bool `protobuf:"varint,26,opt,name=upgrade_to_pre_releases,json=upgradeToPreReleases,proto3" json:"upgradeToPreReleases" xml:"upgradeToPreReleases"`
KeepTemporariesH int `protobuf:"varint,27,opt,name=keep_temporaries_h,json=keepTemporariesH,proto3,casttype=int" json:"keepTemporariesH" xml:"keepTemporariesH" default:"24"`
CacheIgnoredFiles bool `protobuf:"varint,28,opt,name=cache_ignored_files,json=cacheIgnoredFiles,proto3" json:"cacheIgnoredFiles" xml:"cacheIgnoredFiles" default:"false"`
ProgressUpdateIntervalS int `protobuf:"varint,29,opt,name=progress_update_interval_s,json=progressUpdateIntervalS,proto3,casttype=int" json:"progressUpdateIntervalS" xml:"progressUpdateIntervalS" default:"5"`
LimitBandwidthInLan bool `protobuf:"varint,30,opt,name=limit_bandwidth_in_lan,json=limitBandwidthInLan,proto3" json:"limitBandwidthInLan" xml:"limitBandwidthInLan" default:"false"`
MinHomeDiskFree Size `protobuf:"bytes,31,opt,name=min_home_disk_free,json=minHomeDiskFree,proto3" json:"minHomeDiskFree" xml:"minHomeDiskFree" default:"1 %"`
ReleasesURL string `protobuf:"bytes,32,opt,name=releases_url,json=releasesUrl,proto3" json:"releasesURL" xml:"releasesURL" default:"https://upgrades.syncthing.net/meta.json"`
AlwaysLocalNets []string `protobuf:"bytes,33,rep,name=always_local_nets,json=alwaysLocalNets,proto3" json:"alwaysLocalNets" xml:"alwaysLocalNet"`
OverwriteRemoteDevNames bool `protobuf:"varint,34,opt,name=overwrite_remote_device_names_on_connect,json=overwriteRemoteDeviceNamesOnConnect,proto3" json:"overwriteRemoteDeviceNamesOnConnect" xml:"overwriteRemoteDeviceNamesOnConnect" default:"false"`
TempIndexMinBlocks int `protobuf:"varint,35,opt,name=temp_index_min_blocks,json=tempIndexMinBlocks,proto3,casttype=int" json:"tempIndexMinBlocks" xml:"tempIndexMinBlocks" default:"10"`
UnackedNotificationIDs []string `protobuf:"bytes,36,rep,name=unacked_notification_ids,json=unackedNotificationIds,proto3" json:"unackedNotificationIDs" xml:"unackedNotificationID"`
TrafficClass int `protobuf:"varint,37,opt,name=traffic_class,json=trafficClass,proto3,casttype=int" json:"trafficClass" xml:"trafficClass"`
DeprecatedDefaultFolderPath string `protobuf:"bytes,38,opt,name=default_folder_path,json=defaultFolderPath,proto3" json:"-" xml:"defaultFolderPath,omitempty"` // Deprecated: Do not use.
SetLowPriority bool `protobuf:"varint,39,opt,name=set_low_priority,json=setLowPriority,proto3" json:"setLowPriority" xml:"setLowPriority" default:"true"`
RawMaxFolderConcurrency int `protobuf:"varint,40,opt,name=max_folder_concurrency,json=maxFolderConcurrency,proto3,casttype=int" json:"maxFolderConcurrency" xml:"maxFolderConcurrency"`
CRURL string `protobuf:"bytes,41,opt,name=crash_reporting_url,json=crashReportingUrl,proto3" json:"crURL" xml:"crashReportingURL" default:"https://crash.syncthing.net/newcrash"`
CREnabled bool `protobuf:"varint,42,opt,name=crash_reporting_enabled,json=crashReportingEnabled,proto3" json:"crashReportingEnabled" xml:"crashReportingEnabled" default:"true"`
StunKeepaliveStartS int `protobuf:"varint,43,opt,name=stun_keepalive_start_s,json=stunKeepaliveStartS,proto3,casttype=int" json:"stunKeepaliveStartS" xml:"stunKeepaliveStartS" default:"180"`
StunKeepaliveMinS int `protobuf:"varint,44,opt,name=stun_keepalive_min_s,json=stunKeepaliveMinS,proto3,casttype=int" json:"stunKeepaliveMinS" xml:"stunKeepaliveMinS" default:"20"`
RawStunServers []string `protobuf:"bytes,45,rep,name=stun_servers,json=stunServers,proto3" json:"stunServers" xml:"stunServer" default:"default"`
DatabaseTuning Tuning `protobuf:"varint,46,opt,name=database_tuning,json=databaseTuning,proto3,enum=config.Tuning" json:"databaseTuning" xml:"databaseTuning" restart:"true"`
RawMaxCIRequestKiB int `protobuf:"varint,47,opt,name=max_concurrent_incoming_request_kib,json=maxConcurrentIncomingRequestKib,proto3,casttype=int" json:"maxConcurrentIncomingRequestKiB" xml:"maxConcurrentIncomingRequestKiB"`
AnnounceLANAddresses bool `protobuf:"varint,48,opt,name=announce_lan_addresses,json=announceLanAddresses,proto3" json:"announceLANAddresses" xml:"announceLANAddresses" default:"true"`
SendFullIndexOnUpgrade bool `protobuf:"varint,49,opt,name=send_full_index_on_upgrade,json=sendFullIndexOnUpgrade,proto3" json:"sendFullIndexOnUpgrade" xml:"sendFullIndexOnUpgrade"`
FeatureFlags []string `protobuf:"bytes,50,rep,name=feature_flags,json=featureFlags,proto3" json:"featureFlags" xml:"featureFlag"`
// The number of connections at which we stop trying to connect to more
// devices, zero meaning no limit. Does not affect incoming connections.
ConnectionLimitEnough int `protobuf:"varint,51,opt,name=connection_limit_enough,json=connectionLimitEnough,proto3,casttype=int" json:"connectionLimitEnough" xml:"connectionLimitEnough"`
@ -133,208 +133,209 @@ func init() {
}
var fileDescriptor_d09882599506ca03 = []byte{
// 3211 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x5a, 0x5b, 0x6c, 0xdc, 0xc6,
0xd5, 0x36, 0xed, 0xd8, 0x89, 0x69, 0x59, 0xb6, 0x28, 0x59, 0x62, 0x6c, 0x47, 0x54, 0xd6, 0xeb,
0x44, 0xb9, 0xd9, 0x92, 0xec, 0xf8, 0x77, 0x0c, 0xfc, 0xc8, 0xaf, 0x4b, 0xf4, 0x5b, 0xb1, 0x64,
0x0b, 0x23, 0x09, 0xf9, 0x91, 0x1f, 0x05, 0x31, 0xcb, 0x9d, 0x95, 0x58, 0x71, 0x87, 0x6b, 0x72,
0xa8, 0x95, 0xd2, 0x22, 0x0d, 0x52, 0xf4, 0xf2, 0xd6, 0x56, 0xe8, 0x05, 0x68, 0x81, 0x22, 0x45,
0x5b, 0xa0, 0x69, 0x9a, 0xa2, 0x40, 0x81, 0x02, 0xed, 0x4b, 0x8b, 0x02, 0x05, 0x82, 0x16, 0xa8,
0xf4, 0x58, 0xa0, 0x29, 0x8b, 0xc8, 0x79, 0xda, 0x87, 0x3e, 0xec, 0xa3, 0xfa, 0x52, 0x9c, 0xe1,
0x6d, 0x48, 0xce, 0xc6, 0x7e, 0x5b, 0x9e, 0xef, 0xcc, 0x99, 0xef, 0xcc, 0xe5, 0xcc, 0x39, 0x33,
0xab, 0x5e, 0x76, 0xec, 0xda, 0x55, 0xcb, 0xa5, 0x0d, 0x7b, 0xfd, 0xaa, 0xdb, 0x62, 0xb6, 0x4b,
0xfd, 0xe8, 0x2b, 0xf0, 0x30, 0x7c, 0x5d, 0x69, 0x79, 0x2e, 0x73, 0xb5, 0x13, 0x91, 0xf0, 0xfc,
0x88, 0xa0, 0xce, 0x02, 0x6a, 0xd3, 0xf5, 0x48, 0xe1, 0xfc, 0x39, 0x01, 0xf0, 0xed, 0xb7, 0x48,
0x2c, 0x3e, 0x49, 0xb6, 0x59, 0xf4, 0xb3, 0xf2, 0xd7, 0xdb, 0xea, 0xd0, 0xbd, 0xa8, 0x87, 0x59,
0xb1, 0x07, 0xed, 0x87, 0x8a, 0x7a, 0xd6, 0xb1, 0x7d, 0x46, 0xa8, 0x89, 0xeb, 0x75, 0x8f, 0xf8,
0x3e, 0xf1, 0x75, 0x65, 0xec, 0xd8, 0xf8, 0xc9, 0x19, 0xff, 0x20, 0x34, 0x34, 0x84, 0xdb, 0x8b,
0x1c, 0x9e, 0x4e, 0xd0, 0x4e, 0x68, 0x9c, 0x71, 0xf2, 0xa2, 0x6e, 0x68, 0x5c, 0xde, 0x6e, 0x3a,
0xb7, 0x2a, 0x39, 0x79, 0x65, 0xac, 0x4e, 0x1a, 0x38, 0x70, 0xd8, 0xad, 0x4a, 0xfc, 0xa3, 0x72,
0xb8, 0x57, 0x7d, 0x3c, 0xfe, 0xbd, 0xbb, 0x5f, 0x95, 0x18, 0x47, 0x45, 0xd3, 0xda, 0xbf, 0x14,
0x55, 0x5f, 0x77, 0xdc, 0x1a, 0x76, 0xcc, 0xba, 0xed, 0x5b, 0xee, 0x16, 0xf1, 0x76, 0x4c, 0x9f,
0x78, 0x5b, 0xc4, 0xf3, 0xf5, 0xa3, 0x9c, 0xe8, 0xaf, 0x95, 0x83, 0xd0, 0x18, 0x44, 0xb8, 0xfd,
0xbf, 0x5c, 0x6f, 0x9a, 0xd2, 0x95, 0x08, 0xef, 0x84, 0xc6, 0xb9, 0xf5, 0x44, 0xe6, 0x06, 0xd4,
0x22, 0x31, 0xd0, 0x0d, 0x8d, 0x17, 0x39, 0x61, 0x19, 0x2a, 0xe1, 0xdd, 0xd9, 0xab, 0x0e, 0xc9,
0x54, 0xbb, 0x7b, 0x55, 0x79, 0x07, 0x79, 0x47, 0x65, 0xdc, 0xd0, 0x70, 0xd4, 0x70, 0x2e, 0x71,
0x2a, 0x96, 0x6b, 0x9f, 0xca, 0x1c, 0x26, 0x14, 0xd7, 0x1c, 0x52, 0xd7, 0x8f, 0x8d, 0x29, 0xe3,
0x4f, 0xcc, 0xbc, 0x0f, 0x0e, 0x9f, 0x4d, 0x2d, 0xbe, 0x16, 0x81, 0x65, 0x6f, 0x63, 0xa0, 0x1b,
0x1a, 0xcf, 0x4b, 0xbc, 0x8d, 0x51, 0xc1, 0x5d, 0xe6, 0x05, 0x04, 0x7c, 0xed, 0x61, 0xa6, 0x17,
0x70, 0xb8, 0x57, 0x7d, 0x0c, 0x9a, 0xee, 0xee, 0x57, 0x4b, 0xa4, 0x4a, 0x6e, 0xc6, 0x72, 0xed,
0x63, 0x45, 0x1d, 0x71, 0x5c, 0x4b, 0xea, 0xe5, 0x63, 0xdc, 0xcb, 0x1f, 0x83, 0x97, 0x67, 0x16,
0x41, 0x27, 0xe7, 0xe4, 0x90, 0x13, 0x8b, 0x0a, 0x3e, 0x3e, 0x17, 0x2d, 0x41, 0x09, 0x28, 0x71,
0x51, 0x6e, 0xa4, 0x87, 0x5c, 0x70, 0xb0, 0xc8, 0x07, 0x9d, 0xe3, 0x0d, 0x4a, 0xee, 0xfd, 0x45,
0x51, 0x07, 0x23, 0xf7, 0x70, 0x6c, 0xcb, 0x6c, 0xb9, 0x1e, 0xd3, 0x8f, 0x8f, 0x29, 0xe3, 0xc7,
0x67, 0xbe, 0x0f, 0xae, 0xf5, 0x25, 0xa6, 0x96, 0x5d, 0x8f, 0x75, 0x42, 0x63, 0x20, 0xd7, 0x35,
0x08, 0xbb, 0xa1, 0xf1, 0x6c, 0xd9, 0x29, 0x40, 0x04, 0x8f, 0xa6, 0x26, 0x27, 0xa6, 0xfe, 0xab,
0x72, 0x18, 0x1a, 0xc7, 0x6c, 0xca, 0x3a, 0x7b, 0x55, 0x89, 0x19, 0x99, 0xf0, 0x70, 0xaf, 0x7a,
0x9c, 0x37, 0xdd, 0xdd, 0xaf, 0xe6, 0x98, 0xa0, 0xb2, 0xae, 0xf6, 0xe5, 0xa3, 0xea, 0x58, 0xc1,
0x9b, 0x66, 0xe0, 0x30, 0xdb, 0xc2, 0x3e, 0x4b, 0xe2, 0x86, 0x7e, 0x62, 0x4c, 0x19, 0x3f, 0x39,
0xf3, 0x5b, 0x70, 0xad, 0x3f, 0x31, 0xb8, 0x34, 0x0b, 0x3b, 0xb9, 0x13, 0x1a, 0x83, 0x39, 0xa3,
0x91, 0xb8, 0x1b, 0x1a, 0x37, 0xca, 0xee, 0x45, 0x98, 0xe0, 0xe0, 0xff, 0x37, 0x1a, 0x93, 0x53,
0xb7, 0x6e, 0xdd, 0xbc, 0x76, 0xf3, 0xfa, 0xe7, 0x6e, 0x45, 0xde, 0x76, 0xf6, 0xaa, 0x52, 0x83,
0x72, 0xf1, 0xe1, 0x5e, 0x55, 0x2b, 0x1b, 0xd9, 0xdd, 0xaf, 0x16, 0x68, 0xa2, 0xa7, 0xf2, 0x8d,
0x13, 0x0f, 0xe3, 0x60, 0xa4, 0xdd, 0x53, 0x4f, 0x37, 0xf1, 0xb6, 0xe9, 0x13, 0x5a, 0x37, 0x37,
0x6b, 0x2d, 0x5f, 0x7f, 0x9c, 0x4f, 0xe6, 0x0b, 0x9d, 0xd0, 0x38, 0xd5, 0xc4, 0xdb, 0x2b, 0x84,
0xd6, 0xef, 0xd4, 0x5a, 0x10, 0x5c, 0x06, 0xb8, 0x5b, 0x82, 0x2c, 0x99, 0x1f, 0x24, 0x2a, 0x26,
0x06, 0x3d, 0x62, 0x6d, 0x45, 0x06, 0x9f, 0xc8, 0x19, 0x44, 0xc4, 0xda, 0x2a, 0x1a, 0x4c, 0x64,
0x39, 0x83, 0x89, 0x50, 0xfb, 0x8d, 0xa2, 0x8e, 0x78, 0xc4, 0x72, 0x29, 0x25, 0x16, 0x84, 0x77,
0xd3, 0xa6, 0x8c, 0x78, 0x5b, 0xd8, 0x31, 0x7d, 0xfd, 0x24, 0xb7, 0xfd, 0x36, 0x0f, 0xea, 0x89,
0xca, 0x42, 0x0c, 0xaf, 0x40, 0xec, 0x10, 0x1b, 0xa6, 0x40, 0x37, 0x34, 0xc6, 0x79, 0xdf, 0x52,
0x54, 0x98, 0xa5, 0x1b, 0x13, 0x09, 0xa5, 0xc3, 0xbd, 0xea, 0xd1, 0x1b, 0x13, 0x3c, 0xbe, 0x97,
0xfa, 0x41, 0xf2, 0x5e, 0xb4, 0x86, 0xda, 0xef, 0x11, 0x07, 0xef, 0xf8, 0x69, 0x0c, 0x50, 0x79,
0x0c, 0x78, 0xb5, 0x13, 0x1a, 0xa7, 0x23, 0x24, 0xdb, 0xe8, 0x95, 0x98, 0x90, 0x20, 0x2d, 0xee,
0xf0, 0x64, 0xc7, 0xa2, 0x7c, 0x63, 0xed, 0xdd, 0xa3, 0xea, 0x85, 0xb8, 0xa3, 0x94, 0x48, 0x36,
0x48, 0x4d, 0xfd, 0x14, 0x1f, 0xa4, 0x3f, 0xc2, 0x1a, 0x1e, 0x41, 0xa0, 0x57, 0x72, 0x61, 0xa9,
0x13, 0x1a, 0x23, 0x9e, 0x1c, 0x4a, 0x03, 0x6d, 0x0f, 0x5c, 0x60, 0x39, 0x39, 0x21, 0x6c, 0xd9,
0x9e, 0xf6, 0x7a, 0x43, 0x30, 0xc8, 0x93, 0x30, 0xc8, 0xbd, 0x68, 0x22, 0x3d, 0xf2, 0xb3, 0x8c,
0x68, 0x35, 0xf5, 0xb4, 0xcf, 0xb0, 0xc7, 0xcc, 0x9a, 0xe7, 0xb6, 0x7d, 0xe2, 0xe9, 0x7d, 0x7c,
0xac, 0xff, 0xbb, 0x13, 0x1a, 0x7d, 0x1c, 0x98, 0x89, 0xe4, 0xdd, 0xd0, 0x78, 0x9a, 0xbb, 0x23,
0x0a, 0x7b, 0x8e, 0x74, 0xae, 0xa9, 0xf6, 0x53, 0x45, 0x3d, 0x47, 0x31, 0x33, 0x99, 0x87, 0xe1,
0x54, 0xc3, 0x4e, 0x3a, 0xb1, 0xfd, 0xbc, 0xb3, 0xfb, 0x07, 0xa1, 0xa1, 0xde, 0x9d, 0x5e, 0xcd,
0xc2, 0xba, 0x4a, 0x31, 0xcb, 0xe6, 0xd8, 0xe0, 0x1d, 0x67, 0x22, 0x49, 0x08, 0x17, 0x1b, 0xe4,
0xbe, 0x84, 0x70, 0x2d, 0x74, 0x81, 0x06, 0x29, 0x66, 0xab, 0x09, 0x9d, 0x64, 0x41, 0xfc, 0xae,
0xc4, 0xd3, 0x21, 0xd8, 0x27, 0x66, 0x53, 0x3f, 0xc3, 0x97, 0xc2, 0x57, 0x61, 0x29, 0x9c, 0xbc,
0x3b, 0xbd, 0xba, 0x08, 0x62, 0x98, 0xfc, 0x33, 0x14, 0xb3, 0xe8, 0xc3, 0xa6, 0x01, 0xe3, 0xc9,
0x4f, 0x25, 0x21, 0x2b, 0xca, 0xa5, 0x7b, 0xa3, 0xb3, 0x57, 0x2d, 0xb5, 0x2f, 0x8b, 0xd2, 0x1d,
0x94, 0x75, 0x8c, 0x34, 0x91, 0x7d, 0x24, 0xd3, 0xfe, 0xac, 0xa8, 0x23, 0x79, 0xf2, 0x1e, 0xa1,
0xa4, 0xcd, 0x57, 0xf2, 0x59, 0x4e, 0x7f, 0x17, 0xe8, 0x9f, 0xba, 0x3b, 0xbd, 0x8a, 0x22, 0x00,
0x1c, 0x18, 0xa0, 0x98, 0x25, 0x9f, 0xa9, 0x0b, 0xd5, 0xc4, 0x85, 0x3c, 0x22, 0x38, 0x71, 0x4d,
0x74, 0x42, 0x62, 0x43, 0x26, 0x04, 0x47, 0xae, 0x81, 0x23, 0x22, 0x05, 0x34, 0x24, 0xba, 0x92,
0x48, 0x25, 0xce, 0x30, 0xbb, 0x49, 0xdc, 0x80, 0x99, 0xbe, 0x3e, 0x90, 0x77, 0x66, 0x35, 0x02,
0x56, 0x62, 0x67, 0x92, 0x4f, 0x58, 0xe9, 0xf5, 0x9c, 0x33, 0x79, 0xa4, 0xd7, 0xf6, 0x93, 0xd8,
0x90, 0x09, 0xd3, 0x2d, 0x27, 0x52, 0xc8, 0x3b, 0x93, 0x48, 0xb5, 0x1f, 0x28, 0xaa, 0x1e, 0xf8,
0x78, 0x9d, 0x98, 0x1e, 0x81, 0x73, 0xdf, 0xa6, 0xeb, 0x26, 0xb6, 0x2c, 0xd2, 0x62, 0xa4, 0xae,
0x6b, 0xdc, 0x1b, 0x0c, 0x3b, 0x60, 0x0d, 0x4d, 0xc7, 0x52, 0xd8, 0x01, 0x81, 0x97, 0x7c, 0x75,
0x43, 0xe3, 0x2c, 0x77, 0x22, 0x13, 0x09, 0x84, 0x45, 0xc5, 0xdc, 0x17, 0xac, 0xf8, 0xcc, 0x24,
0x1a, 0xe6, 0x14, 0x50, 0xc2, 0x20, 0x91, 0x6b, 0x5f, 0x50, 0x87, 0x8a, 0xe4, 0x7c, 0x42, 0xa8,
0x3e, 0xc8, 0x89, 0x2d, 0x1c, 0x84, 0xc6, 0x89, 0x35, 0xb4, 0x42, 0x08, 0xed, 0x84, 0xc6, 0x89,
0xc0, 0x83, 0x5f, 0xdd, 0xd0, 0xe8, 0x8b, 0x09, 0xc1, 0xa7, 0x40, 0x26, 0x51, 0x48, 0x7f, 0xed,
0xee, 0x57, 0xe3, 0xe6, 0x48, 0xcb, 0x13, 0x00, 0x99, 0xf6, 0x1d, 0x45, 0x7d, 0xb2, 0xd8, 0x7b,
0x40, 0xed, 0xfb, 0x01, 0x31, 0xed, 0xba, 0x3e, 0xc4, 0x93, 0x88, 0x37, 0xa3, 0xb1, 0x59, 0xe3,
0xe2, 0x85, 0xb9, 0x68, 0x6c, 0xe2, 0x2f, 0x71, 0x6c, 0x12, 0x85, 0x4a, 0x34, 0x28, 0xc9, 0x67,
0x57, 0xfc, 0x8a, 0x07, 0x25, 0xc1, 0x8a, 0x83, 0x92, 0x68, 0x69, 0x7f, 0x50, 0xd4, 0xc1, 0x12,
0x2f, 0xcf, 0xd1, 0xcf, 0x71, 0x46, 0xdf, 0x80, 0xb5, 0x77, 0x7c, 0x0d, 0xad, 0xa1, 0xc5, 0x4e,
0x68, 0x1c, 0x0f, 0xbc, 0x35, 0xb4, 0xd8, 0x0d, 0x8d, 0x9b, 0x09, 0x11, 0xb4, 0x28, 0xac, 0xae,
0x0d, 0xc6, 0x5a, 0xfe, 0xad, 0xab, 0x57, 0xeb, 0x98, 0xe1, 0x2b, 0xfe, 0x0e, 0xb5, 0xd8, 0x06,
0x14, 0x6b, 0x94, 0xb0, 0xab, 0x94, 0xb4, 0x41, 0x0a, 0x84, 0x63, 0x23, 0xc9, 0x8f, 0xc3, 0xbd,
0xea, 0x23, 0x34, 0xdc, 0xdd, 0xaf, 0x46, 0x2c, 0xd0, 0x40, 0xc1, 0x0f, 0xcf, 0xd1, 0xfe, 0xa9,
0xa8, 0x46, 0xd1, 0x85, 0x96, 0xeb, 0xc3, 0x09, 0xe7, 0x13, 0x2b, 0xf0, 0x88, 0xb3, 0xa3, 0x0f,
0xf3, 0xf0, 0xfb, 0x3d, 0x5e, 0x41, 0xac, 0xa1, 0x65, 0xd7, 0x67, 0x0b, 0x29, 0xd8, 0x09, 0x8d,
0xb3, 0x81, 0x97, 0x97, 0x75, 0x43, 0xe3, 0x99, 0xd8, 0xc9, 0x3c, 0x20, 0xf8, 0xdb, 0xc0, 0x8e,
0xcf, 0x43, 0x72, 0xb9, 0xb5, 0x44, 0x06, 0x99, 0x27, 0x6f, 0x01, 0xf5, 0x42, 0x91, 0x02, 0xba,
0x98, 0x77, 0x2b, 0x8f, 0x6a, 0xff, 0x90, 0x78, 0x68, 0x53, 0x9b, 0xd9, 0x50, 0x47, 0xc0, 0x79,
0x67, 0xfa, 0xfa, 0x08, 0x5f, 0xc5, 0xdf, 0xe5, 0xd5, 0xc3, 0x1a, 0x5a, 0x88, 0xd0, 0x39, 0x00,
0x21, 0x60, 0x9c, 0x09, 0xbc, 0x9c, 0x28, 0x0d, 0x17, 0x05, 0xb9, 0x18, 0x2c, 0x6e, 0x4e, 0xe4,
0x02, 0x78, 0xd1, 0x42, 0x59, 0x04, 0x27, 0x10, 0xb4, 0x82, 0x82, 0xa1, 0x40, 0x01, 0x5d, 0xc8,
0x3b, 0x98, 0x03, 0x35, 0x57, 0x1d, 0xf0, 0x48, 0x74, 0x38, 0xbb, 0xd4, 0x6c, 0xe3, 0x4d, 0x12,
0xb4, 0x74, 0x9d, 0x4f, 0xd9, 0x2c, 0x90, 0x8f, 0xc1, 0x7b, 0xf4, 0x0d, 0x0e, 0xa5, 0xe4, 0x0b,
0xf2, 0x9e, 0x87, 0x74, 0xd1, 0x80, 0xf6, 0x35, 0x45, 0x1d, 0xc1, 0x01, 0x73, 0xcd, 0xa0, 0xb5,
0xee, 0xe1, 0x3a, 0xc9, 0x92, 0xa1, 0x0d, 0xfd, 0x49, 0x3e, 0x90, 0xcb, 0x50, 0x72, 0x81, 0xca,
0x5a, 0xa4, 0x91, 0xe4, 0x11, 0xb7, 0xd3, 0xea, 0x44, 0x06, 0x8a, 0xc3, 0x37, 0x25, 0x66, 0x86,
0x93, 0x53, 0x48, 0x6a, 0x4d, 0x6b, 0xaa, 0x23, 0x09, 0x07, 0xe6, 0x9a, 0x2d, 0x0f, 0xa6, 0x98,
0x9f, 0xc5, 0xbe, 0x7e, 0x9e, 0x0f, 0xc0, 0x0d, 0x20, 0x12, 0xab, 0xac, 0xba, 0xcb, 0x1e, 0x41,
0x31, 0xde, 0x0d, 0x8d, 0xf3, 0xd1, 0x14, 0x4a, 0xc0, 0x0a, 0x92, 0xb6, 0xd1, 0xb6, 0x54, 0x6d,
0x93, 0x90, 0x96, 0xc9, 0x48, 0xb3, 0xe5, 0x7a, 0xd8, 0xb3, 0x89, 0x6f, 0x6e, 0xe8, 0x17, 0xb8,
0xcb, 0xb7, 0x61, 0x23, 0x00, 0xba, 0x9a, 0x81, 0xe0, 0xee, 0x25, 0xde, 0x4b, 0x11, 0x10, 0x6b,
0xb1, 0xeb, 0xa2, 0xab, 0x53, 0xd7, 0x51, 0xc9, 0x8a, 0xb6, 0xa3, 0x0e, 0x5a, 0xd8, 0xda, 0x20,
0xa6, 0xbd, 0x4e, 0x5d, 0x8f, 0xd4, 0xcd, 0x86, 0xed, 0x10, 0x5f, 0xbf, 0xc8, 0x5d, 0x5c, 0x80,
0x13, 0x8d, 0xc3, 0x0b, 0x11, 0x3a, 0x0f, 0x60, 0x3a, 0xd0, 0x25, 0xa4, 0xb4, 0x07, 0xd3, 0xbd,
0x85, 0xca, 0x66, 0xb4, 0x6f, 0x29, 0xea, 0xf9, 0x96, 0xe7, 0xae, 0x43, 0x31, 0x63, 0x06, 0xad,
0x3a, 0x66, 0x44, 0x2c, 0x10, 0x9e, 0xe2, 0xbe, 0xaf, 0x42, 0x7e, 0x9b, 0x68, 0xad, 0x71, 0x25,
0xb1, 0x18, 0x88, 0x8a, 0xec, 0x1e, 0xb8, 0x40, 0xe7, 0x65, 0x61, 0x20, 0x94, 0x97, 0x51, 0x2f,
0x8b, 0xda, 0xbb, 0x8a, 0x3a, 0xec, 0xd8, 0x4d, 0x9b, 0x99, 0x35, 0x4c, 0xeb, 0x6d, 0xbb, 0xce,
0x36, 0x4c, 0x9b, 0x9a, 0x0e, 0xa6, 0xfa, 0x28, 0x1f, 0x92, 0x25, 0x5e, 0x3c, 0x82, 0xc6, 0x4c,
0xa2, 0xb0, 0x40, 0x17, 0x31, 0xcd, 0x0a, 0xfe, 0x32, 0xf6, 0x19, 0xc3, 0x22, 0x33, 0xa5, 0xbd,
0xa3, 0xa8, 0x5a, 0xd3, 0xa6, 0xe6, 0x86, 0xdb, 0x24, 0x66, 0xdd, 0xf6, 0x37, 0xcd, 0x86, 0x47,
0x88, 0x6e, 0x8c, 0x29, 0xe3, 0xa7, 0xa6, 0xfa, 0xae, 0x44, 0x37, 0x6b, 0x57, 0x56, 0xec, 0xb7,
0xc8, 0xcc, 0x6b, 0x1f, 0x85, 0xc6, 0x11, 0xd8, 0x89, 0x4d, 0x9b, 0xde, 0x76, 0x9b, 0x64, 0xce,
0xf6, 0x37, 0xe7, 0x3d, 0x42, 0xd2, 0xd5, 0x51, 0x90, 0x8b, 0xfb, 0x60, 0xec, 0x32, 0x10, 0x39,
0x36, 0x39, 0x76, 0x19, 0x15, 0x9b, 0x6b, 0x0f, 0x14, 0xb5, 0x2f, 0x59, 0xef, 0xfc, 0xd8, 0x19,
0xe3, 0xc7, 0xce, 0xef, 0x79, 0xca, 0x93, 0x2c, 0xda, 0xe8, 0xf0, 0x39, 0xe5, 0x65, 0x9f, 0xdd,
0xd0, 0x98, 0x4b, 0x2a, 0x8e, 0x44, 0x26, 0x39, 0x88, 0xe2, 0x1d, 0xe0, 0x17, 0xce, 0x94, 0x26,
0x61, 0xf8, 0xca, 0xe7, 0x7d, 0x97, 0x42, 0xec, 0xce, 0x99, 0xcd, 0x7f, 0x1e, 0xee, 0x55, 0xc7,
0x1f, 0xd5, 0x14, 0xe4, 0x47, 0x02, 0x5f, 0x94, 0xd9, 0xf1, 0x1c, 0xed, 0x0d, 0x75, 0x00, 0x3b,
0x6d, 0xa8, 0xbe, 0xa2, 0xdb, 0x04, 0x4a, 0x98, 0xaf, 0x3f, 0xcd, 0x2f, 0xf1, 0xa0, 0xe8, 0x3d,
0x13, 0x81, 0xbc, 0x2a, 0xbf, 0x4b, 0x18, 0x2c, 0xfc, 0xa1, 0x28, 0xc2, 0xe4, 0xe4, 0x15, 0x54,
0x54, 0xd4, 0xfe, 0xad, 0xa8, 0xe3, 0xee, 0x16, 0xf1, 0xda, 0x9e, 0xcd, 0x20, 0x70, 0x34, 0x5d,
0x46, 0xcc, 0x3a, 0xd9, 0xb2, 0x2d, 0x62, 0x52, 0xdc, 0x24, 0x3e, 0x84, 0xd3, 0xb8, 0x10, 0xd2,
0x2b, 0xd9, 0xf5, 0xd2, 0xc8, 0xbd, 0xa4, 0x11, 0xe2, 0x6d, 0xe6, 0xc8, 0xd6, 0x5d, 0x50, 0xef,
0x84, 0xc6, 0x25, 0xb7, 0x04, 0xd9, 0x16, 0xe1, 0xe8, 0x3d, 0x3a, 0x1b, 0x99, 0xea, 0x86, 0xc6,
0x2b, 0x9c, 0xe0, 0x23, 0xe8, 0xf6, 0x5e, 0x94, 0x50, 0xc5, 0xf5, 0xe0, 0x81, 0x1e, 0x85, 0x85,
0xf6, 0x25, 0xf5, 0x1c, 0x84, 0x31, 0xd3, 0xa6, 0x75, 0xb2, 0x6d, 0xc2, 0x4a, 0xae, 0x39, 0xae,
0xb5, 0xe9, 0xeb, 0x97, 0xf8, 0x96, 0x86, 0x45, 0xa3, 0x81, 0xc2, 0x02, 0xe0, 0x4b, 0x36, 0x9d,
0xe1, 0x68, 0x7a, 0x6b, 0x5b, 0x86, 0xa4, 0x99, 0x72, 0x94, 0xff, 0x22, 0x89, 0x25, 0xed, 0xef,
0x90, 0xee, 0x52, 0x6c, 0x6d, 0x92, 0xba, 0x49, 0x5d, 0x66, 0x37, 0x6c, 0x0b, 0x47, 0xf7, 0x0f,
0x75, 0x5f, 0xaf, 0xf2, 0xf9, 0x7d, 0x0f, 0x86, 0x7b, 0x78, 0x2d, 0x52, 0xba, 0x2b, 0xe8, 0x2c,
0xcc, 0xc1, 0x68, 0x0f, 0x07, 0x52, 0xa4, 0x1b, 0x1a, 0x17, 0xa2, 0xd0, 0x2e, 0x83, 0xf9, 0x5d,
0xa5, 0x14, 0xe9, 0xee, 0x55, 0x7b, 0x58, 0xdc, 0xdd, 0xaf, 0xf6, 0x60, 0x81, 0xa4, 0x2d, 0xea,
0xbe, 0x86, 0xd4, 0xd3, 0xcc, 0xc3, 0x8d, 0x86, 0x6d, 0x99, 0x96, 0x83, 0x7d, 0x5f, 0xbf, 0xcc,
0x87, 0xf5, 0x25, 0xa8, 0x97, 0x63, 0x60, 0x16, 0xe4, 0xdd, 0xd0, 0xd0, 0xa2, 0x01, 0x15, 0x84,
0xe9, 0x45, 0x4d, 0x4e, 0x55, 0xbb, 0xaf, 0x0e, 0xc6, 0x43, 0x6c, 0x36, 0x5c, 0xa7, 0x4e, 0x3c,
0xb3, 0x85, 0xd9, 0x86, 0xfe, 0x0c, 0xdf, 0xf5, 0xd3, 0x70, 0x0c, 0xc4, 0xf0, 0x3c, 0x47, 0x97,
0x31, 0xdb, 0x48, 0x43, 0x4c, 0x09, 0x11, 0xa6, 0xeb, 0x6d, 0x58, 0x56, 0xca, 0xdb, 0xa8, 0xdc,
0x5c, 0xdb, 0x54, 0xcf, 0xfa, 0x84, 0x99, 0x8e, 0xdb, 0x36, 0x5b, 0x9e, 0xed, 0x7a, 0x36, 0xdb,
0xd1, 0x9f, 0xe5, 0x5b, 0x01, 0xfa, 0xeb, 0xf7, 0x09, 0x5b, 0x74, 0xdb, 0xcb, 0x31, 0x92, 0x76,
0x96, 0x17, 0xf7, 0x4c, 0x2c, 0x0a, 0xcd, 0xb5, 0xf7, 0x15, 0x75, 0xb8, 0x89, 0xb7, 0x13, 0xe7,
0x2c, 0x97, 0x5a, 0x81, 0xe7, 0x11, 0x6a, 0xed, 0xe8, 0xe3, 0x7c, 0xf4, 0x7c, 0x7e, 0xc5, 0x82,
0xdb, 0x4b, 0x78, 0x3b, 0xe2, 0x38, 0x9b, 0xa9, 0xc0, 0x41, 0xdf, 0x94, 0xc8, 0xd3, 0x83, 0x5e,
0x06, 0x26, 0x03, 0xcd, 0xef, 0x44, 0xe4, 0x76, 0x91, 0xd4, 0xaa, 0xf6, 0xb1, 0xa2, 0x0e, 0x5a,
0x1e, 0xf6, 0x37, 0x0a, 0x99, 0xff, 0x73, 0x7c, 0x32, 0x3e, 0xe0, 0x99, 0xff, 0x6c, 0x92, 0xf9,
0x5b, 0x71, 0xe6, 0x3f, 0x1f, 0x9d, 0xc8, 0xd0, 0x2c, 0xcb, 0xc1, 0xa5, 0xc1, 0x97, 0xeb, 0x94,
0xb3, 0x79, 0x2e, 0x86, 0x15, 0x3c, 0x50, 0x32, 0x02, 0x35, 0x81, 0x15, 0xd7, 0x04, 0xd5, 0x47,
0x31, 0x03, 0x55, 0xc1, 0x6c, 0x54, 0x15, 0x14, 0x8c, 0x79, 0x8e, 0xf6, 0x23, 0x45, 0x1d, 0x29,
0xba, 0x97, 0x5c, 0xc6, 0x3c, 0xcf, 0xe7, 0xdf, 0x3e, 0x08, 0x8d, 0x93, 0xb3, 0x48, 0x78, 0x47,
0xc8, 0x5b, 0x29, 0xbe, 0x23, 0x48, 0xd1, 0x5e, 0x4b, 0x63, 0x77, 0xbf, 0x9a, 0xd9, 0x46, 0x72,
0xcb, 0xda, 0x57, 0x14, 0x75, 0xd8, 0x67, 0x01, 0x35, 0x21, 0x5f, 0xc2, 0x8e, 0xbd, 0x45, 0xcc,
0x28, 0x0b, 0xf6, 0xf5, 0x17, 0xd2, 0x2c, 0x74, 0x10, 0x34, 0xee, 0x24, 0x0a, 0x2b, 0x80, 0xaf,
0xa4, 0xb9, 0x91, 0x04, 0xcb, 0xa7, 0xf0, 0x42, 0x18, 0x3b, 0x36, 0x79, 0x73, 0x02, 0xc9, 0xac,
0x41, 0x65, 0x5c, 0xa0, 0x01, 0xd1, 0xd4, 0xd7, 0x5f, 0xe4, 0x24, 0x5e, 0x87, 0x7d, 0x99, 0x6b,
0xb6, 0x64, 0xd3, 0xac, 0x82, 0x28, 0x21, 0x62, 0x66, 0x98, 0x0b, 0xa3, 0x53, 0x13, 0xa8, 0x6c,
0x07, 0x72, 0xf1, 0x3e, 0xde, 0x7b, 0xf2, 0xbc, 0xf5, 0x12, 0x8f, 0x9c, 0xf5, 0x83, 0xd0, 0xe8,
0x47, 0xb8, 0xbd, 0xc2, 0x02, 0xe1, 0x61, 0xeb, 0x94, 0x9f, 0x7d, 0xa6, 0x57, 0x50, 0x99, 0xec,
0xa1, 0x8f, 0x6f, 0x05, 0x8b, 0x48, 0xb4, 0xa7, 0x6d, 0xa9, 0x67, 0xa0, 0xd8, 0xac, 0x61, 0x9f,
0x98, 0xd1, 0x4b, 0xa3, 0x7e, 0x65, 0x4c, 0x19, 0xef, 0x9f, 0xea, 0x4f, 0x92, 0xa1, 0x55, 0x2e,
0xe5, 0x77, 0x86, 0xfd, 0x89, 0x6a, 0x24, 0xcb, 0xc2, 0x54, 0x4e, 0x5c, 0x19, 0x8b, 0x4b, 0x8f,
0x78, 0x79, 0xbc, 0xb3, 0x5f, 0x55, 0x50, 0xa1, 0xa9, 0xf6, 0xed, 0xa3, 0xea, 0x25, 0x88, 0x1a,
0x69, 0xb8, 0x80, 0xd2, 0xd5, 0x72, 0x9b, 0xb0, 0x64, 0x3d, 0x72, 0x3f, 0x20, 0x3e, 0x33, 0x37,
0xed, 0x9a, 0x7e, 0x95, 0x4f, 0xc7, 0x9f, 0x94, 0xf8, 0x85, 0x72, 0x09, 0x6f, 0xcf, 0x2e, 0xa0,
0x08, 0xbf, 0x63, 0xcf, 0x74, 0x42, 0xc3, 0x68, 0xe2, 0xed, 0x74, 0x8b, 0xb3, 0x85, 0xd8, 0x46,
0xa6, 0x92, 0x9e, 0x7d, 0x0f, 0xd1, 0x13, 0xca, 0xbe, 0x87, 0x9a, 0x7c, 0xb8, 0x4a, 0xfc, 0xe6,
0x59, 0xa0, 0x8b, 0x1e, 0xd2, 0xac, 0xa6, 0x7d, 0xaa, 0xa8, 0xc3, 0xe9, 0xc3, 0x8b, 0x83, 0xc5,
0xa7, 0xda, 0x09, 0xbe, 0x81, 0x3f, 0x84, 0x91, 0x18, 0x4a, 0x1e, 0x2e, 0x16, 0xa7, 0xef, 0x8a,
0xaf, 0xb5, 0x43, 0x58, 0x22, 0x4f, 0xd3, 0x67, 0x19, 0x28, 0x7b, 0x2f, 0x93, 0x1a, 0xe9, 0x21,
0x17, 0xb6, 0xbe, 0x94, 0x14, 0xca, 0x5a, 0x61, 0xe1, 0xa9, 0x77, 0x4b, 0x3d, 0xcf, 0xdf, 0x56,
0x1a, 0x81, 0xe3, 0xc4, 0xb9, 0x8c, 0x4b, 0x93, 0xc2, 0x54, 0x9f, 0xe4, 0x9e, 0xde, 0x82, 0x5c,
0x01, 0xb4, 0xe6, 0x03, 0xc7, 0xe1, 0x59, 0xc8, 0x3d, 0x1a, 0x97, 0x92, 0xdd, 0xd0, 0xb8, 0x18,
0x1f, 0x59, 0x32, 0xb8, 0x82, 0x7a, 0xb4, 0xd3, 0x5e, 0x57, 0x4f, 0x37, 0x08, 0x66, 0x81, 0x47,
0xcc, 0x86, 0x83, 0xd7, 0x7d, 0x7d, 0x8a, 0xef, 0xbb, 0xcb, 0x70, 0xbe, 0xc7, 0xc0, 0x3c, 0xc8,
0xd3, 0x77, 0x18, 0x41, 0x58, 0x41, 0x39, 0x15, 0xad, 0xad, 0x8e, 0x08, 0xcf, 0x2f, 0x51, 0x65,
0x43, 0xa8, 0x1b, 0xac, 0x6f, 0xe8, 0xd7, 0xf8, 0xa2, 0x7d, 0x95, 0x87, 0xd7, 0x54, 0x65, 0x11,
0x34, 0x5e, 0xe3, 0x0a, 0x69, 0xae, 0x23, 0x45, 0xd3, 0x3c, 0x42, 0xde, 0x58, 0xdb, 0x54, 0x87,
0x4a, 0x1d, 0x37, 0xf1, 0xb6, 0x7e, 0x9d, 0xf7, 0xfa, 0x0a, 0xa4, 0x80, 0x85, 0x86, 0x4b, 0x78,
0xbb, 0x1b, 0x1a, 0xba, 0xac, 0xcb, 0x25, 0xbc, 0x9d, 0xf6, 0x27, 0x69, 0xa6, 0x7d, 0x51, 0xed,
0x0b, 0x5a, 0xb4, 0x95, 0x1e, 0x23, 0x3f, 0x9b, 0xe7, 0x93, 0xf3, 0x7f, 0x07, 0xa1, 0x71, 0x6e,
0x8e, 0xb4, 0x3c, 0x62, 0x61, 0x46, 0xea, 0x6b, 0xcb, 0x74, 0x39, 0x3b, 0x53, 0x94, 0x97, 0xb2,
0x64, 0xae, 0x45, 0x5b, 0x31, 0xf0, 0xa2, 0xdb, 0xb4, 0x21, 0xa1, 0x64, 0x3b, 0x95, 0xdd, 0xfd,
0xaa, 0xbc, 0xb1, 0xae, 0xa0, 0x53, 0x42, 0x13, 0xed, 0x27, 0x4a, 0xdc, 0x7d, 0x72, 0x55, 0xff,
0xfe, 0x3c, 0x77, 0xf2, 0x1d, 0xbe, 0x0b, 0xf2, 0x26, 0xd2, 0x6b, 0x7b, 0xde, 0xfd, 0x58, 0xda,
0xbd, 0x78, 0xdd, 0x2e, 0x70, 0xc8, 0xb6, 0xfb, 0xf9, 0xde, 0x5a, 0xb0, 0xac, 0x65, 0xbd, 0xe8,
0x0a, 0x52, 0xb3, 0x56, 0xda, 0xaf, 0x14, 0xb5, 0x9f, 0xd3, 0xcc, 0x2e, 0xe5, 0x7f, 0x1e, 0x11,
0xfd, 0x3a, 0xcf, 0x85, 0xf3, 0x26, 0x84, 0x0b, 0x7a, 0x4e, 0xb5, 0x92, 0x52, 0xcd, 0x5f, 0xa9,
0x4b, 0xc9, 0x5e, 0xfc, 0x2c, 0x3d, 0xc8, 0x78, 0xe5, 0x7d, 0xe9, 0x0a, 0xea, 0x13, 0x5b, 0x66,
0x94, 0xb3, 0xab, 0xf7, 0x0f, 0x7a, 0x53, 0x16, 0xae, 0xe1, 0x0b, 0x94, 0xf3, 0x17, 0xe7, 0xbd,
0x29, 0xf7, 0xd2, 0x2b, 0x53, 0x4e, 0x34, 0x13, 0xca, 0xe9, 0x4d, 0x7b, 0x43, 0x8d, 0x9e, 0xf8,
0xd2, 0x43, 0xf3, 0x17, 0xf3, 0x7c, 0xf7, 0xfe, 0x4f, 0x9e, 0x2f, 0x7f, 0x25, 0xcb, 0x4e, 0x4f,
0x61, 0x31, 0x7a, 0x19, 0x22, 0x10, 0x85, 0x7e, 0x04, 0xc4, 0xe7, 0x17, 0x15, 0xe5, 0x3b, 0x02,
0xb3, 0x65, 0x31, 0xfd, 0x43, 0x18, 0x22, 0x65, 0x66, 0xe9, 0x20, 0x34, 0x2e, 0x66, 0x3d, 0x2e,
0xe5, 0x2b, 0xfc, 0x65, 0x8b, 0xe5, 0xc7, 0xa9, 0x59, 0xc2, 0xf3, 0xdd, 0x6b, 0x65, 0x05, 0xc8,
0x10, 0x86, 0x0a, 0xe7, 0xa3, 0x6f, 0x61, 0xea, 0xeb, 0xbf, 0x8c, 0x66, 0x69, 0xb5, 0x40, 0x41,
0x3c, 0x57, 0x56, 0x40, 0xb1, 0x40, 0xa1, 0x84, 0x97, 0xa7, 0x8a, 0x33, 0x29, 0xe9, 0xcd, 0xdc,
0xf9, 0xe8, 0x93, 0xd1, 0x23, 0xfb, 0x9f, 0x8c, 0x1e, 0xf9, 0xe8, 0x60, 0x54, 0xd9, 0x3f, 0x18,
0x55, 0xbe, 0xf9, 0x60, 0xf4, 0xc8, 0x7b, 0x0f, 0x46, 0x95, 0xfd, 0x07, 0xa3, 0x47, 0xfe, 0xf6,
0x60, 0xf4, 0xc8, 0x9b, 0xcf, 0xad, 0xdb, 0x6c, 0x23, 0xa8, 0x5d, 0xb1, 0xdc, 0xe6, 0xd5, 0x34,
0x6b, 0x15, 0x7e, 0x65, 0xff, 0x59, 0xaa, 0x9d, 0xe0, 0x7f, 0x52, 0xba, 0xf6, 0x9f, 0x00, 0x00,
0x00, 0xff, 0xff, 0x43, 0x37, 0xb7, 0x54, 0x10, 0x25, 0x00, 0x00,
// 3218 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x5a, 0x5d, 0x6c, 0x1d, 0x47,
0xf5, 0xcf, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x1e, 0x3b, 0xf6, 0x36, 0x49, 0xbd, 0xee, 0xcd,
0x4d, 0xeb, 0x7e, 0x25, 0xb6, 0x93, 0xe6, 0x9f, 0x46, 0xfa, 0xab, 0xf8, 0xa3, 0x26, 0x6e, 0xec,
0xc4, 0x1a, 0xdb, 0x2a, 0x2a, 0x42, 0xab, 0xb9, 0x7b, 0xe7, 0xda, 0x8b, 0xf7, 0xce, 0xde, 0xee,
0xcc, 0xfa, 0xda, 0x2d, 0x82, 0xaa, 0x88, 0x8f, 0x37, 0xc0, 0xe2, 0x43, 0x02, 0x09, 0x15, 0x01,
0x12, 0xa5, 0x14, 0x21, 0x21, 0x21, 0xc1, 0x0b, 0x08, 0x09, 0xa9, 0x82, 0x07, 0xfb, 0xb1, 0x12,
0x65, 0x51, 0x9d, 0x3e, 0xdd, 0x07, 0x1e, 0xee, 0xa3, 0x79, 0x41, 0x33, 0xfb, 0x35, 0xbb, 0x3b,
0xb7, 0xc9, 0xdb, 0xdd, 0xf3, 0x3b, 0x73, 0xe6, 0x77, 0xe6, 0xe3, 0xcc, 0x39, 0x33, 0x57, 0xbf,
0xec, 0x3a, 0xb5, 0xab, 0xb6, 0x47, 0x1a, 0xce, 0xfa, 0x55, 0xaf, 0xc5, 0x1c, 0x8f, 0xd0, 0xe8,
0x2b, 0xf0, 0x11, 0xff, 0xba, 0xd2, 0xf2, 0x3d, 0xe6, 0x81, 0x13, 0x91, 0xf0, 0xfc, 0x88, 0xa4,
0xce, 0x02, 0xe2, 0x90, 0xf5, 0x48, 0xe1, 0xfc, 0x39, 0x09, 0xa0, 0xce, 0x9b, 0x38, 0x16, 0x9f,
0xc4, 0xdb, 0x2c, 0xfa, 0x59, 0xf9, 0xe8, 0xb6, 0x3e, 0x74, 0x2f, 0xea, 0x61, 0x56, 0xee, 0x01,
0xfc, 0x54, 0xd3, 0xcf, 0xba, 0x0e, 0x65, 0x98, 0x58, 0xa8, 0x5e, 0xf7, 0x31, 0xa5, 0x98, 0x1a,
0xda, 0xd8, 0xb1, 0xf1, 0x93, 0x33, 0xf4, 0x20, 0x34, 0x01, 0x44, 0xed, 0x45, 0x01, 0x4f, 0x27,
0x68, 0x27, 0x34, 0xcf, 0xb8, 0x79, 0x51, 0x37, 0x34, 0x2f, 0x6f, 0x37, 0xdd, 0x5b, 0x95, 0x9c,
0xbc, 0x32, 0x56, 0xc7, 0x0d, 0x14, 0xb8, 0xec, 0x56, 0x25, 0xfe, 0x51, 0x39, 0xdc, 0xab, 0x3e,
0x1a, 0xff, 0xde, 0xdd, 0xaf, 0x2a, 0x8c, 0xc3, 0xa2, 0x69, 0xf0, 0x1f, 0x4d, 0x37, 0xd6, 0x5d,
0xaf, 0x86, 0x5c, 0xab, 0xee, 0x50, 0xdb, 0xdb, 0xc2, 0xfe, 0x8e, 0x45, 0xb1, 0xbf, 0x85, 0x7d,
0x6a, 0x1c, 0x15, 0x44, 0x7f, 0xaf, 0x1d, 0x84, 0xe6, 0x20, 0x44, 0xed, 0xcf, 0x0b, 0xbd, 0x69,
0x42, 0x56, 0x22, 0xbc, 0x13, 0x9a, 0xe7, 0xd6, 0x13, 0x99, 0x17, 0x10, 0x1b, 0xc7, 0x40, 0x37,
0x34, 0x9f, 0x17, 0x84, 0x55, 0xa8, 0x82, 0x77, 0x67, 0xaf, 0x3a, 0xa4, 0x52, 0xed, 0xee, 0x55,
0xd5, 0x1d, 0xe4, 0x1d, 0x55, 0x71, 0x83, 0xc3, 0x51, 0xc3, 0xb9, 0xc4, 0xa9, 0x58, 0x0e, 0x3e,
0x55, 0x39, 0x8c, 0x09, 0xaa, 0xb9, 0xb8, 0x6e, 0x1c, 0x1b, 0xd3, 0xc6, 0x1f, 0x9b, 0x79, 0x8f,
0x3b, 0x7c, 0x36, 0xb5, 0xf8, 0x4a, 0x04, 0x96, 0xbd, 0x8d, 0x81, 0x6e, 0x68, 0x3e, 0xab, 0xf0,
0x36, 0x46, 0x25, 0x77, 0x99, 0x1f, 0x60, 0xee, 0x6b, 0x0f, 0x33, 0xbd, 0x80, 0xc3, 0xbd, 0xea,
0x23, 0xbc, 0xe9, 0xee, 0x7e, 0xb5, 0x44, 0xaa, 0xe4, 0x66, 0x2c, 0x07, 0x1f, 0x6b, 0xfa, 0x88,
0xeb, 0xd9, 0x4a, 0x2f, 0x1f, 0x11, 0x5e, 0xfe, 0x9c, 0x7b, 0x79, 0x66, 0x91, 0xeb, 0xe4, 0x9c,
0x1c, 0x72, 0x63, 0x51, 0xc1, 0xc7, 0x67, 0xa2, 0x25, 0xa8, 0x00, 0x15, 0x2e, 0xaa, 0x8d, 0xf4,
0x90, 0x4b, 0x0e, 0x16, 0xf9, 0xc0, 0x73, 0xa2, 0x41, 0xc9, 0xbd, 0x7f, 0x68, 0xfa, 0x60, 0xe4,
0x1e, 0x8a, 0x6d, 0x59, 0x2d, 0xcf, 0x67, 0xc6, 0xf1, 0x31, 0x6d, 0xfc, 0xf8, 0xcc, 0x8f, 0xb9,
0x6b, 0x7d, 0x89, 0xa9, 0x65, 0xcf, 0x67, 0x9d, 0xd0, 0x1c, 0xc8, 0x75, 0xcd, 0x85, 0xdd, 0xd0,
0x7c, 0xba, 0xec, 0x14, 0x47, 0x24, 0x8f, 0xa6, 0x26, 0x27, 0xa6, 0xfe, 0xaf, 0x72, 0x18, 0x9a,
0xc7, 0x1c, 0xc2, 0x3a, 0x7b, 0x55, 0x85, 0x19, 0x95, 0xf0, 0x70, 0xaf, 0x7a, 0x5c, 0x34, 0xdd,
0xdd, 0xaf, 0xe6, 0x98, 0xc0, 0xb2, 0x2e, 0xf8, 0xfa, 0x51, 0x7d, 0xac, 0xe0, 0x4d, 0x33, 0x70,
0x99, 0x63, 0x23, 0xca, 0x92, 0xb8, 0x61, 0x9c, 0x18, 0xd3, 0xc6, 0x4f, 0xce, 0xfc, 0x91, 0xbb,
0xd6, 0x9f, 0x18, 0x5c, 0x9a, 0xe5, 0x3b, 0xb9, 0x13, 0x9a, 0x83, 0x39, 0xa3, 0x91, 0xb8, 0x1b,
0x9a, 0x37, 0xca, 0xee, 0x45, 0x98, 0xe4, 0xe0, 0x17, 0x1b, 0x8d, 0xc9, 0xa9, 0x5b, 0xb7, 0x6e,
0x5e, 0xbb, 0x79, 0xfd, 0x4b, 0xb7, 0x22, 0x6f, 0x3b, 0x7b, 0x55, 0xa5, 0x41, 0xb5, 0xf8, 0x70,
0xaf, 0x0a, 0xca, 0x46, 0x76, 0xf7, 0xab, 0x05, 0x9a, 0xf0, 0x89, 0x7c, 0xe3, 0xc4, 0xc3, 0x38,
0x18, 0x81, 0x7b, 0xfa, 0xe9, 0x26, 0xda, 0xb6, 0x28, 0x26, 0x75, 0x6b, 0xb3, 0xd6, 0xa2, 0xc6,
0xa3, 0x62, 0x32, 0x9f, 0xeb, 0x84, 0xe6, 0xa9, 0x26, 0xda, 0x5e, 0xc1, 0xa4, 0x7e, 0xa7, 0xd6,
0xe2, 0xc1, 0x65, 0x40, 0xb8, 0x25, 0xc9, 0x92, 0xf9, 0x81, 0xb2, 0x62, 0x62, 0xd0, 0xc7, 0xf6,
0x56, 0x64, 0xf0, 0xb1, 0x9c, 0x41, 0x88, 0xed, 0xad, 0xa2, 0xc1, 0x44, 0x96, 0x33, 0x98, 0x08,
0xc1, 0x1f, 0x34, 0x7d, 0xc4, 0xc7, 0xb6, 0x47, 0x08, 0xb6, 0x79, 0x78, 0xb7, 0x1c, 0xc2, 0xb0,
0xbf, 0x85, 0x5c, 0x8b, 0x1a, 0x27, 0x85, 0xed, 0xaf, 0x8a, 0xa0, 0x9e, 0xa8, 0x2c, 0xc4, 0xf0,
0x0a, 0x8f, 0x1d, 0x72, 0xc3, 0x14, 0xe8, 0x86, 0xe6, 0xb8, 0xe8, 0x5b, 0x89, 0x4a, 0xb3, 0x74,
0x63, 0x22, 0xa1, 0x74, 0xb8, 0x57, 0x3d, 0x7a, 0x63, 0x42, 0xc4, 0xf7, 0x52, 0x3f, 0x50, 0xdd,
0x0b, 0x68, 0xe8, 0xfd, 0x3e, 0x76, 0xd1, 0x0e, 0x4d, 0x63, 0x80, 0x2e, 0x62, 0xc0, 0xcb, 0x9d,
0xd0, 0x3c, 0x1d, 0x21, 0xd9, 0x46, 0xaf, 0xc4, 0x84, 0x24, 0x69, 0x71, 0x87, 0x27, 0x3b, 0x16,
0xe6, 0x1b, 0x83, 0x77, 0x8e, 0xea, 0x17, 0xe2, 0x8e, 0x52, 0x22, 0xd9, 0x20, 0x35, 0x8d, 0x53,
0x62, 0x90, 0xfe, 0xca, 0xd7, 0xf0, 0x08, 0xe4, 0x7a, 0x25, 0x17, 0x96, 0x3a, 0xa1, 0x39, 0xe2,
0xab, 0xa1, 0x34, 0xd0, 0xf6, 0xc0, 0x25, 0x96, 0x93, 0x13, 0xd2, 0x96, 0xed, 0x69, 0xaf, 0x37,
0xc4, 0x07, 0x79, 0x92, 0x0f, 0x72, 0x2f, 0x9a, 0xd0, 0x88, 0xfc, 0x2c, 0x23, 0xa0, 0xa6, 0x9f,
0xa6, 0x0c, 0xf9, 0xcc, 0xaa, 0xf9, 0x5e, 0x9b, 0x62, 0xdf, 0xe8, 0x13, 0x63, 0xfd, 0xff, 0x9d,
0xd0, 0xec, 0x13, 0xc0, 0x4c, 0x24, 0xef, 0x86, 0xe6, 0x93, 0xc2, 0x1d, 0x59, 0xd8, 0x73, 0xa4,
0x73, 0x4d, 0xc1, 0x2f, 0x35, 0xfd, 0x1c, 0x41, 0xcc, 0x62, 0x3e, 0xe2, 0xa7, 0x1a, 0x72, 0xd3,
0x89, 0xed, 0x17, 0x9d, 0xbd, 0x71, 0x10, 0x9a, 0xfa, 0xdd, 0xe9, 0xd5, 0x2c, 0xac, 0xeb, 0x04,
0xb1, 0x6c, 0x8e, 0x4d, 0xd1, 0x71, 0x26, 0x52, 0x84, 0x70, 0xb9, 0x41, 0xee, 0x4b, 0x0a, 0xd7,
0x52, 0x17, 0x70, 0x90, 0x20, 0xb6, 0x9a, 0xd0, 0x49, 0x16, 0xc4, 0x9f, 0x4a, 0x3c, 0x5d, 0x8c,
0x28, 0xb6, 0x9a, 0xc6, 0x19, 0xb1, 0x14, 0xbe, 0xc9, 0x97, 0xc2, 0xc9, 0xbb, 0xd3, 0xab, 0x8b,
0x5c, 0xcc, 0x27, 0xff, 0x0c, 0x41, 0x2c, 0xfa, 0x70, 0x48, 0xc0, 0x44, 0xf2, 0x53, 0x49, 0xc8,
0xca, 0x72, 0xe5, 0xde, 0xe8, 0xec, 0x55, 0x4b, 0xed, 0xcb, 0xa2, 0x74, 0x07, 0x65, 0x1d, 0x43,
0x20, 0xb3, 0x8f, 0x64, 0xe0, 0xef, 0x9a, 0x3e, 0x92, 0x27, 0xef, 0x63, 0x82, 0xdb, 0x62, 0x25,
0x9f, 0x15, 0xf4, 0x77, 0x39, 0xfd, 0x53, 0x77, 0xa7, 0x57, 0x61, 0x04, 0x70, 0x07, 0x06, 0x08,
0x62, 0xc9, 0x67, 0xea, 0x42, 0x35, 0x71, 0x21, 0x8f, 0x48, 0x4e, 0x5c, 0x93, 0x9d, 0x50, 0xd8,
0x50, 0x09, 0xb9, 0x23, 0xd7, 0xb8, 0x23, 0x32, 0x05, 0x38, 0x24, 0xbb, 0x92, 0x48, 0x15, 0xce,
0x30, 0xa7, 0x89, 0xbd, 0x80, 0x59, 0xd4, 0x18, 0xc8, 0x3b, 0xb3, 0x1a, 0x01, 0x2b, 0xb1, 0x33,
0xc9, 0x27, 0x5f, 0xe9, 0xf5, 0x9c, 0x33, 0x79, 0xa4, 0xd7, 0xf6, 0x53, 0xd8, 0x50, 0x09, 0xd3,
0x2d, 0x27, 0x53, 0xc8, 0x3b, 0x93, 0x48, 0xc1, 0x4f, 0x34, 0xdd, 0x08, 0x28, 0x5a, 0xc7, 0x96,
0x8f, 0xf9, 0xb9, 0xef, 0x90, 0x75, 0x0b, 0xd9, 0x36, 0x6e, 0x31, 0x5c, 0x37, 0x80, 0xf0, 0x06,
0xf1, 0x1d, 0xb0, 0x06, 0xa7, 0x63, 0x29, 0xdf, 0x01, 0x81, 0x9f, 0x7c, 0x75, 0x43, 0xf3, 0xac,
0x70, 0x22, 0x13, 0x49, 0x84, 0x65, 0xc5, 0xdc, 0x17, 0x5f, 0xf1, 0x99, 0x49, 0x38, 0x2c, 0x28,
0xc0, 0x84, 0x41, 0x22, 0x07, 0x6f, 0xe9, 0x43, 0x45, 0x72, 0x14, 0x63, 0x62, 0x0c, 0x0a, 0x62,
0x0b, 0x07, 0xa1, 0x79, 0x62, 0x0d, 0xae, 0x60, 0x4c, 0x3a, 0xa1, 0x79, 0x22, 0xf0, 0xf9, 0xaf,
0x6e, 0x68, 0xf6, 0xc5, 0x84, 0xf8, 0xa7, 0x44, 0x26, 0x51, 0x48, 0x7f, 0xed, 0xee, 0x57, 0xe3,
0xe6, 0x10, 0xe4, 0x09, 0x70, 0x19, 0xf8, 0x81, 0xa6, 0x3f, 0x5e, 0xec, 0x3d, 0x20, 0xce, 0x1b,
0x01, 0xb6, 0x9c, 0xba, 0x31, 0x24, 0x92, 0x88, 0xd7, 0xa3, 0xb1, 0x59, 0x13, 0xe2, 0x85, 0xb9,
0x68, 0x6c, 0xe2, 0x2f, 0x79, 0x6c, 0x12, 0x85, 0x4a, 0x34, 0x28, 0xc9, 0x67, 0x57, 0xfe, 0x8a,
0x07, 0x25, 0xc1, 0x8a, 0x83, 0x92, 0x68, 0x81, 0xbf, 0x68, 0xfa, 0x60, 0x89, 0x97, 0xef, 0x1a,
0xe7, 0x04, 0xa3, 0xef, 0xf0, 0xb5, 0x77, 0x7c, 0x0d, 0xae, 0xc1, 0xc5, 0x4e, 0x68, 0x1e, 0x0f,
0xfc, 0x35, 0xb8, 0xd8, 0x0d, 0xcd, 0x9b, 0x09, 0x11, 0xb8, 0x28, 0xad, 0xae, 0x0d, 0xc6, 0x5a,
0xf4, 0xd6, 0xd5, 0xab, 0x75, 0xc4, 0xd0, 0x15, 0xba, 0x43, 0x6c, 0xb6, 0xc1, 0x8b, 0x35, 0x82,
0xd9, 0x55, 0x82, 0xdb, 0x5c, 0xca, 0x09, 0xc7, 0x46, 0x92, 0x1f, 0x87, 0x7b, 0xd5, 0x87, 0x68,
0xb8, 0xbb, 0x5f, 0x8d, 0x58, 0xc0, 0x81, 0x82, 0x1f, 0xbe, 0x0b, 0xfe, 0xad, 0xe9, 0x66, 0xd1,
0x85, 0x96, 0x47, 0xf9, 0x09, 0x47, 0xb1, 0x1d, 0xf8, 0xd8, 0xdd, 0x31, 0x86, 0x45, 0xf8, 0xfd,
0x91, 0xa8, 0x20, 0xd6, 0xe0, 0xb2, 0x47, 0xd9, 0x42, 0x0a, 0x76, 0x42, 0xf3, 0x6c, 0xe0, 0xe7,
0x65, 0xdd, 0xd0, 0x7c, 0x2a, 0x76, 0x32, 0x0f, 0x48, 0xfe, 0x36, 0x90, 0x4b, 0x45, 0x48, 0x2e,
0xb7, 0x56, 0xc8, 0x78, 0xe6, 0x29, 0x5a, 0xf0, 0x7a, 0xa1, 0x48, 0x01, 0x5e, 0xcc, 0xbb, 0x95,
0x47, 0xc1, 0xbf, 0x14, 0x1e, 0x3a, 0xc4, 0x61, 0x0e, 0xaf, 0x23, 0xf8, 0x79, 0x67, 0x51, 0x63,
0x44, 0xac, 0xe2, 0x1f, 0x8a, 0xea, 0x61, 0x0d, 0x2e, 0x44, 0xe8, 0x1c, 0x07, 0x79, 0xc0, 0x38,
0x13, 0xf8, 0x39, 0x51, 0x1a, 0x2e, 0x0a, 0x72, 0x39, 0x58, 0xdc, 0x9c, 0xc8, 0x05, 0xf0, 0xa2,
0x85, 0xb2, 0x88, 0x9f, 0x40, 0xbc, 0x15, 0x2f, 0x18, 0x0a, 0x14, 0xe0, 0x85, 0xbc, 0x83, 0x39,
0x10, 0x78, 0xfa, 0x80, 0x8f, 0xa3, 0xc3, 0xd9, 0x23, 0x56, 0x1b, 0x6d, 0xe2, 0xa0, 0x65, 0x18,
0x62, 0xca, 0x66, 0x39, 0xf9, 0x18, 0xbc, 0x47, 0x5e, 0x13, 0x50, 0x4a, 0xbe, 0x20, 0xef, 0x79,
0x48, 0x17, 0x0d, 0x80, 0x6f, 0x69, 0xfa, 0x08, 0x0a, 0x98, 0x67, 0x05, 0xad, 0x75, 0x1f, 0xd5,
0x71, 0x96, 0x0c, 0x6d, 0x18, 0x8f, 0x8b, 0x81, 0x5c, 0xe6, 0x25, 0x17, 0x57, 0x59, 0x8b, 0x34,
0x92, 0x3c, 0xe2, 0x76, 0x5a, 0x9d, 0xa8, 0x40, 0x79, 0xf8, 0xa6, 0xe4, 0xcc, 0x70, 0x72, 0x0a,
0x2a, 0xad, 0x81, 0xa6, 0x3e, 0x92, 0x70, 0x60, 0x9e, 0xd5, 0xf2, 0xf9, 0x14, 0x8b, 0xb3, 0x98,
0x1a, 0xe7, 0xc5, 0x00, 0xdc, 0xe0, 0x44, 0x62, 0x95, 0x55, 0x6f, 0xd9, 0xc7, 0x30, 0xc6, 0xbb,
0xa1, 0x79, 0x3e, 0x9a, 0x42, 0x05, 0x58, 0x81, 0xca, 0x36, 0x60, 0x4b, 0x07, 0x9b, 0x18, 0xb7,
0x2c, 0x86, 0x9b, 0x2d, 0xcf, 0x47, 0xbe, 0x83, 0xa9, 0xb5, 0x61, 0x5c, 0x10, 0x2e, 0xdf, 0xe6,
0x1b, 0x81, 0xa3, 0xab, 0x19, 0xc8, 0xdd, 0xbd, 0x24, 0x7a, 0x29, 0x02, 0x72, 0x2d, 0x76, 0x5d,
0x76, 0x75, 0xea, 0x3a, 0x2c, 0x59, 0x01, 0x3b, 0xfa, 0xa0, 0x8d, 0xec, 0x0d, 0x6c, 0x39, 0xeb,
0xc4, 0xf3, 0x71, 0xdd, 0x6a, 0x38, 0x2e, 0xa6, 0xc6, 0x45, 0xe1, 0xe2, 0x02, 0x3f, 0xd1, 0x04,
0xbc, 0x10, 0xa1, 0xf3, 0x1c, 0x4c, 0x07, 0xba, 0x84, 0x94, 0xf6, 0x60, 0xba, 0xb7, 0x60, 0xd9,
0x0c, 0xf8, 0x9e, 0xa6, 0x9f, 0x6f, 0xf9, 0xde, 0x3a, 0x2f, 0x66, 0xac, 0xa0, 0x55, 0x47, 0x0c,
0xcb, 0x05, 0xc2, 0x13, 0xc2, 0xf7, 0x55, 0x9e, 0xdf, 0x26, 0x5a, 0x6b, 0x42, 0x49, 0x2e, 0x06,
0xa2, 0x22, 0xbb, 0x07, 0x2e, 0xd1, 0x79, 0x51, 0x1a, 0x08, 0xed, 0x45, 0xd8, 0xcb, 0x22, 0x78,
0x47, 0xd3, 0x87, 0x5d, 0xa7, 0xe9, 0x30, 0xab, 0x86, 0x48, 0xbd, 0xed, 0xd4, 0xd9, 0x86, 0xe5,
0x10, 0xcb, 0x45, 0xc4, 0x18, 0x15, 0x43, 0xb2, 0x24, 0x8a, 0x47, 0xae, 0x31, 0x93, 0x28, 0x2c,
0x90, 0x45, 0x44, 0xb2, 0x82, 0xbf, 0x8c, 0x7d, 0xc6, 0xb0, 0xa8, 0x4c, 0x81, 0xb7, 0x35, 0x1d,
0x34, 0x1d, 0x62, 0x6d, 0x78, 0x4d, 0x6c, 0xd5, 0x1d, 0xba, 0x69, 0x35, 0x7c, 0x8c, 0x0d, 0x73,
0x4c, 0x1b, 0x3f, 0x35, 0xd5, 0x77, 0x25, 0xba, 0x59, 0xbb, 0xb2, 0xe2, 0xbc, 0x89, 0x67, 0x5e,
0xf9, 0x30, 0x34, 0x8f, 0xf0, 0x9d, 0xd8, 0x74, 0xc8, 0x6d, 0xaf, 0x89, 0xe7, 0x1c, 0xba, 0x39,
0xef, 0x63, 0x9c, 0xae, 0x8e, 0x82, 0x5c, 0xde, 0x07, 0x63, 0x97, 0x39, 0x91, 0x63, 0x93, 0x63,
0x97, 0x61, 0xb1, 0x39, 0xb8, 0xaf, 0xe9, 0x7d, 0xc9, 0x7a, 0x17, 0xc7, 0xce, 0x98, 0x38, 0x76,
0xfe, 0x2c, 0x52, 0x9e, 0x64, 0xd1, 0x46, 0x87, 0xcf, 0x29, 0x3f, 0xfb, 0xec, 0x86, 0xe6, 0x5c,
0x52, 0x71, 0x24, 0x32, 0xc5, 0x41, 0x14, 0xef, 0x00, 0x5a, 0x38, 0x53, 0x9a, 0x98, 0xa1, 0x2b,
0x5f, 0xa6, 0x1e, 0xe1, 0xb1, 0x3b, 0x67, 0x36, 0xff, 0x79, 0xb8, 0x57, 0x1d, 0x7f, 0x58, 0x53,
0x3c, 0x3f, 0x92, 0xf8, 0xc2, 0xcc, 0x8e, 0xef, 0x82, 0xd7, 0xf4, 0x01, 0xe4, 0xb6, 0x79, 0xf5,
0x15, 0xdd, 0x26, 0x10, 0xcc, 0xa8, 0xf1, 0xa4, 0xb8, 0xc4, 0xe3, 0x45, 0xef, 0x99, 0x08, 0x14,
0x55, 0xf9, 0x5d, 0xcc, 0xf8, 0xc2, 0x1f, 0x8a, 0x22, 0x4c, 0x4e, 0x5e, 0x81, 0x45, 0x45, 0xf0,
0x5f, 0x4d, 0x1f, 0xf7, 0xb6, 0xb0, 0xdf, 0xf6, 0x1d, 0xc6, 0x03, 0x47, 0xd3, 0x63, 0xd8, 0xaa,
0xe3, 0x2d, 0xc7, 0xc6, 0x16, 0x41, 0x4d, 0x4c, 0x79, 0x38, 0x8d, 0x0b, 0x21, 0xa3, 0x92, 0x5d,
0x2f, 0x8d, 0xdc, 0x4b, 0x1a, 0x41, 0xd1, 0x66, 0x0e, 0x6f, 0xdd, 0xe5, 0xea, 0x9d, 0xd0, 0xbc,
0xe4, 0x95, 0x20, 0xc7, 0xc6, 0x02, 0xbd, 0x47, 0x66, 0x23, 0x53, 0xdd, 0xd0, 0x7c, 0x49, 0x10,
0x7c, 0x08, 0xdd, 0xde, 0x8b, 0x92, 0x57, 0x71, 0x3d, 0x78, 0xc0, 0x87, 0x61, 0x01, 0xbe, 0xa6,
0x9f, 0xe3, 0x61, 0xcc, 0x72, 0x48, 0x1d, 0x6f, 0x5b, 0x7c, 0x25, 0xd7, 0x5c, 0xcf, 0xde, 0xa4,
0xc6, 0x25, 0xb1, 0xa5, 0xf9, 0xa2, 0x01, 0x5c, 0x61, 0x81, 0xe3, 0x4b, 0x0e, 0x99, 0x11, 0x68,
0x7a, 0x6b, 0x5b, 0x86, 0x94, 0x99, 0x72, 0x94, 0xff, 0x42, 0x85, 0x25, 0xf0, 0x4f, 0x9e, 0xee,
0x12, 0x64, 0x6f, 0xe2, 0xba, 0x45, 0x3c, 0xe6, 0x34, 0x1c, 0x1b, 0x45, 0xf7, 0x0f, 0x75, 0x6a,
0x54, 0xc5, 0xfc, 0xbe, 0xcb, 0x87, 0x7b, 0x78, 0x2d, 0x52, 0xba, 0x2b, 0xe9, 0x2c, 0xcc, 0xf1,
0xd1, 0x1e, 0x0e, 0x94, 0x48, 0x37, 0x34, 0x2f, 0x44, 0xa1, 0x5d, 0x05, 0x8b, 0xbb, 0x4a, 0x25,
0xd2, 0xdd, 0xab, 0xf6, 0xb0, 0xb8, 0xbb, 0x5f, 0xed, 0xc1, 0x02, 0x2a, 0x5b, 0xd4, 0x29, 0x80,
0xfa, 0x69, 0xe6, 0xa3, 0x46, 0xc3, 0xb1, 0x2d, 0xdb, 0x45, 0x94, 0x1a, 0x97, 0xc5, 0xb0, 0xbe,
0xc0, 0xeb, 0xe5, 0x18, 0x98, 0xe5, 0xf2, 0x6e, 0x68, 0x82, 0x68, 0x40, 0x25, 0x61, 0x7a, 0x51,
0x93, 0x53, 0x05, 0x6f, 0xe9, 0x83, 0xf1, 0x10, 0x5b, 0x0d, 0xcf, 0xad, 0x63, 0xdf, 0x6a, 0x21,
0xb6, 0x61, 0x3c, 0x25, 0x76, 0xfd, 0x9d, 0x83, 0xd0, 0xbc, 0x30, 0x87, 0x5b, 0x3e, 0xb6, 0x11,
0xc3, 0xf5, 0xb9, 0x48, 0x71, 0x5e, 0xe8, 0x2d, 0x23, 0xb6, 0xd1, 0x09, 0x4d, 0xed, 0x85, 0xb4,
0x3a, 0xaf, 0x17, 0xe1, 0xe7, 0xbd, 0xa6, 0xc3, 0x27, 0x89, 0xed, 0x54, 0x0c, 0x0d, 0x0e, 0x94,
0x70, 0xb0, 0xa9, 0x9f, 0xa5, 0x98, 0x59, 0xae, 0xd7, 0xb6, 0x5a, 0xbe, 0xe3, 0xf9, 0x0e, 0xdb,
0x31, 0x9e, 0x16, 0x9b, 0x62, 0xba, 0x13, 0x9a, 0xfd, 0x14, 0xb3, 0x45, 0xaf, 0xbd, 0x1c, 0x23,
0x69, 0x64, 0xcb, 0x8b, 0x7b, 0xa6, 0x18, 0x85, 0xe6, 0xe0, 0x3d, 0x4d, 0x1f, 0x6e, 0xa2, 0xed,
0xc4, 0x4d, 0xdb, 0x23, 0x76, 0xe0, 0xfb, 0x98, 0xd8, 0x3b, 0xc6, 0xb8, 0x18, 0x47, 0x2a, 0x2e,
0x5b, 0x50, 0x7b, 0x09, 0x6d, 0x47, 0x1c, 0x67, 0x33, 0x15, 0x7e, 0xe4, 0x37, 0x15, 0xf2, 0xf4,
0xc8, 0x57, 0x81, 0xc9, 0x90, 0x8b, 0xdb, 0x11, 0xb5, 0x5d, 0xa8, 0xb4, 0x0a, 0x3e, 0xd6, 0xf4,
0x41, 0xdb, 0x47, 0x74, 0xa3, 0x50, 0x03, 0x3c, 0x23, 0xa6, 0xe5, 0x7d, 0x51, 0x03, 0xcc, 0x26,
0x35, 0x80, 0x1d, 0xd7, 0x00, 0xf3, 0xd1, 0xd9, 0xcc, 0x9b, 0x65, 0xd9, 0xb8, 0x32, 0x0c, 0x0b,
0x9d, 0x72, 0x5e, 0x2f, 0xc4, 0x7c, 0x2d, 0x0f, 0x94, 0x8c, 0xf0, 0xea, 0xc0, 0x8e, 0xab, 0x83,
0xea, 0xc3, 0x98, 0xe1, 0xf5, 0xc1, 0x6c, 0x54, 0x1f, 0x14, 0x8c, 0xf9, 0x2e, 0xf8, 0x99, 0xa6,
0x8f, 0x14, 0xdd, 0x4b, 0xae, 0x65, 0x9e, 0x15, 0xf3, 0xef, 0x1c, 0x84, 0xe6, 0xc9, 0x59, 0x28,
0xbd, 0x28, 0xe4, 0xad, 0x14, 0x5f, 0x14, 0x94, 0x68, 0xaf, 0xa5, 0xb1, 0xbb, 0x5f, 0xcd, 0x6c,
0x43, 0xb5, 0x65, 0xf0, 0x0d, 0x4d, 0x1f, 0xa6, 0x2c, 0x20, 0x16, 0xcf, 0x9c, 0x90, 0xeb, 0x6c,
0x61, 0x2b, 0xca, 0x87, 0xa9, 0xf1, 0x5c, 0x9a, 0x8f, 0x0e, 0x72, 0x8d, 0x3b, 0x89, 0xc2, 0x0a,
0xc7, 0x57, 0xd2, 0x2c, 0x49, 0x81, 0xe5, 0x93, 0x79, 0x29, 0xa0, 0x1d, 0x9b, 0xbc, 0x39, 0x01,
0x55, 0xd6, 0x78, 0x8d, 0x5c, 0xa0, 0xc1, 0xe3, 0x2a, 0x35, 0x9e, 0x17, 0x24, 0x5e, 0xe5, 0x89,
0x5a, 0xae, 0xd9, 0x92, 0x43, 0xb2, 0x5a, 0xa2, 0x84, 0xc8, 0x39, 0x62, 0x2e, 0xa0, 0x4e, 0x4d,
0xc0, 0xb2, 0x1d, 0x9e, 0x95, 0xf7, 0x89, 0xde, 0x93, 0x87, 0xae, 0x17, 0x44, 0x0c, 0xad, 0x1f,
0x84, 0x66, 0x3f, 0x44, 0xed, 0x15, 0x16, 0x48, 0x4f, 0x5c, 0xa7, 0x68, 0xf6, 0x99, 0x5e, 0x46,
0x65, 0xb2, 0x07, 0x3e, 0xc3, 0x15, 0x2c, 0x42, 0xd9, 0x1e, 0xd8, 0xd2, 0xcf, 0xf0, 0xb2, 0xb3,
0x86, 0x28, 0xb6, 0xa2, 0x37, 0x47, 0xe3, 0xca, 0x98, 0x36, 0xde, 0x3f, 0xd5, 0x9f, 0xa4, 0x45,
0xab, 0x42, 0x2a, 0x6e, 0x0f, 0xfb, 0x13, 0xd5, 0x48, 0x96, 0x46, 0x8e, 0xbc, 0xb8, 0x32, 0x16,
0x17, 0x21, 0xf1, 0xf2, 0x78, 0x7b, 0xbf, 0xaa, 0xc1, 0x42, 0x53, 0xf0, 0xfd, 0xa3, 0xfa, 0x25,
0x1e, 0x35, 0xd2, 0x70, 0xc1, 0x8b, 0x58, 0xdb, 0x6b, 0xf2, 0x25, 0xeb, 0xe3, 0x37, 0x02, 0x4c,
0x99, 0xb5, 0xe9, 0xd4, 0x8c, 0xab, 0x62, 0x3a, 0xfe, 0xa6, 0xc5, 0x6f, 0x95, 0x4b, 0x68, 0x7b,
0x76, 0x01, 0x46, 0xf8, 0x1d, 0x67, 0xa6, 0x13, 0x9a, 0x66, 0x13, 0x6d, 0xa7, 0x5b, 0x9c, 0x2d,
0xc4, 0x36, 0x32, 0x95, 0xf4, 0x14, 0x7c, 0x80, 0x9e, 0x54, 0x00, 0x3e, 0xd0, 0xe4, 0x83, 0x55,
0xe2, 0xd7, 0xcf, 0x02, 0x5d, 0xf8, 0x80, 0x66, 0x35, 0xf0, 0xa9, 0xa6, 0x0f, 0xa7, 0x4f, 0x30,
0x2e, 0x92, 0x1f, 0x6d, 0x27, 0xc4, 0x06, 0xfe, 0x80, 0x8f, 0xc4, 0x50, 0xf2, 0x84, 0xb1, 0x38,
0x7d, 0x57, 0x7e, 0xb7, 0x1d, 0x42, 0x0a, 0x79, 0x9a, 0x48, 0xab, 0x40, 0xd5, 0xcb, 0x99, 0xd2,
0x48, 0x0f, 0xb9, 0xb4, 0xf5, 0x95, 0xa4, 0x60, 0xd6, 0x0a, 0x49, 0x8f, 0xbe, 0x5b, 0xfa, 0x79,
0xf1, 0xca, 0xd2, 0x08, 0x5c, 0x37, 0xce, 0x6a, 0x3c, 0x92, 0x94, 0xa8, 0xc6, 0xa4, 0xf0, 0xf4,
0x16, 0xcf, 0x1a, 0xb8, 0xd6, 0x7c, 0xe0, 0xba, 0x22, 0x1f, 0xb9, 0x47, 0xe2, 0xa2, 0xb2, 0x1b,
0x9a, 0x17, 0xe3, 0x23, 0x4b, 0x05, 0x57, 0x60, 0x8f, 0x76, 0xe0, 0x55, 0xfd, 0x74, 0x03, 0x23,
0x16, 0xf8, 0xd8, 0x6a, 0xb8, 0x68, 0x9d, 0x1a, 0x53, 0x62, 0xdf, 0x5d, 0xe6, 0x27, 0x7d, 0x0c,
0xcc, 0x73, 0x79, 0xfa, 0x22, 0x23, 0x09, 0x2b, 0x30, 0xa7, 0x02, 0xda, 0xfa, 0x88, 0xf4, 0x10,
0x13, 0xd5, 0x38, 0x98, 0x78, 0xc1, 0xfa, 0x86, 0x71, 0x4d, 0x2c, 0xda, 0x97, 0x45, 0x78, 0x4d,
0x55, 0x16, 0xb9, 0xc6, 0x2b, 0x42, 0x21, 0xcd, 0x7a, 0x94, 0x68, 0x9a, 0x51, 0xa8, 0x1b, 0x83,
0x4d, 0x7d, 0xa8, 0xd4, 0x71, 0x13, 0x6d, 0x1b, 0xd7, 0x45, 0xaf, 0x2f, 0xf1, 0x64, 0xb0, 0xd0,
0x70, 0x09, 0x6d, 0x77, 0x43, 0xd3, 0x50, 0x75, 0xb9, 0x84, 0xb6, 0xd3, 0xfe, 0x14, 0xcd, 0xc0,
0x57, 0xf4, 0xbe, 0xa0, 0x45, 0x5a, 0xe9, 0x31, 0xf2, 0xab, 0x79, 0x31, 0x39, 0x5f, 0x38, 0x08,
0xcd, 0x73, 0x59, 0x06, 0xb3, 0xb6, 0x4c, 0x96, 0xb3, 0x33, 0x45, 0xe4, 0x2e, 0x71, 0x5a, 0xd7,
0x22, 0xad, 0x18, 0x90, 0xb2, 0x96, 0xdd, 0xfd, 0xaa, 0xba, 0xb1, 0xa1, 0xc1, 0x53, 0x52, 0x13,
0xf0, 0x0b, 0x2d, 0xee, 0x3e, 0xb9, 0xb4, 0x7f, 0x6f, 0x5e, 0x38, 0xf9, 0xb6, 0xd8, 0x05, 0x79,
0x13, 0xe9, 0x05, 0xbe, 0xe8, 0x7e, 0x2c, 0xed, 0x5e, 0xbe, 0x78, 0x97, 0x38, 0x64, 0xdb, 0xfd,
0x7c, 0x6f, 0x2d, 0xbe, 0xac, 0x55, 0xbd, 0x18, 0x1a, 0xd4, 0xb3, 0x56, 0xe0, 0x77, 0x9a, 0xde,
0x2f, 0x68, 0x66, 0xd7, 0xf3, 0xbf, 0x8e, 0x88, 0x7e, 0x5b, 0x64, 0xc5, 0x79, 0x13, 0xd2, 0x55,
0xbd, 0xa0, 0x5a, 0x49, 0xa9, 0xe6, 0x2f, 0xd7, 0x95, 0x64, 0x2f, 0x7e, 0x96, 0x1e, 0xcf, 0x7d,
0xd5, 0x7d, 0x19, 0x1a, 0xec, 0x93, 0x5b, 0x66, 0x94, 0xb3, 0x4b, 0xf8, 0xf7, 0x7b, 0x53, 0x96,
0x2e, 0xe4, 0x0b, 0x94, 0xf3, 0x57, 0xe8, 0xbd, 0x29, 0xf7, 0xd2, 0x2b, 0x53, 0x4e, 0x34, 0x13,
0xca, 0xe9, 0x9d, 0x7b, 0x43, 0x8f, 0x1e, 0xfb, 0xd2, 0x43, 0xf3, 0x37, 0xf3, 0x62, 0xf7, 0x7e,
0x2e, 0xcf, 0x57, 0xbc, 0x97, 0x65, 0xa7, 0xa7, 0xb4, 0x18, 0xfd, 0x0c, 0xc9, 0xa7, 0xd0, 0x7d,
0x12, 0x42, 0xc5, 0x95, 0x45, 0xf9, 0xb6, 0xc0, 0x6a, 0xd9, 0xcc, 0xf8, 0x80, 0x0f, 0x91, 0x36,
0xb3, 0x74, 0x10, 0x9a, 0x17, 0xb3, 0x1e, 0x97, 0xf2, 0xb5, 0xfe, 0xb2, 0xcd, 0xf2, 0xe3, 0xd4,
0x2c, 0xe1, 0xf9, 0xee, 0x41, 0x59, 0x81, 0x67, 0x08, 0x43, 0x85, 0xf3, 0x91, 0xda, 0x88, 0x50,
0xe3, 0xb7, 0xd1, 0x2c, 0xad, 0x16, 0x28, 0xc8, 0xe7, 0xca, 0x0a, 0x57, 0x2c, 0x50, 0x28, 0xe1,
0xe5, 0xa9, 0x12, 0x4c, 0x4a, 0x7a, 0x33, 0x77, 0x3e, 0xfc, 0x64, 0xf4, 0xc8, 0xfe, 0x27, 0xa3,
0x47, 0x3e, 0x3c, 0x18, 0xd5, 0xf6, 0x0f, 0x46, 0xb5, 0xef, 0xde, 0x1f, 0x3d, 0xf2, 0xee, 0xfd,
0x51, 0x6d, 0xff, 0xfe, 0xe8, 0x91, 0x8f, 0xee, 0x8f, 0x1e, 0x79, 0xfd, 0x99, 0x75, 0x87, 0x6d,
0x04, 0xb5, 0x2b, 0xb6, 0xd7, 0xbc, 0x9a, 0x66, 0xad, 0xd2, 0xaf, 0xec, 0xdf, 0x4b, 0xb5, 0x13,
0xe2, 0xef, 0x4a, 0xd7, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, 0x2c, 0x30, 0xd1, 0x0d, 0x1a, 0x25,
0x00, 0x00,
}
func (m *OptionsConfiguration) Marshal() (dAtA []byte, err error) {
@ -558,10 +559,10 @@ func (m *OptionsConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0xb8
}
if len(m.DefaultFolderPath) > 0 {
i -= len(m.DefaultFolderPath)
copy(dAtA[i:], m.DefaultFolderPath)
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(len(m.DefaultFolderPath)))
if len(m.DeprecatedDefaultFolderPath) > 0 {
i -= len(m.DeprecatedDefaultFolderPath)
copy(dAtA[i:], m.DeprecatedDefaultFolderPath)
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(len(m.DeprecatedDefaultFolderPath)))
i--
dAtA[i] = 0x2
i--
@ -1018,7 +1019,7 @@ func (m *OptionsConfiguration) ProtoSize() (n int) {
if m.TrafficClass != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.TrafficClass))
}
l = len(m.DefaultFolderPath)
l = len(m.DeprecatedDefaultFolderPath)
if l > 0 {
n += 2 + l + sovOptionsconfiguration(uint64(l))
}
@ -1948,7 +1949,7 @@ func (m *OptionsConfiguration) Unmarshal(dAtA []byte) error {
}
case 38:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field DefaultFolderPath", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedDefaultFolderPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
@ -1976,7 +1977,7 @@ func (m *OptionsConfiguration) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.DefaultFolderPath = string(dAtA[iNdEx:postIndex])
m.DeprecatedDefaultFolderPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 39:
if wireType != 0 {

View File

@ -1,4 +1,4 @@
<configuration version="31">
<configuration version="34">
<options>
<listenAddress>tcp://:23000</listenAddress>
<allowDelete>false</allowDelete>
@ -36,7 +36,6 @@
<releasesURL>https://localhost/releases</releasesURL>
<overwriteRemoteDeviceNamesOnConnect>true</overwriteRemoteDeviceNamesOnConnect>
<tempIndexMinBlocks>100</tempIndexMinBlocks>
<defaultFolderPath>/media/syncthing</defaultFolderPath>
<setLowPriority>false</setLowPriority>
<crashReportingURL>https://localhost/newcrash</crashReportingURL>
<crashReportingEnabled>false</crashReportingEnabled>
@ -47,4 +46,45 @@
<announceLANAddresses>false</announceLANAddresses>
<featureFlag>feature</featureFlag>
</options>
<defaults>
<folder id="" label="" path="/media/syncthing" type="sendreceive" rescanIntervalS="3600" fsWatcherEnabled="true" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true">
<filesystemType>basic</filesystemType>
<minDiskFree unit="%">1</minDiskFree>
<versioning type="trashcan">
<param key="cleanoutDays" val="0"></param>
<cleanupIntervalS>3600</cleanupIntervalS>
</versioning>
<copiers>0</copiers>
<pullerMaxPendingKiB>0</pullerMaxPendingKiB>
<hashers>0</hashers>
<order>random</order>
<ignoreDelete>false</ignoreDelete>
<scanProgressIntervalS>0</scanProgressIntervalS>
<pullerPauseS>0</pullerPauseS>
<maxConflicts>10</maxConflicts>
<disableSparseFiles>false</disableSparseFiles>
<disableTempIndexes>false</disableTempIndexes>
<paused>false</paused>
<weakHashThresholdPct>25</weakHashThresholdPct>
<markerName>.stfolder</markerName>
<copyOwnershipFromParent>false</copyOwnershipFromParent>
<modTimeWindowS>0</modTimeWindowS>
<maxConcurrentWrites>2</maxConcurrentWrites>
<disableFsync>false</disableFsync>
<blockPullOrder>standard</blockPullOrder>
<copyRangeMethod>standard</copyRangeMethod>
<caseSensitiveFS>false</caseSensitiveFS>
<junctionsAsDirs>false</junctionsAsDirs>
</folder>
<device id="" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
<address>dynamic</address>
<paused>false</paused>
<autoAcceptFolders>false</autoAcceptFolders>
<maxSendKbps>0</maxSendKbps>
<maxRecvKbps>0</maxRecvKbps>
<maxRequestKiB>0</maxRequestKiB>
<untrusted>false</untrusted>
<remoteGUIPort>0</remoteGUIPort>
</device>
</defaults>
</configuration>

View File

@ -52,7 +52,7 @@ func (c *VersioningConfiguration) UnmarshalXML(d *xml.Decoder, start xml.StartEl
return nil
}
func (c *VersioningConfiguration) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
func (c VersioningConfiguration) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
// Using EncodeElement instead of plain Encode ensures that we use the
// outer tag name from the VersioningConfiguration (i.e.,
// `<versioning>`) rather than whatever the internal representation

View File

@ -96,10 +96,12 @@ type Wrapper interface {
Folders() map[string]FolderConfiguration
FolderList() []FolderConfiguration
FolderPasswords(device protocol.DeviceID) map[string]string
DefaultFolder() FolderConfiguration
Device(id protocol.DeviceID) (DeviceConfiguration, bool)
Devices() map[protocol.DeviceID]DeviceConfiguration
DeviceList() []DeviceConfiguration
DefaultDevice() DeviceConfiguration
IgnoredDevices() []ObservedDevice
IgnoredDevice(id protocol.DeviceID) bool
@ -353,6 +355,12 @@ func (w *wrapper) RemoveDevice(id protocol.DeviceID) (Waiter, error) {
})
}
func (w *wrapper) DefaultDevice() DeviceConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Defaults.Device.Copy()
}
// Folders returns a map of folders.
func (w *wrapper) Folders() map[string]FolderConfiguration {
w.mut.Lock()
@ -388,6 +396,12 @@ func (w *wrapper) FolderPasswords(device protocol.DeviceID) map[string]string {
return w.cfg.FolderPasswords(device)
}
func (w *wrapper) DefaultFolder() FolderConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Defaults.Folder.Copy()
}
// Options returns the current options configuration object.
func (w *wrapper) Options() OptionsConfiguration {
w.mut.Lock()

View File

@ -31,12 +31,19 @@ func init() {
device4, _ = protocol.DeviceIDFromString("P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2")
}
func newDeviceConfiguration(w config.Wrapper, id protocol.DeviceID, name string) config.DeviceConfiguration {
cfg := w.DefaultDevice()
cfg.DeviceID = id
cfg.Name = name
return cfg
}
func initConfig() (config.Wrapper, context.CancelFunc) {
wrapper := config.Wrap("/dev/null", config.New(device1), device1, events.NoopLogger)
dev1Conf = config.NewDeviceConfiguration(device1, "device1")
dev2Conf = config.NewDeviceConfiguration(device2, "device2")
dev3Conf = config.NewDeviceConfiguration(device3, "device3")
dev4Conf = config.NewDeviceConfiguration(device4, "device4")
dev1Conf = newDeviceConfiguration(wrapper, device1, "device1")
dev2Conf = newDeviceConfiguration(wrapper, device2, "device2")
dev3Conf = newDeviceConfiguration(wrapper, device3, "device3")
dev4Conf = newDeviceConfiguration(wrapper, device4, "device4")
var cancel context.CancelFunc = func() {}
if wrapperService, ok := wrapper.(suture.Service); ok {
@ -149,7 +156,7 @@ func TestAddDevice(t *testing.T) {
lim := newLimiter(device1, wrapper)
addedDevice, _ := protocol.DeviceIDFromString("XZJ4UNS-ENI7QGJ-J45DT6G-QSGML2K-6I4XVOG-NAZ7BF5-2VAOWNT-TFDOMQU")
addDevConf := config.NewDeviceConfiguration(addedDevice, "addedDevice")
addDevConf := newDeviceConfiguration(wrapper, addedDevice, "addedDevice")
addDevConf.MaxRecvKbps = 120
addDevConf.MaxSendKbps = 240
@ -183,7 +190,7 @@ func TestAddAndRemove(t *testing.T) {
lim := newLimiter(device1, wrapper)
addedDevice, _ := protocol.DeviceIDFromString("XZJ4UNS-ENI7QGJ-J45DT6G-QSGML2K-6I4XVOG-NAZ7BF5-2VAOWNT-TFDOMQU")
addDevConf := config.NewDeviceConfiguration(addedDevice, "addedDevice")
addDevConf := newDeviceConfiguration(wrapper, addedDevice, "addedDevice")
addDevConf.MaxRecvKbps = 120
addDevConf.MaxSendKbps = 240

View File

@ -8,10 +8,10 @@ import (
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
_ "github.com/golang/protobuf/ptypes/timestamp"
github_com_syncthing_syncthing_lib_protocol "github.com/syncthing/syncthing/lib/protocol"
protocol "github.com/syncthing/syncthing/lib/protocol"
_ "github.com/syncthing/syncthing/proto/ext"
_ "google.golang.org/protobuf/types/known/timestamppb"
io "io"
math "math"
math_bits "math/bits"

View File

@ -21,7 +21,6 @@ import (
"testing"
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/ignore"
@ -806,7 +805,7 @@ func TestCopyOwner(t *testing.T) {
m, f, wcfgCancel := setupSendReceiveFolder(t)
defer cleanupSRFolder(f, m, wcfgCancel)
f.folder.FolderConfiguration = config.NewFolderConfiguration(m.id, f.ID, f.Label, fs.FilesystemTypeFake, "/TestCopyOwner")
f.folder.FolderConfiguration = newFolderConfiguration(m.cfg, f.ID, f.Label, fs.FilesystemTypeFake, "/TestCopyOwner")
f.folder.FolderConfiguration.CopyOwnershipFromParent = true
f.fset = newFileSet(t, f.ID, f.Filesystem(), m.db)

View File

@ -1218,7 +1218,7 @@ func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
haveFcfg := cfg.FolderMap()
for _, folder := range cm.Folders {
from, ok := haveFcfg[folder.ID]
if to, changed := m.handleAutoAccepts(deviceID, folder, ccDeviceInfos[folder.ID], from, ok, cfg.Options.DefaultFolderPath); changed {
if to, changed := m.handleAutoAccepts(deviceID, folder, ccDeviceInfos[folder.ID], from, ok, cfg.Defaults.Folder.Path); changed {
changedFcfg[folder.ID] = to
}
}
@ -1638,7 +1638,7 @@ func (m *model) handleAutoAccepts(deviceID protocol.DeviceID, folder protocol.Fo
continue
}
fcfg := config.NewFolderConfiguration(m.id, folder.ID, folder.Label, fs.FilesystemTypeBasic, filepath.Join(defaultPath, path))
fcfg := newFolderConfiguration(m.cfg, folder.ID, folder.Label, fs.FilesystemTypeBasic, filepath.Join(defaultPath, path))
fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{
DeviceID: deviceID,
})
@ -1678,6 +1678,15 @@ func (m *model) handleAutoAccepts(deviceID protocol.DeviceID, folder protocol.Fo
}
}
func (m *model) newFolderConfiguration(id, label string, fsType fs.FilesystemType, path string) config.FolderConfiguration {
fcfg := m.cfg.DefaultFolder()
fcfg.ID = id
fcfg.Label = label
fcfg.FilesystemType = fsType
fcfg.Path = path
return fcfg
}
func (m *model) introduceDevice(device protocol.Device, introducerCfg config.DeviceConfiguration) config.DeviceConfiguration {
addresses := []string{"dynamic"}
for _, addr := range device.Addresses {
@ -1687,14 +1696,13 @@ func (m *model) introduceDevice(device protocol.Device, introducerCfg config.Dev
}
l.Infof("Adding device %v to config (vouched for by introducer %v)", device.ID, introducerCfg.DeviceID)
newDeviceCfg := config.DeviceConfiguration{
DeviceID: device.ID,
Name: device.Name,
Compression: introducerCfg.Compression,
Addresses: addresses,
CertName: device.CertName,
IntroducedBy: introducerCfg.DeviceID,
}
newDeviceCfg := m.cfg.DefaultDevice()
newDeviceCfg.DeviceID = device.ID
newDeviceCfg.Name = device.Name
newDeviceCfg.Compression = introducerCfg.Compression
newDeviceCfg.Addresses = addresses
newDeviceCfg.CertName = device.CertName
newDeviceCfg.IntroducedBy = introducerCfg.DeviceID
// The introducers' introducers are also our introducers.
if device.Introducer {
@ -3156,3 +3164,12 @@ func writeEncryptionToken(token []byte, cfg config.FolderConfiguration) error {
Token: token,
})
}
func newFolderConfiguration(w config.Wrapper, id, label string, fsType fs.FilesystemType, path string) config.FolderConfiguration {
fcfg := w.DefaultFolder()
fcfg.ID = id
fcfg.Label = label
fcfg.FilesystemType = fsType
fcfg.Path = path
return fcfg
}

View File

@ -1006,7 +1006,7 @@ func TestAutoAcceptNewFolderPremutationsNoPanic(t *testing.T) {
for _, dev2folder := range premutations {
cfg := defaultAutoAcceptCfg.Copy()
if localFolder.Label != "" {
fcfg := config.NewFolderConfiguration(myID, localFolder.ID, localFolder.Label, fs.FilesystemTypeBasic, localFolder.ID)
fcfg := newFolderConfiguration(defaultCfgWrapper, localFolder.ID, localFolder.Label, fs.FilesystemTypeBasic, localFolder.ID)
fcfg.Paused = localFolderPaused
cfg.Folders = append(cfg.Folders, fcfg)
}
@ -1211,7 +1211,7 @@ func TestAutoAcceptPausedWhenFolderConfigChanged(t *testing.T) {
defer os.RemoveAll(idOther)
tcfg := defaultAutoAcceptCfg.Copy()
fcfg := config.NewFolderConfiguration(myID, id, "", fs.FilesystemTypeBasic, idOther)
fcfg := newFolderConfiguration(defaultCfgWrapper, id, "", fs.FilesystemTypeBasic, idOther)
fcfg.Paused = true
// The order of devices here is wrong (cfg.clean() sorts them), which will cause the folder to restart.
// Because of the restart, folder gets removed from m.deviceFolder, which means that generateClusterConfig will not panic.
@ -1259,7 +1259,7 @@ func TestAutoAcceptPausedWhenFolderConfigNotChanged(t *testing.T) {
defer os.RemoveAll(idOther)
tcfg := defaultAutoAcceptCfg.Copy()
fcfg := config.NewFolderConfiguration(myID, id, "", fs.FilesystemTypeBasic, idOther)
fcfg := newFolderConfiguration(defaultCfgWrapper, id, "", fs.FilesystemTypeBasic, idOther)
fcfg.Paused = true
// The new folder is exactly the same as the one constructed by handleAutoAccept, which means
// the folder will not be restarted (even if it's paused), yet handleAutoAccept used to add the folder
@ -2749,7 +2749,7 @@ func TestVersionRestore(t *testing.T) {
must(t, err)
defer os.RemoveAll(dir)
fcfg := config.NewFolderConfiguration(myID, "default", "default", fs.FilesystemTypeBasic, dir)
fcfg := newFolderConfiguration(defaultCfgWrapper, "default", "default", fs.FilesystemTypeBasic, dir)
fcfg.Versioning.Type = "simple"
fcfg.FSWatcherEnabled = false
filesystem := fcfg.Filesystem()
@ -3810,7 +3810,7 @@ func testConfigChangeTriggersClusterConfigs(t *testing.T, expectFirst, expectSec
m := setupModel(t, wcfg)
defer cleanupModel(m)
setDevice(t, wcfg, config.NewDeviceConfiguration(device2, "device2"))
setDevice(t, wcfg, newDeviceConfiguration(wcfg.DefaultDevice(), device2, "device2"))
if pre != nil {
pre(wcfg)
@ -3877,7 +3877,7 @@ func TestIssue6961(t *testing.T) {
defer wcfgCancel()
tfs := fcfg.Filesystem()
waiter, err := wcfg.Modify(func(cfg *config.Configuration) {
cfg.SetDevice(config.NewDeviceConfiguration(device2, "device2"))
cfg.SetDevice(newDeviceConfiguration(cfg.Defaults.Device, device2, "device2"))
fcfg.Type = config.FolderTypeReceiveOnly
fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{DeviceID: device2})
cfg.SetFolder(fcfg)

View File

@ -40,12 +40,13 @@ func init() {
device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
defaultCfgWrapper, defaultCfgWrapperCancel = createTmpWrapper(config.New(myID))
defaultFolderConfig = testFolderConfig("testdata")
defaultFs = defaultFolderConfig.Filesystem()
defaultCfgWrapper, defaultCfgWrapperCancel = createTmpWrapper(config.New(myID))
waiter, _ := defaultCfgWrapper.Modify(func(cfg *config.Configuration) {
cfg.SetDevice(config.NewDeviceConfiguration(device1, "device1"))
cfg.SetDevice(newDeviceConfiguration(cfg.Defaults.Device, device1, "device1"))
cfg.SetFolder(defaultFolderConfig)
cfg.Options.KeepTemporariesH = 1
})
@ -68,8 +69,10 @@ func init() {
AutoAcceptFolders: true,
},
},
Options: config.OptionsConfiguration{
DefaultFolderPath: ".",
Defaults: config.Defaults{
Folder: config.FolderConfiguration{
Path: ".",
},
},
}
}
@ -104,14 +107,14 @@ func testFolderConfigTmp() config.FolderConfiguration {
}
func testFolderConfig(path string) config.FolderConfiguration {
cfg := config.NewFolderConfiguration(myID, "default", "default", fs.FilesystemTypeBasic, path)
cfg := newFolderConfiguration(defaultCfgWrapper, "default", "default", fs.FilesystemTypeBasic, path)
cfg.FSWatcherEnabled = false
cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{DeviceID: device1})
return cfg
}
func testFolderConfigFake() config.FolderConfiguration {
cfg := config.NewFolderConfiguration(myID, "default", "default", fs.FilesystemTypeFake, rand.String(32)+"?content=true")
cfg := newFolderConfiguration(defaultCfgWrapper, "default", "default", fs.FilesystemTypeFake, rand.String(32)+"?content=true")
cfg.FSWatcherEnabled = false
cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{DeviceID: device1})
return cfg
@ -326,6 +329,13 @@ func localIndexUpdate(m *testModel, folder string, fs []protocol.FileInfo) {
})
}
func newDeviceConfiguration(defaultCfg config.DeviceConfiguration, id protocol.DeviceID, name string) config.DeviceConfiguration {
cfg := defaultCfg.Copy()
cfg.DeviceID = id
cfg.Name = name
return cfg
}
func newFileSet(t testing.TB, folder string, fs fs.Filesystem, ldb *db.Lowlevel) *db.FileSet {
t.Helper()
fset, err := db.NewFileSet(folder, fs, ldb)
@ -394,7 +404,7 @@ func setDevice(t testing.TB, w config.Wrapper, device config.DeviceConfiguration
func addDevice2(t testing.TB, w config.Wrapper, fcfg config.FolderConfiguration) {
waiter, err := w.Modify(func(cfg *config.Configuration) {
cfg.SetDevice(config.NewDeviceConfiguration(device2, "device2"))
cfg.SetDevice(newDeviceConfiguration(cfg.Defaults.Device, device2, "device2"))
fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{DeviceID: device2})
cfg.SetFolder(fcfg)
})

View File

@ -52,7 +52,12 @@ func DefaultConfig(path string, myID protocol.DeviceID, evLogger events.Logger,
return config.Wrap(path, newCfg, myID, evLogger), nil
}
newCfg.Folders = append(newCfg.Folders, config.NewFolderConfiguration(myID, "default", "Default Folder", fs.FilesystemTypeBasic, locations.Get(locations.DefFolder)))
fcfg := newCfg.Defaults.Folder.Copy()
fcfg.ID = "default"
fcfg.Label = "Default Folder"
fcfg.FilesystemType = fs.FilesystemTypeBasic
fcfg.Path = locations.Get(locations.DefFolder)
newCfg.Folders = append(newCfg.Folders, fcfg)
l.Infoln("Default folder created and/or linked to new config")
return config.Wrap(path, newCfg, myID, evLogger), nil
}

View File

@ -71,6 +71,7 @@ func (s *Service) ReportDataPreview(ctx context.Context, urVersion int) (*contra
func (s *Service) reportData(ctx context.Context, urVersion int, preview bool) (*contract.Report, error) {
opts := s.cfg.Options()
defaultFolder := s.cfg.DefaultFolder()
var totFiles, maxFiles int
var totBytes, maxBytes int64
@ -212,7 +213,7 @@ func (s *Service) reportData(ctx context.Context, urVersion int, preview bool) (
report.CacheIgnoredFiles = opts.CacheIgnoredFiles
report.OverwriteRemoteDeviceNames = opts.OverwriteRemoteDevNames
report.ProgressEmitterEnabled = opts.ProgressUpdateIntervalS > -1
report.CustomDefaultFolderPath = opts.DefaultFolderPath != "~"
report.CustomDefaultFolderPath = defaultFolder.Path != "~"
report.CustomTrafficClass = opts.TrafficClass != 0
report.CustomTempIndexMinBlocks = opts.TempIndexMinBlocks != 10
report.TemporariesDisabled = opts.KeepTemporariesH == 0

View File

@ -18,6 +18,7 @@ extend google.protobuf.FieldOptions {
optional bool device_id = 75009;
optional string goname = 75010;
optional string gotype = 75011;
optional bool nodefault = 75012;
}
extend google.protobuf.EnumValueOptions {

View File

@ -93,6 +93,15 @@ var E_Gotype = &proto.ExtensionDesc{
Filename: "ext.proto",
}
var E_Nodefault = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 75012,
Name: "ext.nodefault",
Tag: "varint,75012,opt,name=nodefault",
Filename: "ext.proto",
}
var E_Enumgoname = &proto.ExtensionDesc{
ExtendedType: (*descriptor.EnumValueOptions)(nil),
ExtensionType: (*string)(nil),
@ -111,31 +120,33 @@ func init() {
proto.RegisterExtension(E_DeviceId)
proto.RegisterExtension(E_Goname)
proto.RegisterExtension(E_Gotype)
proto.RegisterExtension(E_Nodefault)
proto.RegisterExtension(E_Enumgoname)
}
func init() { proto.RegisterFile("ext.proto", fileDescriptor_95fe6908ffcf64d3) }
var fileDescriptor_95fe6908ffcf64d3 = []byte{
// 318 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0xd1, 0xcb, 0x4a, 0x33, 0x31,
0x14, 0xc0, 0x71, 0x86, 0x96, 0xaf, 0x6d, 0x96, 0x5d, 0x7d, 0x08, 0xd6, 0xba, 0xeb, 0x6a, 0x06,
0x11, 0x14, 0x43, 0x57, 0x8a, 0x82, 0x0b, 0x11, 0x8a, 0xb8, 0x70, 0x53, 0xd2, 0x99, 0xd3, 0x34,
0x92, 0xcb, 0x30, 0x39, 0x23, 0xd3, 0x9d, 0x97, 0x27, 0xf0, 0x95, 0x5c, 0x69, 0x57, 0xfa, 0x06,
0xd2, 0xa5, 0xef, 0xe0, 0x85, 0xe9, 0xa4, 0x5a, 0xe8, 0x22, 0xbb, 0x10, 0xfe, 0xbf, 0x93, 0x84,
0x90, 0x16, 0x14, 0x18, 0xa6, 0x99, 0x41, 0xd3, 0xae, 0x41, 0x81, 0x1b, 0x5d, 0x6e, 0x0c, 0x97,
0x10, 0x2d, 0xb6, 0x46, 0xf9, 0x38, 0x4a, 0xc0, 0xc6, 0x99, 0x48, 0xd1, 0x64, 0x55, 0x46, 0xfb,
0xa4, 0x59, 0x28, 0x39, 0x44, 0xc6, 0x6d, 0x7b, 0x2b, 0xac, 0xf2, 0x70, 0x99, 0x87, 0x67, 0x60,
0x2d, 0xe3, 0x70, 0x9e, 0xa2, 0x30, 0xda, 0xfe, 0x7f, 0x7c, 0xaa, 0x77, 0x83, 0x5e, 0x73, 0xd0,
0x28, 0x94, 0xbc, 0x60, 0xdc, 0xd2, 0x1d, 0x52, 0x2b, 0x94, 0x6c, 0x6f, 0xae, 0xc1, 0x13, 0x01,
0x32, 0x59, 0xb2, 0xcf, 0x97, 0x92, 0xb5, 0x06, 0x65, 0x4b, 0x77, 0x49, 0xfd, 0xda, 0x1a, 0xed,
0x33, 0x5f, 0xce, 0x2c, 0x62, 0x7a, 0x40, 0x1a, 0x09, 0x8c, 0x59, 0x2e, 0xd1, 0xe7, 0xbe, 0x9d,
0x5b, 0xf6, 0x25, 0xcd, 0xc0, 0x22, 0xcb, 0xbc, 0xf4, 0x76, 0xe6, 0x5e, 0xe7, 0x7a, 0xda, 0x27,
0xad, 0x04, 0x6e, 0x44, 0x0c, 0x43, 0x91, 0xf8, 0xf0, 0x9d, 0xc3, 0xcd, 0x4a, 0x9c, 0x26, 0x74,
0x9f, 0xfc, 0xe3, 0x46, 0x33, 0x05, 0x3e, 0x7a, 0x3f, 0xab, 0xae, 0xec, 0xf2, 0x0a, 0xe2, 0x34,
0xf5, 0xc2, 0x87, 0x3f, 0x58, 0xe6, 0xf4, 0x88, 0x10, 0xd0, 0xb9, 0x72, 0xa7, 0x6e, 0xaf, 0xe1,
0x63, 0x9d, 0xab, 0x4b, 0x26, 0xf3, 0xdf, 0xff, 0xfc, 0x78, 0xab, 0x06, 0xac, 0xb0, 0xc3, 0xbd,
0xe7, 0x79, 0x27, 0x78, 0x9d, 0x77, 0x82, 0xf7, 0x79, 0x27, 0xb8, 0xea, 0x71, 0x81, 0x93, 0x7c,
0x14, 0xc6, 0x46, 0x45, 0x76, 0xaa, 0x63, 0x9c, 0x08, 0xcd, 0x57, 0x56, 0x8b, 0xd9, 0x11, 0x14,
0xf8, 0x13, 0x00, 0x00, 0xff, 0xff, 0x5a, 0xa4, 0x49, 0x7c, 0x7b, 0x02, 0x00, 0x00,
// 332 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0xd2, 0x4d, 0x4b, 0xfb, 0x30,
0x1c, 0xc0, 0x71, 0xca, 0xc6, 0x7f, 0x6b, 0x8e, 0x3b, 0xfd, 0x11, 0x9c, 0xf3, 0xb6, 0x53, 0x8b,
0x08, 0x8a, 0x61, 0x5e, 0x14, 0x05, 0x0f, 0x22, 0x0c, 0xf1, 0xe0, 0x65, 0x64, 0xed, 0x6f, 0x59,
0x24, 0x0f, 0xa5, 0x49, 0xa5, 0xbb, 0xf9, 0xf4, 0x06, 0x7c, 0x4b, 0x9e, 0x74, 0x27, 0x7d, 0x07,
0xb2, 0xa3, 0xef, 0xc1, 0x07, 0xba, 0xa6, 0x6e, 0xb0, 0x43, 0xbc, 0x95, 0xf2, 0xfd, 0x24, 0xbf,
0x84, 0x20, 0x1f, 0x72, 0x13, 0x24, 0xa9, 0x32, 0xaa, 0x55, 0x83, 0xdc, 0xac, 0x75, 0xa8, 0x52,
0x94, 0x43, 0x38, 0xff, 0x35, 0xcc, 0x46, 0x61, 0x0c, 0x3a, 0x4a, 0x59, 0x62, 0x54, 0x5a, 0x66,
0xb8, 0x87, 0x9a, 0xb9, 0xe0, 0x03, 0x43, 0xa8, 0x6e, 0x6d, 0x04, 0x65, 0x1e, 0x54, 0x79, 0x70,
0x0a, 0x5a, 0x13, 0x0a, 0x67, 0x89, 0x61, 0x4a, 0xea, 0xff, 0x8f, 0x4f, 0xf5, 0x8e, 0xd7, 0x6d,
0xf6, 0x1b, 0xb9, 0xe0, 0xe7, 0x84, 0x6a, 0xbc, 0x85, 0x6a, 0xb9, 0xe0, 0xad, 0xf5, 0x15, 0x78,
0xcc, 0x80, 0xc7, 0x15, 0xfb, 0x7c, 0x29, 0x98, 0xdf, 0x2f, 0x5a, 0xbc, 0x8d, 0xea, 0x57, 0x5a,
0x49, 0x97, 0xf9, 0xb2, 0x66, 0x1e, 0xe3, 0x3d, 0xd4, 0x88, 0x61, 0x44, 0x32, 0x6e, 0x5c, 0xee,
0xdb, 0xba, 0xaa, 0x2f, 0x68, 0x0a, 0xda, 0x90, 0xd4, 0x49, 0x6f, 0xa6, 0xf6, 0x74, 0xb6, 0xc7,
0x3d, 0xe4, 0xc7, 0x70, 0xcd, 0x22, 0x18, 0xb0, 0xd8, 0x85, 0x6f, 0x2d, 0x6e, 0x96, 0xe2, 0x24,
0xc6, 0xbb, 0xe8, 0x1f, 0x55, 0x92, 0x08, 0x70, 0xd1, 0xbb, 0x69, 0x39, 0xb2, 0xcd, 0x4b, 0x68,
0x26, 0x89, 0x13, 0xde, 0x2f, 0x60, 0x91, 0xe3, 0x7d, 0xe4, 0x4b, 0xf5, 0xc7, 0x7b, 0x7a, 0xb0,
0xf3, 0x2e, 0x04, 0x3e, 0x44, 0x08, 0x64, 0x26, 0xec, 0xd0, 0x9b, 0x2b, 0xfe, 0x48, 0x66, 0xe2,
0x82, 0xf0, 0xec, 0xf7, 0x39, 0x7c, 0xbc, 0x95, 0xfb, 0x2f, 0xb1, 0x83, 0x9d, 0xe7, 0x59, 0xdb,
0x7b, 0x9d, 0xb5, 0xbd, 0xf7, 0x59, 0xdb, 0xbb, 0xec, 0x52, 0x66, 0xc6, 0xd9, 0x30, 0x88, 0x94,
0x08, 0xf5, 0x44, 0x46, 0x66, 0xcc, 0x24, 0x5d, 0xfa, 0x9a, 0xaf, 0x1d, 0x42, 0x6e, 0x7e, 0x02,
0x00, 0x00, 0xff, 0xff, 0x65, 0x95, 0xf9, 0xeb, 0xba, 0x02, 0x00, 0x00,
}

View File

@ -20,4 +20,10 @@ message Configuration {
OptionsConfiguration options = 6;
repeated ObservedDevice ignored_devices = 7 [(ext.json) = "remoteIgnoredDevices", (ext.xml) = "remoteIgnoredDevice"];
repeated ObservedDevice pending_devices = 8 [deprecated=true];
Defaults defaults = 9;
}
message Defaults {
FolderConfiguration folder = 1;
DeviceConfiguration device = 2;
}

View File

@ -8,14 +8,14 @@ import "lib/config/observed.proto";
import "ext.proto";
message DeviceConfiguration {
bytes device_id = 1 [(ext.goname) = "DeviceID", (ext.xml) = "id,attr", (ext.json) = "deviceID", (ext.device_id) = true];
bytes device_id = 1 [(ext.goname) = "DeviceID", (ext.xml) = "id,attr", (ext.json) = "deviceID", (ext.device_id) = true, (ext.nodefault) = true];
string name = 2 [(ext.xml) = "name,attr,omitempty"];
repeated string addresses = 3 [(ext.xml) = "address,omitempty", (ext.default) = "dynamic"];
protocol.Compression compression = 4 [(ext.xml) = "compression,attr"];
string cert_name = 5 [(ext.xml) = "certName,attr,omitempty"];
bool introducer = 6 [(ext.xml) = "introducer,attr"];
bool skip_introduction_removals = 7 [(ext.xml) = "skipIntroductionRemovals,attr"];
bytes introduced_by = 8 [(ext.xml) = "introducedBy,attr", (ext.device_id) = true];
bytes introduced_by = 8 [(ext.xml) = "introducedBy,attr", (ext.device_id) = true, (ext.nodefault) = true];
bool paused = 9;
repeated string allowed_networks = 10 [(ext.xml) = "allowedNetwork,omitempty"];
bool auto_accept_folders = 11;

View File

@ -20,10 +20,10 @@ message FolderDeviceConfiguration {
}
message FolderConfiguration {
string id = 1 [(ext.goname) = "ID", (ext.xml) = "id,attr"];
string id = 1 [(ext.goname) = "ID", (ext.xml) = "id,attr", (ext.nodefault) = true];
string label = 2 [(ext.xml) = "label,attr", (ext.restart) = false];
fs.FilesystemType filesystem_type = 3;
string path = 4 [(ext.xml) = "path,attr"];
string path = 4 [(ext.xml) = "path,attr", (ext.default) = "~"];
FolderType type = 5 [(ext.xml) = "type,attr"];
repeated FolderDeviceConfiguration devices = 6;
int32 rescan_interval_s = 7 [(ext.xml) = "rescanIntervalS,attr", (ext.default) = "3600"];
@ -31,7 +31,7 @@ message FolderConfiguration {
int32 fs_watcher_delay_s = 9 [(ext.goname) = "FSWatcherDelayS", (ext.xml) = "fsWatcherDelayS,attr", (ext.default) = "10"];
bool ignore_perms = 10 [(ext.xml) = "ignorePerms,attr"];
bool auto_normalize = 11 [(ext.xml) = "autoNormalize,attr", (ext.default) = "true"];
Size min_disk_free = 12;
Size min_disk_free = 12 [(ext.default) = "1 %"];
VersioningConfiguration versioning = 13;
int32 copiers = 14;
int32 puller_max_pending_kib = 15 [(ext.goname) = "PullerMaxPendingKiB", (ext.xml) = "pullerMaxPendingKiB", (ext.json) = "pullerMaxPendingKiB"];
@ -40,7 +40,7 @@ message FolderConfiguration {
bool ignore_delete = 18;
int32 scan_progress_interval_s = 19;
int32 puller_pause_s = 20;
int32 max_conflicts = 21 [(ext.default) = "-1"];
int32 max_conflicts = 21 [(ext.default) = "10"];
bool disable_sparse_files = 22;
bool disable_temp_indexes = 23;
bool paused = 24;

View File

@ -44,7 +44,7 @@ message OptionsConfiguration {
int32 temp_index_min_blocks = 35 [(ext.default) = "10"];
repeated string unacked_notification_ids = 36 [(ext.goname) = "UnackedNotificationIDs", (ext.xml) = "unackedNotificationID", (ext.json) = "unackedNotificationIDs"];
int32 traffic_class = 37;
string default_folder_path = 38 [(ext.default) = "~"];
string default_folder_path = 38 [deprecated = true];
bool set_low_priority = 39 [(ext.default) = "true"];
int32 max_folder_concurrency = 40 [(ext.goname) = "RawMaxFolderConcurrency"];
string crash_reporting_url = 41 [(ext.goname) = "CRURL", (ext.xml) = "crashReportingURL", (ext.json) = "crURL", (ext.default) = "https://crash.syncthing.net/newcrash"];

View File

@ -292,6 +292,13 @@ func HandleCustomExtensions(file *descriptor.FileDescriptorProto) func(msg *desc
current += fmt.Sprintf(`default:"%s"`, defaultValue)
}
if nodefaultValue, ok := GetFieldBooleanExtension(field, ext.E_Nodefault); ok {
if len(current) > 0 {
current += " "
}
current += fmt.Sprintf(`nodefault:"%t"`, nodefaultValue)
}
if restartValue, ok := GetFieldBooleanExtension(field, ext.E_Restart); ok {
if len(current) > 0 {
current += " "