Compare commits

...
78 Commits
Author SHA1 Message Date
Simon FreiandGitHub 1a22689328 lib/db: Add failure reports to failures iterating over hashes (#7755) 2021-06-07 23:10:35 +02:00
Jakob BorgandGitHub ce65aea0ab lib/db: Use a more concurrent GC (fixes #7722) (#7750)
This changes the GC mechanism so that the first pass (which reads all
FileInfos to populate bloom filters with block & version hashes) can
happen concurrently with normal database operations.

The big gcMut still exists, and we grab it temporarily to block all
other modifications while we set up the bloom filters. We then release
the lock and let other things happen, with those other things also
updating the bloom filters as required. Once the first phase is done we
again grab the gcMut, knowing that we are the sole modifier of the
database, and do the cleanup.

I also removed the final compaction step.
2021-06-07 10:52:06 +02:00
André ColombandGitHub 45edad867c all: Allow dismissing pending devices / folders without ignoring (fixes #7700) (#7712) 2021-06-07 10:29:24 +02:00
André ColombandGitHub ea0a408849 gui: Modal dialog for listeners and discovery status (#7539) 2021-06-07 09:08:44 +02:00
Simon FreiandGitHub 18592af993 lib/model: Fix wrongly hardcoded arguments in test helper (#7749) 2021-06-05 17:01:23 +02:00
Simon FreiandGitHub b1e0e7b923 lib/model: Fix indexhandling for new folders paused on remote (#7747) 2021-06-05 16:27:15 +02:00
Jakob Borg 1e212a8dc6 cmd/syncthing: Wording on error return in "cli debug file" 2021-06-05 11:45:29 +02:00
Jakob Borg 0e9d2a13af cmd/syncthing: Improve "cli debug file" handling
Proper URL encoding, and return a sensible error when it's not found.
2021-06-05 11:19:02 +02:00
Simon FreiandGitHub 6494a9332d lib/model: Fix test introduced in #7714 failing due to #7689 (#7745) 2021-06-04 15:32:47 +02:00
Simon FreiandGitHub 41baccb85d lib/model: Fix passwords on receive-enc needing token (ref #7518) (#7739) 2021-06-03 15:39:49 +02:00
Simon FreiandGitHub 52eb7392c4 lib/api, lib/config: Apply defaults before deserializing json (#7690) 2021-06-03 15:09:35 +02:00
Simon FreiandGitHub 855c53ad02 lib/model: Fix reverting when version has only our own ID (fixes #7708) (#7714) 2021-06-03 15:08:56 +02:00
Simon FreiandGitHub 004eded398 lib/model: Don't share with introduced device if encrypted (fixes #7724) (#7734) 2021-06-03 15:02:57 +02:00
Simon FreiandGitHub df48276300 lib/model: Ensure indexes are only received after checking IDs (ref #7649) (#7689) 2021-06-03 14:58:50 +02:00
Jakob Borg accaf23aa3 gui, man, authors: Update docs, translations, and contributors 2021-06-02 07:45:38 +02:00
André ColombandGitHub de6fe4dc6f gui: Show ID under each device section (local / remote), clickable for QR code (#7728) 2021-06-01 18:04:11 +02:00
Ikko AshimineandGitHub 08f6a91441 contributing: Fix GitHub format (#7713) 2021-05-31 10:27:35 +02:00
greatroarandGitHub 95c9561e97 lib/db: Clean up Timer and wait for logging before return in GC (#7720) 2021-05-31 09:50:21 +02:00
Simon FreiandGitHub fcb19518c7 build, lib/model: Add flag to run tests without -short and fix failure (#7716) 2021-05-28 22:20:18 +02:00
Jakob BorgandGitHub fbaf696821 readme: Remove drama (#7711) 2021-05-26 14:59:49 +02:00
Jakob Borg abe3483a8f gui, man, authors: Update docs, translations, and contributors 2021-05-26 07:45:29 +02:00
Simon FreiandGitHub 22e09334ec lib/model: Fix incoming request on receive-enc (fixes #7699) (#7702) 2021-05-22 21:38:49 +02:00
Simon FreiandGitHub 58592e3ef1 lib/db: Add logging for GC (#7707) 2021-05-22 21:36:43 +02:00
Simon FreiandGitHub 0126188ba7 lib/config: Set DisableTempIndexes to true on receive-encrypted (#7701) 2021-05-20 22:33:23 +02:00
Simon FreiandGitHub 5bdb6798a9 all: Regenerate proto (#7696) 2021-05-19 13:30:20 +02:00
Jakob Borg ab2729ab79 gui, man, authors: Update docs, translations, and contributors 2021-05-19 07:45:35 +02:00
Audrius ButkeviciusandGitHub 58e81fdffb cmd/syncthing/cli: Update recli, fix stdin handling (fixes #7685, fixes #7673) (#7694) 2021-05-18 20:09:48 +01:00
tomasz1986andGitHub 0619a27872 cmd/strelaypoolsrv: Fix minor grammar, use https in links (#7695)
* cmd/strelaypoolsrv: Fix minor grammar, use https in links

Add a few minor grammatical/stylistic fixes. Use `https` instead of
`http` in the MaxMind link in the footer.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>

* wip

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-05-18 19:07:09 +01:00
greatroarGitHubgreatroar <@>
0e52ce830a lib/fs: Fix UnicodeLowercaseNormalized on lowercase NFD (#7692)
Co-authored-by: greatroar <@>
2021-05-17 20:43:07 +02:00
Jakob BorgandGitHub 97437cad64 lib/fs: Ignore normalization differences in case insensitive lookup (fixes #7677) (#7678) 2021-05-17 12:35:03 +02:00
Simon FreiandGitHub 5b90a98650 lib/model: Fix addFakeConn and other test improvements (#7684) 2021-05-16 17:23:27 +02:00
Audrius ButkeviciusandGitHub 96dae7bfec cmd/uraggregate: Optimise queries (#7679)
* cmd/uraggregate: Optimise queries

* Update main.go
2021-05-16 12:34:46 +01:00
Simon FreiandGitHub 93a02c677e lib/scanner: Do not drop all not-exist-errors and debug logging (#7675) 2021-05-15 11:51:35 +02:00
Simon FreiandGitHub 0d054f9b64 lib/model: Don't use empty folder cfg for index sender (fixes #7649) (#7671) 2021-05-15 11:13:39 +02:00
Audrius ButkeviciusandGitHub 1107f6eb5f lib/connections: Reduce default quic redial interval (fixes #7471) (#7672)
* lib/connections: Reduce default quic redial interval (fixes #7471)

* Update quic_dial.go
2021-05-14 14:26:02 +01:00
Simon Frei 3650364017 Merge branch 'release' 2021-05-13 11:44:59 +02:00
bt90andJakob Borg 086508f51a docker: Remove sysctl from README (#7670) 2021-05-12 22:17:51 +02:00
Audrius ButkeviciusandGitHub 4ace451013 Update main.go (#7667) 2021-05-12 08:01:18 +01:00
Jakob Borg c9ea773a22 gui, man, authors: Update docs, translations, and contributors 2021-05-12 07:45:34 +02:00
Simon FreiandGitHub 0f4ae7636d build: Upgrade pfilter (fixes #7664) (#7666) 2021-05-11 20:57:38 +02:00
Simon Frei 87d3a8363b build: Upgrade pfilter (fixes #7664) 2021-05-11 20:45:35 +02:00
Simon FreiandGitHub c494ced21f lib/connections: Actually remove listenerSupervisor (ref #7644) (#7663) 2021-05-11 14:35:13 +02:00
Audrius ButkeviciusandGitHub a8e2fc6f61 cmd/uraggregate: Handle malformed data, dont abort on error (fixes #7639) (#7659) 2021-05-11 08:02:19 +02:00
Audrius ButkeviciusandGitHub aca1b45e93 lib/connections: Update pfilter to pick up bugfix/oob stuff, support OOB connections (fixes #7636) (#7654) 2021-05-11 07:59:56 +02:00
Simon FreiandGitHub 5cb2a10138 lib/model: Improve encryption cluster-config errors (#7658) 2021-05-11 07:55:44 +02:00
Audrius ButkeviciusandGitHub 411796606c lib/connections: Correct service termination order (#7657) 2021-05-10 22:29:27 +02:00
Simon FreiandGitHub 1a9b54c9fa lib/connections: Separate listener supervisors and lower backoff time (#7644) 2021-05-10 22:26:51 +02:00
Simon FreiandGitHub c7f4f15272 lib/relay, lib/svcutil: Improve service logging (fixes #7580) (#7647) 2021-05-10 22:26:25 +02:00
Simon FreiandGitHub 713527facf all: Refactor relay invitations (#7646) 2021-05-10 22:25:43 +02:00
Simon FreiandGitHub 6e662dc9fc lib/suture: Use ServeBackground to start main supervisor (#7626) 2021-05-10 16:50:45 +02:00
eb178caf3a lib/connections: Add connection benchmarks, allow binding to port zero addresses (#7648)
* Add connbench

* Refactor port fixup

* More cleanup

* touch for build

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2021-05-10 15:44:47 +01:00
Audrius ButkeviciusandGitHub adf3f641ce Ignore GoLand cruft 2021-05-09 23:56:18 +01:00
Simon FreiandGitHub 6157c766de lib/connections: Correct comments on quic wrapper type (#7652) 2021-05-09 19:15:10 +01:00
Audrius ButkeviciusandGitHub 745cd4744a lib/connections: Revert add more methods to the quic conn wrapper (#7651)
This reverts commit faf15b4567.
2021-05-09 19:43:16 +02:00
Simon FreiandGitHub faf15b4567 lib/connections: Add more methods to the quic conn wrapper (#7643) 2021-05-09 12:45:08 +01:00
greatroarandGitHub 3746c899b7 build: List go:generate tools in tools.go (#7599) 2021-05-08 12:52:06 +02:00
Jakob Borg 7bbca12ff8 Merge branch 'release'
* release:
  build: Ignore error from pkill on apt upgrade (fixes #7628) (#7629)
2021-05-06 13:23:02 +02:00
Simon FreiandJakob Borg 3967b39a17 build: Ignore error from pkill on apt upgrade (fixes #7628) (#7629) 2021-05-05 09:37:23 +02:00
Jakob Borg 2b2d24fe20 gui, man, authors: Update docs, translations, and contributors 2021-05-05 07:45:35 +02:00
Simon FreiandGitHub f4e112f404 build: Ignore error from pkill on apt upgrade (fixes #7628) (#7629) 2021-05-04 18:33:25 +02:00
Audrius ButkeviciusandGitHub 87a0eecc31 lib/fs, lib/api, lib/model: Expose mtime remappings as part of /db/file (#7624)
* lib/fs, lib/api, lib/model: Expose mtime remappings as part of /db/file

* Fix wrong error returned by CLI

* Gofmt

* Better names

* Review comments

* Review comments
2021-05-03 11:28:25 +01:00
overkillandGitHub f09dcb98eb gui: Semicolons (#7597) 2021-05-03 12:14:54 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
f90870b99f build: Bump github.com/shirou/gopsutil/v3 from 3.21.3 to 3.21.4 (#7625)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.21.3 to 3.21.4.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.21.3...v3.21.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-03 12:10:04 +02:00
Simon FreiandGitHub 75b58eb480 lib/fs: Watch attrib. changes on inotify for mod. time (#7623)
* lib/fs: Watch attrib. changes on inotify for mod. time

* fix bsds (real) and darwin (test only)
2021-05-02 16:45:44 +02:00
Jakob BorgandGitHub ed9cb923fb build: Update most dependencies (fixes: all the dependabot PRs) (#7622) 2021-04-30 09:11:11 +02:00
Simon FreiandGitHub dd39556759 lib: Revert needing invalid files (fixes #7608, ref #7476) (#7609) 2021-04-29 22:01:46 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d5141c6d51 build: Bump github.com/prometheus/client_golang from 1.8.0 to 1.10.0 (#7612)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.8.0 to 1.10.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.8.0...v1.10.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 21:57:22 +02:00
dependabot-preview[bot]andGitHub 5675644341 build: Upgrade to GitHub-native Dependabot (#7607) 2021-04-29 21:19:06 +02:00
Simon FreiandGitHub 1f30383866 lib/model: Remove path from enc errors and report only once (#7610) 2021-04-29 19:21:07 +02:00
tomasz1986andGitHub 40531ef247 gui: Disable versions button when folder is paused (#7611)
Disable the Versions button when the folder is paused, because it does
not work, i.e. the versioned files are not loaded. The folder needs to
be unpaused to actually be able to view the versioned file list.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-04-29 18:34:08 +02:00
Wulf WeichandGitHub 366700dc36 gui: Cut off long remote device names (fixes #7592) (#7606) 2021-04-28 18:11:05 +02:00
Jakob Borg f23fd683a9 gui, man, authors: Update docs, translations, and contributors 2021-04-28 07:45:43 +02:00
Jakob Borg 755ed6f69f Merge branch 'release'
* release:
  lib/model: Handle invalid needed items on send-only (ref #7476) (#7596)
  gui: Handle empty path in validation (ref #7379) (#7595)
  cmd/syncthing: Don't fail early on api setup error (fixes 7558) (#7591)
2021-04-27 07:59:51 +02:00
66662cd678 Trigger connection loop on config device addition (fixes #7600) (#7604)
* Trigger connection loop on config device addition (fixes #7600)

* Also check for device address equality

* Move EqualStrings from api_test to utils, and use in connections/service.go

* Make sure CommitConfiguration cannot block due on the deviceAddressesChanged channel

* Update lib/connections/service.go

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2021-04-26 21:13:59 +01:00
Simon FreiandGitHub 8734fa65fc lib/model: Handle invalid needed items on send-only (ref #7476) (#7596) 2021-04-26 15:36:51 +02:00
Simon FreiandGitHub c53e5c5f17 gui: Handle empty path in validation (ref #7379) (#7595) 2021-04-26 15:35:12 +02:00
Jakob BorgandGitHub 74823e81e9 all: Deprecate TLS 1.2 on sync connections (fixes #7594) (#7598)
This makes us use TLS 1.3+ on sync connections by default. A new option
`insecureAllowOldTLSVersions` exists to allow communication with TLS
1.2-only clients (roughly Syncthing 1.2.2 and older). Even with that
option set you get a slightly simplified setup, with the cipher suite
order fixed instead of auto detected.
2021-04-26 10:04:35 +02:00
Simon FreiandGitHub ef4b8a2cf8 cmd/syncthing: Don't fail early on api setup error (fixes 7558) (#7591)
* cmd/syncthing: Don't fail early on api setup error (fixes 7558)

* switch to factory pattern

* refactor config command to show help on nothing

* wip

* wip

* already abort in before
2021-04-25 20:48:17 +01:00
162 changed files with 3694 additions and 2154 deletions
+7
View File
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
+1
View File
@@ -19,3 +19,4 @@ deb
/repos
/proto/scripts/protoc-gen-gosyncthing
/gui/next-gen-gui
.idea
+4 -1
View File
@@ -82,7 +82,7 @@ deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.c
Denis A. (dva) <denisva@gmail.com>
Dennis Wilson (snnd) <dw@risu.io>
dependabot-preview[bot] <dependabot-preview[bot]@users.noreply.github.com> <27856297+dependabot-preview[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <49699333+dependabot[bot]@users.noreply.github.com>
derekriemer <derek.riemer@colorado.edu>
desbma <desbma@users.noreply.github.com>
Dmitry Saveliev (dsaveliev) <d.e.saveliev@gmail.com>
@@ -100,6 +100,7 @@ Felix Lampe <mail@flampe.de>
Felix Unterpaintner (bigbear2nd) <bigbear2nd@gmail.com>
Francois-Xavier Gsell (zukoo) <fxgsell@gmail.com>
Frank Isemann (fti7) <frank@isemann.name>
Gahl Saraf <saraf.gahl@gmail.com>
georgespatton <georgespatton@users.noreply.github.com>
ghjklw <malo@jaffre.info>
Gilli Sigurdsson (gillisig) <gilli@vx.is>
@@ -113,6 +114,7 @@ Heiko Zuerker (Smiley73) <heiko@zuerker.org>
Hugo Locurcio <hugo.locurcio@hugo.pro>
Iain Barnett <iainspeed@gmail.com>
Ian Johnson (anonymouse64) <ian.johnson@canonical.com> <person.uwsome@gmail.com>
Ikko Ashimine <eltociear@gmail.com>
Ilya Brin <464157+ilyabrin@users.noreply.github.com>
Iskander Sharipov (Alex) <quasilyte@gmail.com>
Jaakko Hannikainen (jgke) <jgke@jgke.fi>
@@ -203,6 +205,7 @@ NoLooseEnds <jon.koslung@gmail.com>
Oliver Freyermuth <o.freyermuth@googlemail.com>
otbutz <tbutz@optitool.de>
Otiel <Otiel@users.noreply.github.com>
overkill <22098433+0verk1ll@users.noreply.github.com>
Oyebanji Jacob Mayowa <oyebanji05@gmail.com>
Pablo <pbaeyens31+github@gmail.com>
Pascal Jungblut (pascalj) <github@pascalj.com> <mail@pascal-jungblut.com>
+1 -1
View File
@@ -1,6 +1,6 @@
## Reporting Bugs
Please file bugs in the [Github Issue
Please file bugs in the [GitHub Issue
Tracker](https://github.com/syncthing/syncthing/issues). Include at
least the following:
+1 -4
View File
@@ -16,8 +16,7 @@ the name of the Syncthing instance can be optionally defined by using
**Docker cli**
```
$ docker pull syncthing/syncthing
$ docker run --sysctl net.core.rmem_max=2097152 \
-p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp \
$ docker run -p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp \
-v /wherever/st-sync:/var/syncthing \
--hostname=my-syncthing \
syncthing/syncthing:latest
@@ -41,8 +40,6 @@ services:
- 8384:8384
- 22000:22000/tcp
- 22000:22000/udp
sysctls:
- net.core.rmem_max=2097152
restart: unless-stopped
```
+2 -5
View File
@@ -73,9 +73,8 @@ This helps the team understand what are the biggest pain points for our users, a
## Getting in Touch
The first and best point of contact is the [Forum][8]. There is also an IRC
channel, `#syncthing` on [freenode][4] (with a [web client][9]), for talking
directly to developers and users. If you've found something that is clearly a
The first and best point of contact is the [Forum][8].
If you've found something that is clearly a
bug, feel free to report it in the [GitHub issue tracker][10].
## Building
@@ -102,12 +101,10 @@ All code is licensed under the [MPLv2 License][7].
[1]: https://docs.syncthing.net/specs/bep-v1.html
[2]: https://docs.syncthing.net/intro/getting-started.html
[3]: https://github.com/syncthing/syncthing/blob/main/etc
[4]: https://www.freenode.net/
[5]: https://docs.syncthing.net/dev/building.html
[6]: https://docs.syncthing.net/
[7]: https://github.com/syncthing/syncthing/blob/main/LICENSE
[8]: https://forum.syncthing.net/
[9]: https://kiwiirc.com/client/irc.freenode.net/#syncthing
[10]: https://github.com/syncthing/syncthing/issues
[11]: https://docs.syncthing.net/users/contrib.html#gui-wrappers
[12]: https://www.bountysource.com/teams/syncthing/issues
+19 -26
View File
@@ -50,7 +50,9 @@ var (
benchRun string
debugBinary bool
coverage bool
long bool
timeout = "120s"
longTimeout = "600s"
numVersions = 5
withNextGenGUI = os.Getenv("BUILD_NEXT_GEN_GUI") != ""
)
@@ -202,18 +204,6 @@ var targets = map[string]target{
},
}
// These are repos we need to clone to run "go generate"
type dependencyRepo struct {
path string
repo string
commit string
}
var dependencyRepos = []dependencyRepo{
{path: "xdr", repo: "https://github.com/calmh/xdr.git", commit: "08e072f9cb16"},
}
func initTargets() {
all := targets["all"]
pkgs, _ := filepath.Glob("cmd/*")
@@ -375,6 +365,7 @@ func parseFlags() {
flag.StringVar(&cc, "cc", os.Getenv("CC"), "Set CC environment variable for `go build`")
flag.BoolVar(&debugBinary, "debug-binary", debugBinary, "Create unoptimized binary to use with delve, set -gcflags='-N -l' and omit -ldflags")
flag.BoolVar(&coverage, "coverage", coverage, "Write coverage profile of tests to coverage.txt")
flag.BoolVar(&long, "long", long, "Run tests without the -short flag")
flag.IntVar(&numVersions, "num-versions", numVersions, "Number of versions for changelog command")
flag.StringVar(&run, "run", "", "Specify which tests to run")
flag.StringVar(&benchRun, "bench", "", "Specify which benchmarks to run")
@@ -386,7 +377,13 @@ func test(tags []string, pkgs ...string) {
lazyRebuildAssets()
tags = append(tags, "purego")
args := []string{"test", "-short", "-timeout", timeout, "-tags", strings.Join(tags, " ")}
args := []string{"test", "-tags", strings.Join(tags, " ")}
if long {
timeout = longTimeout
} else {
args = append(args, "-short")
}
args = append(args, "-timeout", timeout)
if runtime.GOARCH == "amd64" {
switch runtime.GOOS {
@@ -871,28 +868,24 @@ func shouldRebuildAssets(target, srcdir string) bool {
func proto() {
pv := protobufVersion()
dependencyRepos = append(dependencyRepos,
dependencyRepo{path: "protobuf", repo: "https://github.com/gogo/protobuf.git", commit: pv},
)
repo := "https://github.com/gogo/protobuf.git"
path := filepath.Join("repos", "protobuf")
runPrint(goCmd, "get", fmt.Sprintf("github.com/gogo/protobuf/protoc-gen-gogofast@%v", pv))
os.MkdirAll("repos", 0755)
for _, dep := range dependencyRepos {
path := filepath.Join("repos", dep.path)
if _, err := os.Stat(path); err != nil {
runPrintInDir("repos", "git", "clone", dep.repo, dep.path)
} else {
runPrintInDir(path, "git", "fetch")
}
runPrintInDir(path, "git", "checkout", dep.commit)
if _, err := os.Stat(path); err != nil {
runPrint("git", "clone", repo, path)
} else {
runPrintInDir(path, "git", "fetch")
}
runPrintInDir(path, "git", "checkout", pv)
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/cmd/stdiscosrv")
runPrint(goCmd, "generate", "proto/generate.go")
}
func testmocks() {
runPrint(goCmd, "get", "golang.org/x/tools/cmd/goimports")
runPrint(goCmd, "get", "github.com/maxbrunsfeld/counterfeiter/v6")
args := []string{
"generate",
"github.com/syncthing/syncthing/lib/config",
+3 -12
View File
@@ -510,10 +510,7 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
@@ -648,10 +645,7 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
@@ -752,10 +746,7 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
+4 -4
View File
@@ -46,18 +46,18 @@
<h1>Relay Pool Data</h1>
<div ng-if="relays === undefined" class="text-center">
<img src="https://cdnjs.cloudflare.com/ajax/libs/galleriffic/2.0.1/css/loader.gif" alt=""/>
<p>Please wait while we gather data</p>
<p>Please wait while we gather data</p>
</div>
<div>
<div ng-show="relays !== undefined" class="ng-hide">
<p>
The relays listed on this page are not managed or vetted by the Syncthing project.
Each relay is the responsibility of the relay operator.
Currently {{ relays.length }} relays online.
Currently {{ relays.length }} relays are online.
</p>
</div>
<div id="map"></div> <!-- Can't hide the map, otherwise it freaks out -->
<p>The circle size represents how much bytes the relay transferred relative to other relays</p>
<p>The circle size represents how much bytes the relay has transferred relatively to other relays.</p>
</div>
<div>
<table class="table table-striped table-condensed table">
@@ -188,7 +188,7 @@
<hr>
<p>
This product includes GeoLite2 data created by MaxMind, available from
<a href="http://www.maxmind.com">http://www.maxmind.com</a>.
<a href="https://www.maxmind.com">https://www.maxmind.com</a>.
</p>
</div>
+1 -1
View File
@@ -57,7 +57,7 @@ func main() {
if join {
log.Println("Creating client")
relay, err := client.NewClient(uri, []tls.Certificate{cert}, nil, 10*time.Second)
relay, err := client.NewClient(uri, []tls.Certificate{cert}, 10*time.Second)
if err != nil {
log.Fatal(err)
}
+6 -4
View File
@@ -134,12 +134,14 @@ func (c *apiClient) Post(url, body string) (*http.Response, error) {
return c.Do(request)
}
var errNotFound = errors.New("invalid endpoint or API call")
func checkResponse(response *http.Response) error {
if response.StatusCode == 404 {
return errors.New("invalid endpoint or API call")
} else if response.StatusCode == 403 {
if response.StatusCode == http.StatusNotFound {
return errNotFound
} else if response.StatusCode == http.StatusUnauthorized {
return errors.New("invalid API key")
} else if response.StatusCode != 200 {
} else if response.StatusCode != http.StatusOK {
data, err := responseToBArray(response)
if err != nil {
return err
+5 -1
View File
@@ -8,6 +8,7 @@ package cli
import (
"fmt"
"net/url"
"github.com/urfave/cli"
)
@@ -35,7 +36,10 @@ var debugCommand = cli.Command{
func debugFile() cli.ActionFunc {
return func(c *cli.Context) error {
return indexDumpOutput(fmt.Sprintf("debug/file?folder=%v&file=%v", c.Args()[0], normalizePath(c.Args()[1])))(c)
query := make(url.Values)
query.Set("folder", c.Args()[0])
query.Set("file", normalizePath(c.Args()[1]))
return indexDumpOutput("debug/file?" + query.Encode())(c)
}
}
+33 -30
View File
@@ -8,13 +8,13 @@ package cli
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/alecthomas/kong"
"github.com/flynn-archive/go-shlex"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"github.com/urfave/cli"
@@ -97,38 +97,41 @@ func Run() error {
operationCommand,
errorsCommand,
debugCommand,
{
Name: "-",
HideHelp: true,
Usage: "Read commands from stdin",
Action: func(ctx *cli.Context) error {
if ctx.NArg() > 0 {
return errors.New("command does not expect any arguments")
}
// Drop the `-` not to recurse into self.
args := make([]string, len(os.Args)-1)
copy(args, os.Args)
fmt.Println("Reading commands from stdin...", args)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input, err := shlex.Split(scanner.Text())
if err != nil {
return errors.Wrap(err, "parsing input")
}
if len(input) == 0 {
continue
}
err = app.Run(append(args, input...))
if err != nil {
return err
}
}
return scanner.Err()
},
},
},
}}
tty := isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd())
if !tty {
// Not a TTY, consume from stdin
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input, err := shlex.Split(scanner.Text())
if err != nil {
return errors.Wrap(err, "parsing input")
}
if len(input) == 0 {
continue
}
err = app.Run(append(os.Args, input...))
if err != nil {
return err
}
}
err = scanner.Err()
if err != nil {
return err
}
} else {
err = app.Run(os.Args)
if err != nil {
return err
}
}
return nil
return app.Run(os.Args)
}
func parseFlags(c *preCli) error {
+3
View File
@@ -48,6 +48,9 @@ func indexDumpOutput(url string) cli.ActionFunc {
return err
}
response, err := client.Get(url)
if errors.Is(err, errNotFound) {
return errors.New("not found (folder/file not in database)")
}
if err != nil {
return err
}
+20 -17
View File
@@ -47,32 +47,32 @@ func main() {
func runAggregation(db *sql.DB) {
since := maxIndexedDay(db, "VersionSummary")
log.Println("Aggregating VersionSummary data since", since)
rows, err := aggregateVersionSummary(db, since)
rows, err := aggregateVersionSummary(db, since.Add(24*time.Hour))
if err != nil {
log.Fatalln("aggregate:", err)
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
log.Println("Aggregating UserMovement data")
rows, err = aggregateUserMovement(db)
if err != nil {
log.Fatalln("aggregate:", err)
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
log.Println("Aggregating Performance data")
since = maxIndexedDay(db, "Performance")
rows, err = aggregatePerformance(db, since)
log.Println("Aggregating Performance data since", since)
rows, err = aggregatePerformance(db, since.Add(24*time.Hour))
if err != nil {
log.Fatalln("aggregate:", err)
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
log.Println("Aggregating BlockStats data")
since = maxIndexedDay(db, "BlockStats")
rows, err = aggregateBlockStats(db, since)
log.Println("Aggregating BlockStats data since", since)
rows, err = aggregateBlockStats(db, since.Add(24*time.Hour))
if err != nil {
log.Fatalln("aggregate:", err)
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
}
@@ -163,7 +163,7 @@ func setupDB(db *sql.DB) error {
func maxIndexedDay(db *sql.DB, table string) time.Time {
var t time.Time
row := db.QueryRow("SELECT MAX(Day) FROM " + table)
row := db.QueryRow("SELECT MAX(DATE_TRUNC('day', Day)) FROM " + table)
err := row.Scan(&t)
if err != nil {
return time.Time{}
@@ -179,8 +179,8 @@ func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
COUNT(*) AS Count
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
GROUP BY Day, Ver
);
@@ -198,7 +198,8 @@ func aggregateUserMovement(db *sql.DB) (int64, error) {
Report->>'uniqueID'
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Report->>'uniqueID' IS NOT NULL
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
ORDER BY Day
`)
@@ -283,9 +284,11 @@ func aggregatePerformance(db *sql.DB, since time.Time) (int64, error) {
AVG((Report->>'memoryUsageMiB')::numeric) As MemoryUsageMiB
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
/* Some custom implementation reported bytes when we expect megabytes, cap at petabyte */
AND (Report->>'memorySize')::numeric < 1073741824
GROUP BY Day
);
`, since)
@@ -312,8 +315,8 @@ func aggregateBlockStats(db *sql.DB, since time.Time) (int64, error) {
SUM((Report->'blockStats'->>'copyElsewhere')::numeric) AS CopyElsewhere
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND (Report->>'urVersion')::numeric >= 3
AND Report->>'version' like 'v_.%'
AND Report->>'version' NOT LIKE 'v0.14.40%'
+32 -31
View File
@@ -1,57 +1,58 @@
module github.com/syncthing/syncthing
require (
github.com/AudriusButkevicius/pfilter v0.0.0-20210218141631-7468b85d810a
github.com/AudriusButkevicius/recli v0.0.5
github.com/alecthomas/kong v0.2.12
github.com/AudriusButkevicius/pfilter v0.0.0-20210511165305-e9aaf99ab213
github.com/AudriusButkevicius/recli v0.0.6
github.com/alecthomas/kong v0.2.16
github.com/bkaradzic/go-lz4 v0.0.0-20160924222819-7224d8d8f27e
github.com/calmh/xdr v1.1.0
github.com/ccding/go-stun v0.1.3
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
github.com/certifi/gocertifi v0.0.0-20210429200110-83314bf6d27c // indirect
github.com/chmduquesne/rollinghash v0.0.0-20180912150627-a60f8e7142b5
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/d4l3k/messagediff v1.2.1
github.com/dchest/siphash v1.2.2
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568
github.com/getsentry/raven-go v0.2.0
github.com/go-ldap/ldap/v3 v3.2.4
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-ldap/ldap/v3 v3.3.0
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
github.com/gogo/protobuf v1.3.2
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
github.com/golang/protobuf v1.5.2 // indirect
github.com/greatroar/blobloom v0.7.0
github.com/hashicorp/golang-lru v0.5.4
github.com/jackpal/gateway v1.0.7
github.com/jackpal/go-nat-pmp v1.0.2
github.com/julienschmidt/httprouter v1.3.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/lib/pq v1.8.0
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
github.com/lib/pq v1.10.1
github.com/lucas-clemente/quic-go v0.19.3
github.com/maruel/panicparse v1.5.1
github.com/mattn/go-isatty v0.0.12
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0 // indirect
github.com/minio/sha256-simd v0.1.1
github.com/maruel/panicparse v1.6.1
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0
github.com/minio/sha256-simd v1.0.0
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/onsi/gomega v1.10.3 // indirect
github.com/oschwald/geoip2-golang v1.4.0
github.com/oschwald/geoip2-golang v1.5.0
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.8.0
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0
github.com/prometheus/client_golang v1.10.0
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sasha-s/go-deadlock v0.2.0
github.com/shirou/gopsutil/v3 v3.20.11
github.com/shirou/gopsutil/v3 v3.21.4
github.com/syncthing/notify v0.0.0-20210308121556-f45149b04939
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7
github.com/thejerf/suture/v4 v4.0.0
github.com/urfave/cli v1.22.4
github.com/thejerf/suture/v4 v4.0.1
github.com/urfave/cli v1.22.5
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
golang.org/x/text v0.3.4
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
golang.org/x/tools v0.1.0 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887
golang.org/x/text v0.3.6
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
golang.org/x/tools v0.1.0
google.golang.org/protobuf v1.26.0
)
go 1.14
+105 -68
View File
@@ -7,10 +7,10 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AudriusButkevicius/pfilter v0.0.0-20210218141631-7468b85d810a h1:dUzIAgRmHLIUU0PT+OJ0X1WI5j1hlLbf+G420gUjIQg=
github.com/AudriusButkevicius/pfilter v0.0.0-20210218141631-7468b85d810a/go.mod h1:1N0EEx/irz4B1qV17wW82TFbjQrE7oX316Cki6eDY0Q=
github.com/AudriusButkevicius/recli v0.0.5 h1:xUa55PvWTHBm17T6RvjElRO3y5tALpdceH86vhzQ5wg=
github.com/AudriusButkevicius/recli v0.0.5/go.mod h1:Q2E26yc6RvWWEz/TJ/goUp6yXvipYdJI096hpoaqsNs=
github.com/AudriusButkevicius/pfilter v0.0.0-20210511165305-e9aaf99ab213 h1:9E6vGKdipZ+AAkU19TUb5JQKMf44CGAYMtXDAyfonO4=
github.com/AudriusButkevicius/pfilter v0.0.0-20210511165305-e9aaf99ab213/go.mod h1:EEEtt5r8y0gGHlRFF2+cLx0WUy/rKHnjALmom5E0+74=
github.com/AudriusButkevicius/recli v0.0.6 h1:hY9KH09vIbx0fYpkvdWbvnh67uDiuJEVDGhXlefysDQ=
github.com/AudriusButkevicius/recli v0.0.6/go.mod h1:Nhfib1j/VFnLrXL9cHgA+/n2O6P5THuWelOnbfPNd78=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -21,8 +21,8 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUW
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/kong v0.2.12 h1:X3kkCOXGUNzLmiu+nQtoxWqj4U2a39MpSJR3QdQXOwI=
github.com/alecthomas/kong v0.2.12/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/kong v0.2.16 h1:F232CiYSn54Tnl1sJGTeHmx4vJDNLVP2b9yCVMOQwHQ=
github.com/alecthomas/kong v0.2.16/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -50,14 +50,12 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7
github.com/calmh/xdr v1.1.0 h1:U/Dd4CXNLoo8EiQ4ulJUXkgO1/EyQLgDKLgpY1SOoJE=
github.com/calmh/xdr v1.1.0/go.mod h1:E8sz2ByAdXC8MbANf1LCRYzedSnnc+/sXXJs/PVqoeg=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/ccding/go-stun v0.1.2 h1:1CZhjVwfyO/jGxk06a+0OSOGBWZu588kuZQQO4nihsw=
github.com/ccding/go-stun v0.1.2/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
github.com/ccding/go-stun v0.1.3 h1:uEAFsxqPBuo4tvILfloEHUBO3b4BlEAMnx2PZdh54jE=
github.com/ccding/go-stun v0.1.3/go.mod h1:cCZjJ1J3WFSJV6Wj8Y9Di8JMTsEXh6uv2eNmLzKaUeM=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20210429200110-83314bf6d27c h1:Tt0GPSnn14HRN/+db/WGBPDnUykj4b7EBNtBdHVQFiY=
github.com/certifi/gocertifi v0.0.0-20210429200110-83314bf6d27c/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
@@ -72,8 +70,9 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
@@ -106,14 +105,15 @@ github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JY
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag=
github.com/go-asn1-ber/asn1-ber v1.5.3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-ldap/ldap/v3 v3.2.4 h1:PFavAq2xTgzo/loE8qNXcQaofAaqIpI4WgaLdv+1l3E=
github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ=
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
@@ -127,20 +127,23 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -150,8 +153,10 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -160,8 +165,11 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -176,12 +184,13 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/greatroar/blobloom v0.5.0 h1:jNbCsgDpZ23AI6jgZsXm7oFatkFaLCxr+ZWzlYasONU=
github.com/greatroar/blobloom v0.5.0/go.mod h1:M+yFtr/P96aNZYDYowvNWL3WdDluSMK2PPPHN49LMw8=
github.com/greatroar/blobloom v0.7.0 h1:gZXk/iFa20AgD3merUnWBIJmsvUJTsTJExO6+7N7Mlw=
github.com/greatroar/blobloom v0.7.0/go.mod h1:M+yFtr/P96aNZYDYowvNWL3WdDluSMK2PPPHN49LMw8=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@@ -198,8 +207,9 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
@@ -208,8 +218,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackpal/gateway v1.0.6 h1:/MJORKvJEwNVldtGVJC2p2cwCnsSoLn3hl3zxmZT7tk=
github.com/jackpal/gateway v1.0.6/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/jackpal/gateway v1.0.7 h1:7tIFeCGmpyrMx9qvT0EgYUi7cxVW48a0mMvnIL17bPM=
github.com/jackpal/gateway v1.0.7/go.mod h1:aRcO0UFKt+MgIZmRmvOmnejdDT4Y1DNiNOsSd1AcIbA=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
@@ -228,8 +238,11 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -238,8 +251,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo=
github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4=
@@ -252,10 +265,13 @@ github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl5
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ=
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/maruel/panicparse v1.5.1 h1:hUPcXI7ubtEqj/k+P34KsHQqb86zuVk7zBfkP6tBBPc=
github.com/maruel/panicparse v1.5.1/go.mod h1:aOutY/MUjdj80R0AEVI9qE2zHqig+67t2ffUDDiLzAM=
github.com/marten-seemann/qtls-go1-15 v0.1.4 h1:RehYMOyRW8hPVEja1KBVsFVNSm35Jj9Mvs5yNoZZ28A=
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/maruel/panicparse v1.6.1 h1:803MjBzGcUgE1vYgg3UMNq3G1oyYeKkMu3t6hBS97x0=
github.com/maruel/panicparse v1.6.1/go.mod h1:uoxI4w9gJL6XahaYPMq/z9uadrdr1SyHuQwV2q80Mm0=
github.com/maruel/panicparse/v2 v2.1.1/go.mod h1:AeTWdCE4lcq8OKsLb6cHSj1RWHVSnV9HBCk7sKLF4Jg=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@@ -265,11 +281,11 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0 h1:8E6DrFvII6QR4eJ3PkFvV+lc03P+2qwqTPLm1ax7694=
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0/go.mod h1:fcEyUyXZXoV4Abw8DX0t7wyL8mCDxXyU4iAFZfT3IHw=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75 h1:cUVxyR+UfmdEAZGJ8IiKld1O0dbGotEnkMolG5hfMSY=
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75/go.mod h1:pBbZyGwC5i16IBkjVKoy/sznA8jPD/K9iedwe1ESE6w=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -321,10 +337,10 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/oschwald/geoip2-golang v1.4.0 h1:5RlrjCgRyIGDz/mBmPfnAF4h8k0IAcRv9PvrpOfz+Ug=
github.com/oschwald/geoip2-golang v1.4.0/go.mod h1:8QwxJvRImBH+Zl6Aa6MaIcs5YdlZSTKtzmPGzQqi9ng=
github.com/oschwald/maxminddb-golang v1.6.0 h1:KAJSjdHQ8Kv45nFIbtoLGrGWqHFajOIm7skTyz/+Dls=
github.com/oschwald/maxminddb-golang v1.6.0/go.mod h1:DUJFucBg2cvqx42YmDa/+xHvb0elJtOm3o4aFQ/nb/w=
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
@@ -347,8 +363,8 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg=
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -361,34 +377,36 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y=
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.20.11 h1:NeVf1K0cgxsWz+N3671ojRptdgzvp7BXL3KV21R0JnA=
github.com/shirou/gopsutil/v3 v3.20.11/go.mod h1:igHnfak0qnw1biGeI2qKQvu0ZkwvEkUcCLlYhZzdr/4=
github.com/shirou/gopsutil/v3 v3.21.4 h1:XB/+p+kVnyYLuPHCfa99lxz2aJyvVhnyd+FxZqH/k7M=
github.com/shirou/gopsutil/v3 v3.21.4/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
@@ -409,7 +427,6 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
@@ -432,25 +449,29 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syncthing/notify v0.0.0-20210308121556-f45149b04939 h1:InjitJPCBfhc1/DP0Z8OglJq5qvQD+J0o64TFyenf68=
github.com/syncthing/notify v0.0.0-20210308121556-f45149b04939/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y=
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7 h1:udtnv1cokhJYqnUfCMCppJ71bFN9VKfG1BQ6UsYZnx8=
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thejerf/suture/v4 v4.0.0 h1:GX3X+1Qaewtj9flL2wgoTBfLA5NcmrCY39TJRpPbUrI=
github.com/thejerf/suture/v4 v4.0.0/go.mod h1:g0e8vwskm9tI0jRjxrnA6lSr0q6OfPdWJVX7G5bVWRs=
github.com/thejerf/suture/v4 v4.0.1 h1:CLnC1wxLAiHA5zTbbvhSWMupVuGe5ZJ7YddWE3lvb4M=
github.com/thejerf/suture/v4 v4.0.1/go.mod h1:g0e8vwskm9tI0jRjxrnA6lSr0q6OfPdWJVX7G5bVWRs=
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 h1:okhMind4q9H1OxF44gNegWkiP4H/gsTFLalHFa4OOUI=
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0/go.mod h1:TTbGUfE+cXXceWtbTHq6lqcTvYPBKLNejBEbnUsQJtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
@@ -478,8 +499,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -489,6 +510,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -510,6 +532,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
@@ -517,8 +540,9 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -531,6 +555,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -560,29 +585,35 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -595,7 +626,9 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -619,6 +652,7 @@ google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
@@ -630,14 +664,17 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Натиснете, за да видите грешки при откриването",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Затвори",
"Command": "Команда",
"Comment, when used at the start of a line": "Коментар, използван в началото на реда",
@@ -153,6 +154,7 @@
"Help": "Помощ",
"Home page": "Начална страница",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Игнорирай",
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Clica per a vore els fallos en el descobriment",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Tancar",
"Command": "Comando",
"Comment, when used at the start of a line": "Comentar, quant s'utilitza al principi d'una línia",
@@ -153,6 +154,7 @@
"Help": "Ajuda",
"Home page": "Pàgina inicial",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignorar",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Mazání verzí",
"Cleanup Interval": "Interval mazání",
"Click to see discovery failures": "Kliknutím zobrazíte nezdary při objevování",
"Click to see full identification string and QR code.": "Kliknutím zobrazíte úplnou identifikaci a QR kód.",
"Close": "Zavřít",
"Command": "Příkaz",
"Comment, when used at the start of a line": "Pokud použito na jeho začátku, je řádek považován za komentář",
@@ -153,6 +154,7 @@
"Help": "Nápověda",
"Home page": "Domovská stránka",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Nicméně Vaše současná nastavení značí, že si nepřejete funkci povolit. Automatické hlášení pádů tedy bylo vypnuto.",
"Identification": "Identifikace",
"If untrusted, enter encryption password": "V případě nedůvěryhodnosti zadat šifrovací heslo",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Pokud chcete ostatním uživatelům tohoto počítače zabránit v přístupu k Syncthing (a skrze něj tedy ke svým souborům), zvažte nastavení ověřování se.",
"Ignore": "Ignorovat",
+3 -1
View File
@@ -18,7 +18,7 @@
"Advanced": "Avanceret",
"Advanced Configuration": "Avanceret konfiguration",
"All Data": "Alt data",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Alle mapper delt med denne enhed, skal beskyttes med adgangskode, således at alle sendte data er ikke-læsbare uden den angivne adgangskode.",
"Allow Anonymous Usage Reporting?": "Tillad anonym brugerstatistik?",
"Allowed Networks": "Tilladte netværk",
"Alphabetic": "Alfabetisk",
@@ -45,6 +45,7 @@
"Cleaning Versions": "Rydder op i versioner",
"Cleanup Interval": "Ryd op interval",
"Click to see discovery failures": "Klik for at se opdagelsesfejl",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Luk",
"Command": "Kommando",
"Comment, when used at the start of a line": "Kommentar, når den bruges i starten af en linje",
@@ -153,6 +154,7 @@
"Help": "Hjælp",
"Home page": "Hjem",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Hvis ikke troværdig, indtast krypteringsadgangskode",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignorér",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Versionen bereinigen",
"Cleanup Interval": "Bereinigungsintervall",
"Click to see discovery failures": "Klick um Gerätesuchfehler anzuzeigen",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Schließen",
"Command": "Befehl",
"Comment, when used at the start of a line": "Kommentar, wenn am Anfang der Zeile benutzt.",
@@ -153,6 +154,7 @@
"Help": "Hilfe",
"Home page": "Homepage",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Ihre aktuellen Einstellungen weisen jedoch daraufhin, dass Sie die Aktivierung möglicherweise nicht wünschen. Wir haben die automatischen Absturzberichte für Sie deaktiviert.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Wenn nicht vertraut, geben Sie das Verschlüsselungspasswort ein",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Falls Sie andere Benutzer dieses Computers daran hindern möchten auf Syncthing und somit ihren Dateien Zugriff zu haben, setzen Sie bitte einen Benutzernamen und Passwort.",
"Ignore": "Ignorieren",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Πατήστε για να δείτε τις αποτυχίες ανεύρεσης συσκευών",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Τέλος",
"Command": "Εντολή",
"Comment, when used at the start of a line": "Σχόλιο, όταν χρησιμοποιείται στην αρχή μιας γραμμής",
@@ -153,6 +154,7 @@
"Help": "Βοήθεια",
"Home page": "Αρχική σελίδα",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Ωστόσο, σύμφωνα με τις τρέχουσες ρυθμίσεις σας, μάλλον δεν επιθυμείτε αυτή τη λειτουργία. Οι αναφορές σφαλμάτων απενεργοποιήθηκαν.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Αγνόησε",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Click to see discovery failures",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Close",
"Command": "Command",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
@@ -153,6 +154,7 @@
"Help": "Help",
"Home page": "Home page",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignore",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Click to see discovery failures",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Close",
"Command": "Command",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
@@ -153,6 +154,7 @@
"Help": "Help",
"Home page": "Home page",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignore",
+13
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Click to see discovery failures",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Close",
"Command": "Command",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
@@ -93,6 +94,8 @@
"Discovered": "Discovered",
"Discovery": "Discovery",
"Discovery Failures": "Discovery Failures",
"Dismiss": "Dismiss",
"Do not add it to the ignore list, so this notification may recurr.": "Do not add it to the ignore list, so this notification may recurr.",
"Do not restore": "Do not restore",
"Do not restore all": "Do not restore all",
"Do you want to enable watching for changes for all your folders?": "Do you want to enable watching for changes for all your folders?",
@@ -153,6 +156,7 @@
"Help": "Help",
"Home page": "Home page",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignore",
@@ -225,6 +229,7 @@
"Periodic scanning at given interval and disabled watching for changes": "Periodic scanning at given interval and disabled watching for changes",
"Periodic scanning at given interval and enabled watching for changes": "Periodic scanning at given interval and enabled watching for changes",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:",
"Permanently add it to the ignore list, suppressing further notifications.": "Permanently add it to the ignore list, suppressing further notifications.",
"Permissions": "Permissions",
"Please consult the release notes before performing a major upgrade.": "Please consult the release notes before performing a major upgrade.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Please set a GUI Authentication User and Password in the Settings dialog.",
@@ -284,6 +289,8 @@
"Sharing": "Sharing",
"Show ID": "Show ID",
"Show QR": "Show QR",
"Show detailed discovery status": "Show detailed discovery status",
"Show detailed listener status": "Show detailed listener status",
"Show diff with previous version": "Show diff with previous version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
@@ -293,7 +300,9 @@
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Size": "Size",
"Smallest First": "Smallest First",
"Some discovery methods could not be established for finding other devices or announcing this device:": "Some discovery methods could not be established for finding other devices or announcing this device:",
"Some items could not be restored:": "Some items could not be restored:",
"Some listening addresses could not be enabled to accept connections:": "Some listening addresses could not be enabled to accept connections:",
"Source Code": "Source Code",
"Stable releases and release candidates": "Stable releases and release candidates",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.",
@@ -310,6 +319,8 @@
"Syncthing has been shut down.": "Syncthing has been shut down.",
"Syncthing includes the following software or portions thereof:": "Syncthing includes the following software or portions thereof:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "Syncthing is listening on the following network addresses for connection attempts from other devices:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.",
"Syncthing is restarting.": "Syncthing is restarting.",
"Syncthing is upgrading.": "Syncthing is upgrading.",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.",
@@ -334,6 +345,7 @@
"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.": "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.",
"The following items could not be synchronized.": "The following items could not be synchronized.",
"The following items were changed locally.": "The following items were changed locally.",
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "The following methods are used to discover other devices on the network and announce this device to be found by others:",
"The following unexpected items were found.": "The following unexpected items were found.",
"The interval must be a positive number of seconds.": "The interval must be a positive number of seconds.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.",
@@ -351,6 +363,7 @@
"They are retried automatically and will be synced when the error is resolved.": "They are retried automatically and will be synced when the error is resolved.",
"This Device": "This Device",
"This can easily give hackers access to read and change any files on your computer.": "This can easily give hackers access to read and change any files on your computer.",
"This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.": "This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.",
"This is a major version upgrade.": "This is a major version upgrade.",
"This setting controls the free space required on the home (i.e., index database) disk.": "This setting controls the free space required on the home (i.e., index database) disk.",
"Time": "Time",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Alklaku por vidi malsukcesajn malkovrojn",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Fermi",
"Command": "Komando",
"Comment, when used at the start of a line": "Komento, kiam uzita ĉe la komenco de lineo",
@@ -153,6 +154,7 @@
"Help": "Helpo",
"Home page": "Hejma paĝo",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignoru",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Limpiando Versiones",
"Cleanup Interval": "Intervalo de Limpieza",
"Click to see discovery failures": "Clica para ver fallos de descubrimiento.",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Cerrar",
"Command": "Acción",
"Comment, when used at the start of a line": "Comentar, cuando se usa al comienzo de una línea",
@@ -153,6 +154,7 @@
"Help": "Ayuda",
"Home page": "Página de inicio",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Sin embargo, su configuración actual indica que puede no querer habilitarlo. Hemos deshabilitado el informe automático de errores por usted.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Si no es de confianza, ingrese la contraseña de cifrado.",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Si quiere impedirle a otros usuarios de esta computadora acceder a Syncthing y, a través de este, a sus archivos, considere establecer la autenticación.",
"Ignore": "Ignorar",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Limpiando Versiones",
"Cleanup Interval": "Intervalo de Limpieza",
"Click to see discovery failures": "Clica para ver fallos de descubrimiento.",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Cerrar",
"Command": "Acción",
"Comment, when used at the start of a line": "Comentar, cuando se usa al comienzo de una línea",
@@ -153,6 +154,7 @@
"Help": "Ayuda",
"Home page": "Página de inicio",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Sin embargo, su configuración actual indica que puede no quererla activa. Hemos desactivado los informes automáticos de fallos por usted.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Si no es de confianza, introduzca la contraseña de cifrado",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Si desea evitar que otros usuarios de esta computadora accedan a Syncthing y, a través de él, a sus archivos, considere establecer la autenticación.",
"Ignore": "Ignorar",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Bertsio garbiketa",
"Cleanup Interval": "Garbiketa-tartea",
"Click to see discovery failures": "Klik egin hutsegiteak ikusteko",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Hetsi",
"Command": "Kontrolagailua",
"Comment, when used at the start of a line": "Komentarioa, lerro baten hastean delarik",
@@ -153,6 +154,7 @@
"Help": "Laguntza",
"Home page": "Harrera",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Hala ere, zure ezarpenen arabera baliteke aktibatu nahi ez izatea. Txostenen bidalketa automatikoa desaktibatu dugu zuretzat.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Fidagarria ez bada, idatzi enkriptatzeko pasahitza",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Ordenagailu honetako beste erabiltzaile batzuk Syncthing-era eta haren bidez zure fitxategietara sartzea eragotzi nahi baduzu, kontuan izan autentifikazioa konfiguratu behar duzula.",
"Ignore": "Kontuan ez hartu",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Klikkaa nähdäksesi etsinnässä tapahtuneet virheet",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Sulje",
"Command": "Komento",
"Comment, when used at the start of a line": "Kommentti, käytettäessä rivin alussa",
@@ -153,6 +154,7 @@
"Help": "Apua",
"Home page": "Kotisivu",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ohita",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Purge des versions",
"Cleanup Interval": "Intervalle de purge",
"Click to see discovery failures": "Voir les échecs de découverte",
"Click to see full identification string and QR code.": "Voir la chaîne d'identification complète et le code QR.",
"Close": "Fermer",
"Command": "Commande",
"Comment, when used at the start of a line": "Commentaire lorsque utilisé en début de ligne",
@@ -153,6 +154,7 @@
"Help": "Aide (en anglais)",
"Home page": "Page d'accueil",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Cependant, vos réglages indiquent que vous pourriez souhaiter ne pas l'activer. Nous avons désactivé pour vous l'envoi automatique des rapports.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Entrez un mot de passe pour chiffrer",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Si vous voulez empêcher d'autres utilisateurs de cet appareil à accéder à Syncthing, et via Syncthing à vos fichiers, prenez quelques secondes pour régler l'authentification. ",
"Ignore": "Refuser",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Klik om ûntdekkingsflaters te besjen",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Slute",
"Command": "Kommando",
"Comment, when used at the start of a line": "Kommentaar, wannear as brûkt by it begjin fan in rige",
@@ -153,6 +154,7 @@
"Help": "Help",
"Home page": "Hiemstee",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Lykwols, jo aktuele ynstellings litte sjen dat jo it miskien net oan sette wol. Wy hawwe automatysk rapportearjen fan fêstrinnen foar jo útsetten.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Negearje",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Tisztító verziók",
"Cleanup Interval": "Tisztítási intervallum",
"Click to see discovery failures": "Kattints ide a felfedezési hibák megtekintéséhez",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Bezárás",
"Command": "Parancs",
"Comment, when used at the start of a line": "Megjegyzés, a sor elején használva",
@@ -153,6 +154,7 @@
"Help": "Súgó",
"Home page": "Főoldal",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "A jelenlegi beállítások azonban azt jelzik, hogy nem kívánja engedélyezni. Az automatikus összeomlás-jelentés ezért letiltásra került.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Ha nem megbízható, adjon hozzá titkosítási jelszót",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Ha kívánatos, hogy a számítógép többi felhasználója ne tudja elérni a Syncthinget, sem annak fájljait, érdemes az azonosítást beállítani.",
"Ignore": "Mellőzés",
+6 -4
View File
@@ -25,7 +25,7 @@
"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.": "Il controllo versione è gestito da un comando esterno. Quest'ultimo deve rimuovere il file dalla cartella condivisa. Se il percorso dell'applicazione contiene spazi, deve essere indicato tra virgolette.",
"Anonymous Usage Reporting": "Statistiche Anonime di Utilizzo",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Il formato delle statistiche anonime di utilizzo è cambiato. Vuoi passare al nuovo formato?",
"Are you sure you want to continue?": "Are you sure you want to continue?",
"Are you sure you want to continue?": "Sei sicuro di voler continuare?",
"Are you sure you want to permanently delete all these files?": "Sei sicuro di voler eliminare definitivamente tutti questi file?",
"Are you sure you want to remove device {%name%}?": "Sei sicuro di voler rimuovere il dispositivo {{name}}?",
"Are you sure you want to remove folder {%label%}?": "Sei sicuro di voler rimuovere la cartella {{label}}?",
@@ -45,6 +45,7 @@
"Cleaning Versions": "Pulizia Versioni",
"Cleanup Interval": "Intervallo di Pulizia",
"Click to see discovery failures": "Clicca per vedere gli errori di rilevamento",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Chiudi",
"Command": "Comando",
"Comment, when used at the start of a line": "Per commentare, va inserito all'inizio di una riga",
@@ -153,6 +154,7 @@
"Help": "Aiuto",
"Home page": "Pagina home",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Tuttavia, le impostazioni correnti indicano che potresti non volerla attiva. Abbiamo disattivato la segnalazione automatica degli arresti anomali per te.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Se non attendibile, immettere la password di crittografia",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Se vuoi impedire ad altri utenti di questo computer di accedere a Syncthing e attraverso di esso ai tuoi file, prendi in considerazione la configurazione dell'autenticazione.",
"Ignore": "Ignora",
@@ -163,7 +165,7 @@
"Ignored at": "Ignorato a",
"Incoming Rate Limit (KiB/s)": "Limite Velocità in Ingresso (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Una configurazione non corretta potrebbe danneggiare il contenuto delle cartelle e rendere Syncthing inoperativo.",
"Introduced By": "Introdotto Da",
"Introduced By": "Introdotto da",
"Introducer": "Introduttore",
"Inversion of the given condition (i.e. do not exclude)": "Inversione della condizione indicata (ad es. non escludere)",
"Keep Versions": "Versioni Mantenute",
@@ -378,7 +380,7 @@
"Uptime": "Tempo di Funzionamento",
"Usage reporting is always enabled for candidate releases.": "Le segnalazioni di utilizzo sono sempre abilitate le versioni candidate al rilascio.",
"Use HTTPS for GUI": "Utilizza HTTPS per l'interfaccia grafica",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Utente/Password non sono stati impostati per l'autenticazione GUI. Considerane la configurazione.",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Utente/password non sono stati impostati per autenticazione GUI. Considerane la configurazione.",
"Version": "Versione",
"Versions": "Versioni",
"Versions Path": "Percorso Cartella Versioni",
@@ -386,7 +388,7 @@
"Waiting to Clean": "In attesa di Pulizia",
"Waiting to Scan": "In attesa di Scansione",
"Waiting to Sync": "In attesa di Sincronizzazione",
"Warning": "Warning",
"Warning": "Attenzione",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Attenzione, questo percorso è una cartella superiore di una cartella esistente \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Attenzione, questo percorso è una cartella superiore di una cartella esistente \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Attenzione, questo percorso è una sottocartella di una cartella esistente \"{{otherFolder}}\".",
+17 -15
View File
@@ -25,11 +25,11 @@
"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.": "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.",
"Anonymous Usage Reporting": "匿名での使用状況レポート",
"Anonymous usage report format has changed. Would you like to move to the new format?": "匿名での使用状況レポートのフォーマットが変わりました。新形式でのレポートに移行しますか?",
"Are you sure you want to continue?": "Are you sure you want to continue?",
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
"Are you sure you want to continue?": "続行してもよろしいですか?",
"Are you sure you want to permanently delete all these files?": "これらのファイルをすべて完全に削除してもよろしいですか?",
"Are you sure you want to remove device {%name%}?": "デバイス {{name}} を削除してよろしいですか?",
"Are you sure you want to remove folder {%label%}?": "フォルダー {{label}} を削除してよろしいですか?",
"Are you sure you want to restore {%count%} files?": "Are you sure you want to restore {{count}} files?",
"Are you sure you want to restore {%count%} files?": "{{count}} ファイルを復元してもよろしいですか?",
"Are you sure you want to upgrade?": "アップグレードしてよろしいですか?",
"Auto Accept": "自動承諾",
"Automatic Crash Reporting": "自動クラッシュレポート",
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "接続に失敗した探索サーバーを確認するにはクリックしてください",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "閉じる",
"Command": "コマンド",
"Comment, when used at the start of a line": "行頭で使用するとコメント行になります",
@@ -62,12 +63,12 @@
"Currently Shared With Devices": "現在共有中のデバイス",
"Danger!": "危険!",
"Debugging Facilities": "デバッグ機能",
"Default Configuration": "Default Configuration",
"Default Device": "Default Device",
"Default Folder": "Default Folder",
"Default Configuration": "デフォルトの設定",
"Default Device": "デフォルトのデバイス",
"Default Folder": "デフォルトのフォルダー",
"Default Folder Path": "デフォルトのフォルダーパス",
"Defaults": "Defaults",
"Delete Unexpected Items": "Delete Unexpected Items",
"Defaults": "デフォルト",
"Delete Unexpected Items": "予期しないアイテムを削除",
"Deleted": "削除",
"Deselect All": "すべて選択解除",
"Deselect devices to stop sharing this folder with.": "このフォルダの共有を停止したいデバイスがある場合は、当該デバイスの選択を解除してください。",
@@ -102,9 +103,9 @@
"Downloading": "ダウンロード中",
"Edit": "編集",
"Edit Device": "デバイスの編集",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Device Defaults": "デバイスのデフォルトの編集",
"Edit Folder": "フォルダーの編集",
"Edit Folder Defaults": "Edit Folder Defaults",
"Edit Folder Defaults": "フォルダーのデフォルトの編集",
"Editing {%path%}.": "{{path}} を編集中",
"Enable Crash Reporting": "クラッシュレポートを有効にする",
"Enable NAT traversal": "NATトラバーサルを有効にする",
@@ -153,7 +154,8 @@
"Help": "ヘルプ",
"Home page": "ホームページ",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"Identification": "Identification",
"If untrusted, enter encryption password": "信頼しない場合、暗号化パスワードを入力",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "無視",
"Ignore Patterns": "無視するファイル名",
@@ -202,7 +204,7 @@
"No File Versioning": "バージョン管理をしない",
"No files will be deleted as a result of this operation.": "この操作を行っても、ファイルが削除されることはありません。",
"No upgrades": "アップグレードしない",
"Not shared": "Not shared",
"Not shared": "非共有",
"Notice": "通知",
"OK": "OK",
"Off": "オフ",
@@ -279,7 +281,7 @@
"Share Folder": "フォルダーを共有する",
"Share Folders With Device": "このデバイスと共有するフォルダー",
"Share this folder?": "このフォルダーを共有しますか?",
"Shared Folders": "Shared Folders",
"Shared Folders": "共有中のフォルダー",
"Shared With": "共有中のデバイス",
"Sharing": "共有",
"Show ID": "IDを表示",
@@ -367,8 +369,8 @@
"Unknown": "不明",
"Unshared": "非共有",
"Unshared Devices": "非共有のデバイス",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Unshared Folders": "非共有のフォルダー",
"Untrusted": "信頼しない",
"Up to Date": "最新",
"Updated": "更新",
"Upgrade": "アップグレード",
+39 -37
View File
@@ -22,14 +22,14 @@
"Allow Anonymous Usage Reporting?": "익명 사용 보고서를 보내시겠습니까?",
"Allowed Networks": "허가된 네트워크",
"Alphabetic": "알파벳순",
"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.": "외부 커맨드가 파일 버전을 관리합니다. 공유 폴더에서 파일을 삭제해야 합니다. 응용 프로그램의 경로에 공백이 있으면 따옴표로 묶어야합니다.",
"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.": "외부 명령이 파일 버전을 관리합니다. 공유 폴더에서 파일을 삭제해야 합니다. 응용 프로그램의 경로에 공백이 있으면 따옴표로 묶어야 합니다.",
"Anonymous Usage Reporting": "익명 사용 보고서",
"Anonymous usage report format has changed. Would you like to move to the new format?": "익명 사용 리포트의 형식이 변경되었습니다. 새 형식으로 이동 하시겠습니까?",
"Are you sure you want to continue?": "Are you sure you want to continue?",
"Are you sure you want to permanently delete all these files?": "Are you sure you want to permanently delete all these files?",
"Are you sure you want to remove device {%name%}?": "{{name}} 기기를 정말로 제거하시겠습니까?",
"Are you sure you want to remove folder {%label%}?": "{{label}} 폴더를 제거 하시겠습니까?",
"Are you sure you want to restore {%count%} files?": "{{count}} 개의 파일을 복원 하시겠습니까?",
"Are you sure you want to continue?": "계속하시겠습니까?",
"Are you sure you want to permanently delete all these files?": "모든 파일을 영구 삭제하시겠습니까?",
"Are you sure you want to remove device {%name%}?": "{{name}} 기기를 제거하시겠습니까?",
"Are you sure you want to remove folder {%label%}?": "{{label}} 폴더를 제거하시겠습니까?",
"Are you sure you want to restore {%count%} files?": "{{count}} 개의 파일을 복원하시겠습니까?",
"Are you sure you want to upgrade?": "업그레이드를 하시겠습니까?",
"Auto Accept": "자동 수락",
"Automatic Crash Reporting": "자동 충돌 보고",
@@ -45,6 +45,7 @@
"Cleaning Versions": "버전 정리 중",
"Cleanup Interval": "정리 간격",
"Click to see discovery failures": "탐색 실패 보기",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "닫기",
"Command": "커맨드",
"Comment, when used at the start of a line": "명령행에서 시작을 할수 있어요.",
@@ -58,16 +59,16 @@
"Copied from elsewhere": "다른 곳에서 복사됨",
"Copied from original": "원본에서 복사됨",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "무시 패턴 만들기, {{path}}에 존재하는 파일을 덮어쓰기 합니다",
"Currently Shared With Devices": "현재 공유된 기기",
"Danger!": "경고!",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "무시 패턴 생성 중, {{path}}에 존재하는 파일을 덮어니다.",
"Currently Shared With Devices": "현재 공유된 기기",
"Danger!": "위험!",
"Debugging Facilities": "디버깅 기능",
"Default Configuration": "기본 설정",
"Default Device": "기본 기기",
"Default Folder": "기본 폴더",
"Default Folder Path": "기본 폴더 경로",
"Defaults": "기본 설정",
"Delete Unexpected Items": "Delete Unexpected Items",
"Delete Unexpected Items": "예기치 못한 항목 삭제",
"Deleted": "삭제됨",
"Deselect All": "모두 선택 해제",
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
@@ -77,8 +78,8 @@
"Device ID": "기기 ID",
"Device Identification": "기기 식별자",
"Device Name": "기기 이름",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device rate limits": "Device rate limits",
"Device is untrusted, enter encryption password": "신뢰하지 않는 기기, 암호화 비밀번호를 입력하세요",
"Device rate limits": "기기 속도 제한",
"Device that last modified the item": "항목을 마지막으로 수정 한 기기",
"Devices": "기기",
"Disable Crash Reporting": "충돌 보고 해제",
@@ -87,7 +88,7 @@
"Disabled periodic scanning and enabled watching for changes": "주기적 탐색을 사용 중지하고 변경 사항 감시 하기",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).",
"Discard": "Discard",
"Discard": "무시",
"Disconnected": "연결 끊김",
"Disconnected (Unused)": "연결 해제됨 (미사용)",
"Discovered": "탐색됨",
@@ -118,7 +119,7 @@
"Error": "오류",
"External File Versioning": "외부 파일 버전 관리",
"Failed Items": "실패한 항목",
"Failed to setup, retrying": "Failed to setup, retrying",
"Failed to setup, retrying": "설정 적용 실패, 재시도 중",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "IPv6 네트워크에 연결되지 않은 경우 IPv6 서버에 연결 할 수 없습니다.",
"File Pull Order": "파일 동기화 순서",
"File Versioning": "파일 버전 관리",
@@ -153,10 +154,11 @@
"Help": "도움말",
"Home page": "홈페이지",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"Identification": "Identification",
"If untrusted, enter encryption password": "신뢰하지 않는 경우 암호화 비밀번호를 입력하세요",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "무시",
"Ignore Patterns": "패턴 무시",
"Ignore Patterns": "무시 패턴",
"Ignore Permissions": "권한 무시",
"Ignored Devices": "무시된 기기",
"Ignored Folders": "무시된 폴더",
@@ -173,15 +175,15 @@
"Last seen": "마지막 접속",
"Latest Change": "최신 변경",
"Learn more": "더 알아보기",
"Limit": "Limit",
"Limit": "제한",
"Listeners": "수신자",
"Loading data...": "데이터 불러오는중...",
"Loading...": "불러오는 중...",
"Local Additions": "로컬 변경사항",
"Local Additions": "로컬 변경 항목",
"Local Discovery": "로컬 노드 검색",
"Local State": "로컬 상태",
"Local State (Total)": "로컬 상태 (합계)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "로컬 변경 항목",
"Log": "기록",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "기록",
@@ -238,7 +240,7 @@
"Random": "무작위",
"Receive Encrypted": "암호화 수신",
"Receive Only": "수신 전용",
"Received data is already encrypted": "Received data is already encrypted",
"Received data is already encrypted": "수신된 데이터는 이미 암호화되어 있습니다",
"Recent Changes": "최근 변경",
"Reduced by ignore patterns": "무시 패턴으로 축소",
"Release Notes": "릴리즈 노트",
@@ -260,7 +262,7 @@
"Resume": "재개",
"Resume All": "모두 재개",
"Reused": "재개",
"Revert Local Changes": "로컬 변경사항",
"Revert Local Changes": "로컬 변경 항목",
"Save": "저장",
"Scan Time Remaining": "탐색 남은 시간",
"Scanning": "탐색 중",
@@ -268,7 +270,7 @@
"Select All": "모두 선택",
"Select a version": "버전 선택",
"Select additional devices to share this folder with.": "이 폴더를 추가로 공유할 기기를 선택하세요.",
"Select additional folders to share with this device.": "Select additional folders to share with this device.",
"Select additional folders to share with this device.": "이 기기와 공유할 추가 폴더를 선택하세요.",
"Select latest version": "가장 최신 버전 선택",
"Select oldest version": "가장 오래된 버전 선택",
"Select the folders to share with this device.": "이 기기와 공유할 폴더를 선택합니다.",
@@ -333,8 +335,8 @@
"The folder path cannot be blank.": "폴더 경로는 비워 둘 수 없습니다.",
"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.": "다음과 같은 간격이 사용됩니다: 첫 한 시간 동안은 버전이 매 30초마다 유지되며, 첫 하루 동안은 매 시간, 첫 한 달 동안은 매 일마다 유지됩니다. 그리고 최대 날짜까지는 버전이 매 주마다 유지됩니다.",
"The following items could not be synchronized.": "이 항목들은 동기화 할 수 없습니다.",
"The following items were changed locally.": "The following items were changed locally.",
"The following unexpected items were found.": "The following unexpected items were found.",
"The following items were changed locally.": "다음 로컬 변경 항목이 발견되었습니다.",
"The following unexpected items were found.": "예기치 못한 항목이 발견되었습니다.",
"The interval must be a positive number of seconds.": "간격은 초 단위의 자연수여야 합니다.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.",
"The maximum age must be a number and cannot be blank.": "최대 보존 기간은 숫자여야 하며 비워 둘 수 없습니다.",
@@ -347,7 +349,7 @@
"The rate limit must be a non-negative number (0: no limit)": "대역폭 제한 설정은 반드시 양수로 입력해야 합니다 (0: 무제한)",
"The rescan interval must be a non-negative number of seconds.": "재탐색 간격은 초단위이며 양수로 입력해야 합니다.",
"There are no devices to share this folder with.": "이 폴더를 공유할 기기가 없습니다.",
"There are no folders to share with this device.": "There are no folders to share with this device.",
"There are no folders to share with this device.": "이 기기와 공유할 폴더가 없습니다.",
"They are retried automatically and will be synced when the error is resolved.": "오류가 해결되면 자동적으로 동기화 됩니다.",
"This Device": "현재 기기",
"This can easily give hackers access to read and change any files on your computer.": "이 설정은 해커가 손쉽게 사용자 컴퓨터의 모든 파일을 읽고 변경할 수 있도록 할 수 있습니다.",
@@ -361,14 +363,14 @@
"Unavailable": "불가능",
"Unavailable/Disabled by administrator or maintainer": "운영자 또는 관리자에 의해 불가능/비활성화 됨",
"Undecided (will prompt)": "Undecided (will prompt)",
"Unexpected Items": "Unexpected Items",
"Unexpected items have been found in this folder.": "Unexpected items have been found in this folder.",
"Unignore": "Unignore",
"Unexpected Items": "예기치 못한 항목",
"Unexpected items have been found in this folder.": "이 폴더에 예기치 못한 항목이 발견되었습니다.",
"Unignore": "무시 취소",
"Unknown": "알 수 없음",
"Unshared": "공유되지 않음",
"Unshared Devices": "공유되지 않은 기기",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Unshared Folders": "공유되지 않은 폴더",
"Untrusted": "신뢰하지 않음",
"Up to Date": "최신 데이터",
"Updated": "업데이트 완료",
"Upgrade": "업데이트",
@@ -386,12 +388,12 @@
"Waiting to Clean": "정리 대기 중",
"Waiting to Scan": "탐색 대기 중",
"Waiting to Sync": "동기화 대기 중",
"Warning": "Warning",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "경고, 이 경로는 현재 존재하는 폴더 \"{{otherFolder}}\" 의 상위 폴더 입니다.",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "경고, 이 경로는 현재 존재하는 폴더 \"{{otherFolderLabel}}\" ({{otherFolder}}) 의 상위 폴더 입니다.",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "경고, 이 경로는 현재 존재하는 폴더 \"{{otherFolder}}\" 의 하위 폴더 입니다.",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "경고, 이 경로는 현재 존재하는 폴더 \"{{otherFolderLabel}}\" ({{otherFolder}}) 의 하위 폴더 입니다.",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "경고 : {{syncthingInotify}} 와 같은 외부 감시 도구를 사용하는 경우 비활성화되어 있는지 확인해야 합니다.",
"Warning": "경고",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "경고 : 이 경로는 현재 존재하는 폴더 \"{{otherFolder}}\"의 상위 폴더입니다.",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "경고 : 이 경로는 현재 존재하는 폴더 \"{{otherFolderLabel}}\" ({{otherFolder}})의 상위 폴더입니다.",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "경고 : 이 경로는 현재 존재하는 폴더 \"{{otherFolder}}\"의 하위 폴더입니다.",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "경고 : 이 경로는 현재 존재하는 폴더 \"{{otherFolderLabel}}\" ({{otherFolder}})의 하위 폴더입니다.",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "경고 : {{syncthingInotify}}와 같은 외부 감시 도구를 사용하는 경우 비활성화되어 있는지 확인해야 합니다.",
"Watch for Changes": "변경 사항 감시",
"Watching for Changes": "변경 사항 감시",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
@@ -402,7 +404,7 @@
"You can change your choice at any time in the Settings dialog.": "설정창 에서 언제든지 원하시는 때에 설정을 변경하는 것이 가능합니다.",
"You can read more about the two release channels at the link below.": "이 두 개의 출시 채널에 대해 아래 링크에서 자세하게 읽어 보실 수 있습니다.",
"You have no ignored devices.": "무시된 기기가 없습니다.",
"You have no ignored folders.": "You have no ignored folders.",
"You have no ignored folders.": "무시된 폴더가 없습니다.",
"You have unsaved changes. Do you really want to discard them?": "저장되지 않은 변경이 있습니다. 변경사항을 무시하시겠습니까?",
"You must keep at least one version.": "최소 한 개의 버전은 유지해야 합니다.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "You should never add or change anything locally in a \"{{receiveEncrypted}}\" folder.",
+4 -2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Spustelėkite, norėdami pamatyti matomumo nesėkmes",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Užverti",
"Command": "Komanda",
"Comment, when used at the start of a line": "Komentaras naudojamas naujoje eilutėje",
@@ -153,6 +154,7 @@
"Help": "Pagalba",
"Home page": "Pagrindinis puslapis",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Vis dėlto, jūsų esami nustatymai nurodo, kad jūs, greičiausiai, nenorite turėti jas įjungtas. Mes jums išjungėme automatines ataskaitas apie strigtis.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Jei norite neleisti kitiems šio kompiuterio vartotojams gauti prieigą prie Syncthing, o per ją, prieigą prie jūsų failų, tuomet apsvarstykite galimybę nusistatyti tapatybės nustatymą.",
"Ignore": "Nepaisyti",
@@ -361,8 +363,8 @@
"Unavailable": "Neprieinama",
"Unavailable/Disabled by administrator or maintainer": "Neprieinama/Išjungta administratoriaus ar prižiūrėtojo",
"Undecided (will prompt)": "Nenuspręsta (bus klausiama)",
"Unexpected Items": "Unexpected Items",
"Unexpected items have been found in this folder.": "Unexpected items have been found in this folder.",
"Unexpected Items": "Netikėti elementai",
"Unexpected items have been found in this folder.": "Šiame aplanke rasta netikėtų elementų.",
"Unignore": "Nustoti nepaisyti",
"Unknown": "Nežinoma",
"Unshared": "Nesidalinama",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Klikk for å se oppslagsfeil",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Lukk",
"Command": "Kommando",
"Comment, when used at the start of a line": "Kommentar, når det blir brukt i starten av en linje.",
@@ -153,6 +154,7 @@
"Help": "Hjelp",
"Home page": "Hjemmeside",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignorer",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Versies opruimen",
"Cleanup Interval": "Opruiminterval",
"Click to see discovery failures": "Klikken om detectieproblemen weer te geven",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Sluiten",
"Command": "Opdracht",
"Comment, when used at the start of a line": "Opmerking, wanneer gebruikt aan het begin van een regel",
@@ -153,6 +154,7 @@
"Help": "Help",
"Home page": "Startpagina",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Uw huidige instellingen geven echter aan dat u het misschien niet wilt inschakelen. We hebben de automatische crashrapportage voor u uitgeschakeld.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Indien niet vertrouwd, versleutelingswachtwoord opgeven",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Als u wilt voorkomen dat andere gebruikers op deze computer toegang krijgen tot Syncthing en daardoor uw bestanden, kunt u overwegen om authenticatie in te stellen.",
"Ignore": "Negeren",
+4 -2
View File
@@ -18,7 +18,7 @@
"Advanced": "Zaawansowane",
"Advanced Configuration": "Zaawansowane ustawienia",
"All Data": "Wszystkie dane",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Wszystkie foldery współdzielone z tym urządzeniem muszą być zabezpieczone hasłem, tak aby żadne przesyłane dane nie były możliwe do odczytu bez podania tego hasła.",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Wszystkie foldery współdzielone z tym urządzeniem muszą być zabezpieczone hasłem, tak aby wszystkie przesyłane dane były nie do odczytu bez podania danego hasła.",
"Allow Anonymous Usage Reporting?": "Czy chcesz zezwolić na anonimowe statystyki użycia?",
"Allowed Networks": "Dozwolone sieci",
"Alphabetic": "Alfabetycznie",
@@ -45,6 +45,7 @@
"Cleaning Versions": "Czyszczenie wersji",
"Cleanup Interval": "Przedział czasowy czyszczenia",
"Click to see discovery failures": "Kliknij tutaj, aby zobaczyć błędy odnajdywania",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Zamknij",
"Command": "Polecenie",
"Comment, when used at the start of a line": "Komentarz, jeżeli znajduje się na początku linii",
@@ -58,7 +59,7 @@
"Copied from elsewhere": "Skopiowane z innego miejsca ",
"Copied from original": "Skopiowane z oryginału",
"Copyright © 2014-2019 the following Contributors:": "Wszelkie prawa zastrzeżone © 2014-2019 dla współtwórców:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Ustawianie wzorów ignorowania, nadpisze istniejący plik w {{path}}.",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Tworzenie wzorów ignorowania, nadpisze istniejący plik w {{path}}.",
"Currently Shared With Devices": "Obecnie współdzielony z urządzeniami",
"Danger!": "Niebezpieczeństwo!",
"Debugging Facilities": "Narzędzia do debugowania",
@@ -153,6 +154,7 @@
"Help": "Pomoc",
"Home page": "Strona domowa",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Niemniej jednak, obecne ustawienia wskazują, że możesz nie chcieć włączać tej funkcji. Automatyczne zgłaszanie awarii zostało wyłączone na tym urządzeniu.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Jeżeli folder jest niezaufany, wprowadź szyfrujące hasło",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Jeżeli chcesz zakazać innym użytkownikom tego komputera dostępu do Syncthing, a przez niego do swoich plików, zastanów się nad włączeniem uwierzytelniania.",
"Ignore": "Ignoruj",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Limpando Versões",
"Cleanup Interval": "Intervalo de Limpeza",
"Click to see discovery failures": "Clique para ver as falhas na descoberta de dispositivos",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Fechar",
"Command": "Comando",
"Comment, when used at the start of a line": "Comentário, se usado no início de uma linha",
@@ -153,6 +154,7 @@
"Help": "Ajuda",
"Home page": "Página inicial",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Se o dispositivo não é confiável, digite a senha de criptografia",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignorar",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Limpando versões",
"Cleanup Interval": "Intervalo entre limpezas",
"Click to see discovery failures": "Clique para ver as falhas da pesquisa",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Fechar",
"Command": "Comando",
"Comment, when used at the start of a line": "Comentário, quando usado no início de uma linha",
@@ -153,6 +154,7 @@
"Help": "Ajuda",
"Home page": "Página do projecto",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Contudo, a sua configuração actual indica que pode não a querer activada. Nós desactivámos automaticamente o relatório de estouro para si.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Se não for fiável, insira uma senha de encriptação",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Se quiser evitar que outros utilizadores neste computador acedam ao Syncthing e, através dele, aos seus ficheiros, considere configurar a autenticação.",
"Ignore": "Ignorar",
+13 -11
View File
@@ -42,9 +42,10 @@
"Bugs": "Ошибки",
"Changelog": "Журнал изменений",
"Clean out after": "Очистить после",
"Cleaning Versions": "Cleaning Versions",
"Cleaning Versions": "Очистка Версий",
"Cleanup Interval": "Интервал очистки",
"Click to see discovery failures": "Щёлкните, чтобы посмотреть ошибки",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Закрыть",
"Command": "Команда",
"Comment, when used at the start of a line": "Комментарий, если используется в начале строки",
@@ -77,7 +78,7 @@
"Device ID": "ID устройства",
"Device Identification": "Идентификация устройства",
"Device Name": "Имя устройства",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device is untrusted, enter encryption password": "Устройство ненадёжно, укажите пароль шифрования",
"Device rate limits": "Ограничения скорости для устройства",
"Device that last modified the item": "Устройство, последним изменившее объект",
"Devices": "Устройства",
@@ -102,9 +103,9 @@
"Downloading": "Загрузка",
"Edit": "Редактировать",
"Edit Device": "Редактирование устройства",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Device Defaults": "Изменить умолчания устройства",
"Edit Folder": "Редактирование папки",
"Edit Folder Defaults": "Edit Folder Defaults",
"Edit Folder Defaults": "Изменить умолчания папки",
"Editing {%path%}.": "Правка {{path}}.",
"Enable Crash Reporting": "Включить отчёты о сбоях",
"Enable NAT traversal": "Включить NAT traversal",
@@ -134,8 +135,8 @@
"Folder Label": "Ярлык папки",
"Folder Path": "Путь к папке",
"Folder Type": "Тип папки",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Folder type \"{{receiveEncrypted}}\" can only be set when adding a new folder.",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Folder type \"{{receiveEncrypted}}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Тип папки \"{{receiveEncrypted}}\" может быть указан только при создании новой.",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Тип папки \"{{receiveEncrypted}}\" не может быть изменён после добавления. Вам необходимо убрать папку, удалить или дешифровать данные на диске, а затем добавить папку заново.",
"Folders": "Папки",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "Для следующих папок произошла ошибка при запуске отслеживания изменений. Попытки будут повторяться раз в минуту, и ошибки скоро могут быть устранены. Если этого не произойдёт, попробуйте разобраться в причинах и попросите поддержки, если у вас не получится.",
"Full Rescan Interval (s)": "Интервал полного сканирования (в секундах)",
@@ -153,7 +154,8 @@
"Help": "Помощь",
"Home page": "Сайт",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Ваши настройки указывают что вы не хотите, чтобы эта функция была включена. Мы отключили отправку отчетов о сбоях.",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"Identification": "Identification",
"If untrusted, enter encryption password": "Если ненадёжное, укажите пароль шифрования",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Если вы хотите запретить другим пользователям на этом компьютере доступ к Syncthing и через него к вашим файлам, подумайте о настройке аутентификации.",
"Ignore": "Игнорировать",
"Ignore Patterns": "Шаблоны игнорирования",
@@ -328,8 +330,8 @@
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Введён недопустимый ID устройства. Он должен состоять из букв и цифр, может включать пробелы и дефисы, длина должна быть 52 или 56 символов.",
"The folder ID cannot be blank.": "ID папки не может быть пустым.",
"The folder ID must be unique.": "ID папки должен быть уникальным.",
"The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.",
"The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "Содержание папки на других устройствах будет перезаписано и станет идентично этому устройству. Файлы, отсутствующие здесь, будут удалены на других устройствах.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "Содержание папки на этом устройстве будет перезаписано и станет идентично другим устройствам. Новые файлы на этом устройстве будут удалены.",
"The folder path cannot be blank.": "Путь к папке не должен быть пустым.",
"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.": "Используются следующие интервалы: в первый час версия меняется каждые 30 секунд, в первый день - каждый час, первые 30 дней - каждый день, после, до максимального срока - каждую неделю.",
"The following items could not be synchronized.": "Невозможно синхронизировать следующие объекты",
@@ -368,7 +370,7 @@
"Unshared": "Необщедоступно",
"Unshared Devices": "Устройства без общего доступа",
"Unshared Folders": "Необщедоступные папки",
"Untrusted": "Untrusted",
"Untrusted": "Ненадёжный",
"Up to Date": "В актуальном состоянии",
"Updated": "Обновлено",
"Upgrade": "Обновить",
@@ -414,5 +416,5 @@
"seconds": "сек.",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} хочет поделиться папкой «{{folder}}».",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} хочет поделиться папкой «{{folderlabel}}» ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} might reintroduce this device."
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} может повторно рекомендовать это устройство."
}
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Interval čistenia",
"Click to see discovery failures": "Kliknite pre zobrazenie zlyhaní zisťovania.",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Zatvoriť",
"Command": "Príkaz",
"Comment, when used at the start of a line": "Komentár, keď použité na začiatku riadku",
@@ -153,6 +154,7 @@
"Help": "Pomoc",
"Home page": "Domovská stránka",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Ak nie je dôveryhodný, uveďte heslo na dešifrovanie",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.",
"Ignore": "Ignorovať",
+4 -2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Rensningsversioner",
"Cleanup Interval": "Rensningsintervall",
"Click to see discovery failures": "Klicka för att se upptäcktsmisslyckanden",
"Click to see full identification string and QR code.": "Klicka för att se fullständig identifieringssträng och QR-kod.",
"Close": "Stäng",
"Command": "Kommando",
"Comment, when used at the start of a line": "Kommentara, vid användning i början av en rad.",
@@ -153,6 +154,7 @@
"Help": "Hjälp",
"Home page": "Webbplats",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Dina aktuella inställningar visar dock att du kanske inte vill att den ska aktiveras. Vi har inaktiverat automatisk krasch rapportering för dig.",
"Identification": "Identifiering",
"If untrusted, enter encryption password": "Om opålitlig, ange krypteringslösenord",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Om du vill förhindra att andra användare på denna dator får åtkomst till Syncthing och genom det dina filer, överväg att ställa in autentisering.",
"Ignore": "Ignorera",
@@ -161,7 +163,7 @@
"Ignored Devices": "Ignorerade enheter",
"Ignored Folders": "Ignorerade mappar",
"Ignored at": "Ignorerad vid",
"Incoming Rate Limit (KiB/s)": "Inkommande hastighetsbegränsning (KiB/s)",
"Incoming Rate Limit (KiB/s)": "Inkommande hastighetsgräns (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Inkorrekt konfiguration kan skada innehållet i mappen and få Syncthing att sluta fungera.",
"Introduced By": "Introducerad av",
"Introducer": "Introduktör",
@@ -211,7 +213,7 @@
"Options": "Alternativ",
"Out of Sync": "Osynkroniserad",
"Out of Sync Items": "Osynkroniserade objekt",
"Outgoing Rate Limit (KiB/s)": "Utgående hastighetsbegränsning (KiB/s)",
"Outgoing Rate Limit (KiB/s)": "Utgående hastighetsgräns (KiB/s)",
"Override Changes": "Åsidosätt förändringar",
"Path": "Sökväg",
"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": "Sökväg till mappen på din dator. Kommer att skapas om det inte finns. Tecknet tilde (~) kan användas som en genväg för",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Sürümleri Temizleme",
"Cleanup Interval": "Aralığı Temizle",
"Click to see discovery failures": "Keşif hatalarını görmek için tıklayın",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Kapat",
"Command": "Komut",
"Comment, when used at the start of a line": "Açıklama, bir satırın başında kullanıldığında",
@@ -153,6 +154,7 @@
"Help": "Yardım",
"Home page": "Ana Sayfa",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Ancak, şu anki ayarlarınız etkinleştirilmesini istemediğinizi gösterir. Sizin için otomatik çökme bildirmeyi etkisizleştirdik.",
"Identification": "Identification",
"If untrusted, enter encryption password": "Eğer güvenilmezse, şifreleme parolasını girin",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Eğer bu bilgisayardaki diğer kullanıcıların Syncthing'e ve onun aracılığıyla dosyalarınıza erişmesini önlemek istiyorsanız, kimlik doğrulamasını ayarlamayı düşünün.",
"Ignore": "Yoksay",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "Очищення версій",
"Cleanup Interval": "Інтервал очищення",
"Click to see discovery failures": "Клікніть, щоб переглянути помилки виявлення",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "Закрити",
"Command": "Команда",
"Comment, when used at the start of a line": "Коментар, якщо використовується на початку рядка",
@@ -153,6 +154,7 @@
"Help": "Допомога",
"Home page": "Домашня сторінка",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Однак ваші поточні налаштування вказують, що ви, можливо, не хочете, щоб це було ввімкнено. Ми відключили автоматичне повідомлення про аварійне завершення роботи.",
"Identification": "Identification",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Якщо ви хочете заборонити іншим користувачам цього комп’ютера отримувати доступ до Syncthing і через нього до своїх файлів, подумайте про налаштування автентифікації.",
"Ignore": "Ігнорувати",
+39 -37
View File
@@ -1,6 +1,6 @@
{
"A device with that ID is already added.": "您已添加过相同 ID 的设备",
"A negative number of days doesn't make sense.": "负数天数没有意义。",
"A negative number of days doesn't make sense.": "天数不能为负。",
"A new major version may not be compatible with previous versions.": "重大更新可能与之前的版本之间无法兼容",
"API Key": "API Key",
"About": "关于",
@@ -18,14 +18,14 @@
"Advanced": "高级",
"Advanced Configuration": "高级配置",
"All Data": "所有数据",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "与此设备共享的所有文件夹都必须有密码保护,这样所有发送的数据在没有密码的情况下是不可读的。",
"Allow Anonymous Usage Reporting?": "允许匿名使用报告?",
"Allowed Networks": "允许的网络",
"Alphabetic": "字母顺序",
"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.": "外部命令接管了版本控制。该外部命令必须自行从共享文件夹中删除该文件。如果此应用程序的路径包含空格,应该用半角引号括起来。",
"Anonymous Usage Reporting": "匿名使用报告",
"Anonymous usage report format has changed. Would you like to move to the new format?": "匿名使用情况的报告格式已经变更。是否要迁移到新的格式?",
"Are you sure you want to continue?": "Are you sure you want to continue?",
"Are you sure you want to continue?": "您确定要继续吗?",
"Are you sure you want to permanently delete all these files?": "确认要永久删除这些文件吗?",
"Are you sure you want to remove device {%name%}?": "您确定要移除设备 {{name}} 吗?",
"Are you sure you want to remove folder {%label%}?": "您确定要移除文件夹 {{label}} 吗?",
@@ -45,6 +45,7 @@
"Cleaning Versions": "清除版本",
"Cleanup Interval": "清除间隔",
"Click to see discovery failures": "点击查看设备发现错误",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "关闭",
"Command": "命令",
"Comment, when used at the start of a line": "注释,在行首使用",
@@ -55,23 +56,23 @@
"Connection Type": "连接类型",
"Connections": "连接",
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Syncthing 现在可以持续监视更改了。这将检测磁盘上的更改,然后对有修改的路径发起扫描。这样的好处是更改可以更快地传播,且需要的完整扫描会更少。",
"Copied from elsewhere": "从其设备复制",
"Copied from elsewhere": "从其设备复制",
"Copied from original": "从源复制",
"Copyright © 2014-2019 the following Contributors:": "版权所有 © 2014-2019 以下贡献者:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "正在创建忽略模式,覆盖位于 {{path}} 的已有文件。",
"Currently Shared With Devices": "当前设备已共享",
"Danger!": "危险!",
"Debugging Facilities": "调试功能",
"Default Configuration": "Default Configuration",
"Default Device": "Default Device",
"Default Folder": "Default Folder",
"Default Configuration": "默认配置",
"Default Device": "默认设备",
"Default Folder": "默认文件夹",
"Default Folder Path": "默认文件夹路径",
"Defaults": "Defaults",
"Delete Unexpected Items": "Delete Unexpected Items",
"Defaults": "默认值",
"Delete Unexpected Items": "删除特殊项目",
"Deleted": "已删除",
"Deselect All": "取消全选",
"Deselect devices to stop sharing this folder with.": "反选设备以停止共享此文件夹",
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
"Deselect folders to stop sharing with this device.": "取消选择文件夹以停止与此设备共享。",
"Device": "设备",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "设备 \"{{name}}\"(位于 {{address}} 的 {{device}})请求连接。是否添加新设备?",
"Device ID": "设备 ID",
@@ -102,9 +103,9 @@
"Downloading": "下载中",
"Edit": "选项",
"Edit Device": "编辑设备",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Device Defaults": "编辑设备默认值",
"Edit Folder": "编辑文件夹",
"Edit Folder Defaults": "Edit Folder Defaults",
"Edit Folder Defaults": "编辑文件夹默认值",
"Editing {%path%}.": "正在编辑 {{path}}。",
"Enable Crash Reporting": "启用自动发送崩溃报告",
"Enable NAT traversal": "启用 NAT 遍历",
@@ -134,11 +135,11 @@
"Folder Label": "文件夹标签",
"Folder Path": "文件夹路径",
"Folder Type": "文件夹类型",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Folder type \"{{receiveEncrypted}}\" can only be set when adding a new folder.",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Folder type \"{{receiveEncrypted}}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "只能在添加新文件夹时设置文件夹类型{{receiveEncrypted}}",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "添加文件夹后,无法更改文件夹类型“ {{receiveEncrypted}}”。您需要删除该文件夹,删除或解密磁盘上的数据,然后再次添加该文件夹。",
"Folders": "文件夹",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "开始监视下列文件夹时发生错误。由于每分钟都会重试,所以错误可能很快就消失。如果它们仍存在,请试着修复潜在问题,如不会则请求帮助。",
"Full Rescan Interval (s)": "完整扫描间隔",
"Full Rescan Interval (s)": "完整扫描间隔(秒)",
"GUI": "图形用户界面",
"GUI Authentication Password": "图形管理界面密码",
"GUI Authentication User": "图形管理界面用户名",
@@ -153,7 +154,8 @@
"Help": "帮助",
"Home page": "主页",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "我们已经为您关闭了自动崩溃报告发送功能,因为您当前的设置显示您可能并不想启用该功能。",
"If untrusted, enter encryption password": "If untrusted, enter encryption password",
"Identification": "Identification",
"If untrusted, enter encryption password": "如想更安全,请输入加密密码",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "如果要阻止此计算机上的其他用户访问Syncthing并通过它访问文件,请考虑设置身份验证。",
"Ignore": "忽略",
"Ignore Patterns": "忽略模式",
@@ -165,7 +167,7 @@
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "错误的配置可能损坏您文件夹内的内容,使得 Syncthing 无法工作。",
"Introduced By": "介绍自",
"Introducer": "作为中介",
"Inversion of the given condition (i.e. do not exclude)": "本条件取反(例如:不排除某项",
"Inversion of the given condition (i.e. do not exclude)": "反转本条件(即:不排除)",
"Keep Versions": "保留版本数量",
"LDAP": "LDAP",
"Largest First": "大文件优先",
@@ -202,7 +204,7 @@
"No File Versioning": "不启用版本控制",
"No files will be deleted as a result of this operation.": "此操作结果不会删除任何文件。",
"No upgrades": "无更新",
"Not shared": "Not shared",
"Not shared": "不共享",
"Notice": "提示",
"OK": "确定",
"Off": "关闭",
@@ -236,15 +238,15 @@
"Preview Usage Report": "预览使用报告",
"Quick guide to supported patterns": "支持的通配符的简单教程:",
"Random": "随机顺序",
"Receive Encrypted": "Receive Encrypted",
"Receive Encrypted": "加密接收",
"Receive Only": "仅接收",
"Received data is already encrypted": "Received data is already encrypted",
"Received data is already encrypted": "已加密接收到的数据",
"Recent Changes": "最近更改",
"Reduced by ignore patterns": "已由忽略模式缩减",
"Release Notes": "发布说明",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "发布候选版包含最新的特性和修复。它们跟传统的 Syncthing 双周发布版类似。",
"Remote Devices": "远程设备",
"Remote GUI": "Remote GUI",
"Remote GUI": "远程GUI",
"Remove": "移除",
"Remove Device": "移除设备",
"Remove Folder": "移除文件夹",
@@ -268,7 +270,7 @@
"Select All": "全选",
"Select a version": "选择版本",
"Select additional devices to share this folder with.": "选择其他共享此文件夹的设备",
"Select additional folders to share with this device.": "Select additional folders to share with this device.",
"Select additional folders to share with this device.": "选择要与此设备共享的其它文件夹。",
"Select latest version": "选择最新的版本",
"Select oldest version": "选择最旧的版本",
"Select the folders to share with this device.": "选择与该设备共享的文件夹。",
@@ -279,7 +281,7 @@
"Share Folder": "共享文件夹",
"Share Folders With Device": "将指定文件夹共享给设备",
"Share this folder?": "是否共享该文件夹?",
"Shared Folders": "Shared Folders",
"Shared Folders": "共享文件夹",
"Shared With": "共享给",
"Sharing": "共享",
"Show ID": "显示 ID",
@@ -302,7 +304,7 @@
"Start Browser": "启动浏览器",
"Statistics": "统计",
"Stopped": "已停止",
"Stores and syncs only encrypted data. Folders on all connected devices need to be set up with the same password or be of type \"{%receiveEncrypted%}\" too.": "Stores and syncs only encrypted data. Folders on all connected devices need to be set up with the same password or be of type \"{{receiveEncrypted}}\" too.",
"Stores and syncs only encrypted data. Folders on all connected devices need to be set up with the same password or be of type \"{%receiveEncrypted%}\" too.": "仅存储和同步加密的数据。所有连接的设备上的文件夹也需要使用相同的密码设置,或者也必须设置为“ {{receiveEncrypted}}”类型。",
"Support": "支持",
"Support Bundle": "支持捆绑包",
"Sync Protocol Listen Addresses": "协议监听地址",
@@ -328,13 +330,13 @@
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "输入的设备 ID 似乎无效。设备 ID 包含字母和数字,长度为 52 或 56,空格和横线不计在内。",
"The folder ID cannot be blank.": "文件夹 ID 不能为空。",
"The folder ID must be unique.": "文件夹 ID 不得重复。",
"The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.",
"The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "其它设备上的文件夹内容将被覆盖,以与此设备相同。此处不存在的文件将在其他设备上删除。",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "该设备上的文件夹内容将被覆盖,使其与其他设备相同。在此处新添加的文件将被删除。",
"The folder path cannot be blank.": "文件夹路径不能为空。",
"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.": "保留的历史版本会遵循以下条件:最近一小时内的历史版本,更新间隔小于三十秒的仅保留一份。最近一天内的历史版本,更新间隔小于一小时的仅保留一份。最近一个月内的历史版本,更新间隔小于一天的仅保留一份。距离现在超过一个月且小于最长保留时间的,更新间隔小于一周的仅保留一份。",
"The following items could not be synchronized.": "下列项目无法被同步。",
"The following items were changed locally.": "下列项目存在本地更改。",
"The following unexpected items were found.": "The following unexpected items were found.",
"The following unexpected items were found.": "找到了以下特殊项。",
"The interval must be a positive number of seconds.": "间隔必须为正数秒。",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "在版本目录中运行清理的间隔(秒)。0表示禁用定期清除。",
"The maximum age must be a number and cannot be blank.": "最长保留时间必须为数字,且不能为空。",
@@ -347,7 +349,7 @@
"The rate limit must be a non-negative number (0: no limit)": "传输速度限制为非负整数(0 表示不限制)",
"The rescan interval must be a non-negative number of seconds.": "扫描间隔单位为秒,且不能为负数。",
"There are no devices to share this folder with.": "没有设备共享此文件夹",
"There are no folders to share with this device.": "There are no folders to share with this device.",
"There are no folders to share with this device.": "没有文件夹与此设备共享。",
"They are retried automatically and will be synced when the error is resolved.": "系统将会自动重试,当错误被解决时,它们将会被同步。",
"This Device": "当前设备",
"This can easily give hackers access to read and change any files on your computer.": "这会让骇客能够轻而易举地访问及修改您的文件。",
@@ -361,14 +363,14 @@
"Unavailable": "无效",
"Unavailable/Disabled by administrator or maintainer": "无效/禁用(由管理员或维护者)",
"Undecided (will prompt)": "待定(将提示)",
"Unexpected Items": "Unexpected Items",
"Unexpected items have been found in this folder.": "Unexpected items have been found in this folder.",
"Unexpected Items": "特殊项目",
"Unexpected items have been found in this folder.": "在此文件夹中发现了特殊项目",
"Unignore": "解除忽略",
"Unknown": "未知",
"Unshared": "共享",
"Unshared Devices": "共享设备",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Unshared": "共享",
"Unshared Devices": "共享设备",
"Unshared Folders": "非共享文件夹",
"Untrusted": "不可信的",
"Up to Date": "同步完成",
"Updated": "已更新",
"Upgrade": "更新",
@@ -386,7 +388,7 @@
"Waiting to Clean": "等待清除",
"Waiting to Scan": "等待扫描",
"Waiting to Sync": "等待同步",
"Warning": "Warning",
"Warning": "警告",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "警告,该路径是已有文件夹\"{{otherFolder}}\"的上级目录。",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "警告,该路径是已有文件夹\"{{otherFolderLabel}}\" ({{otherFolder}})的上级目录。",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "警告,该路径是已有文件夹\"{{otherFolder}}\"的下级目录。",
@@ -405,7 +407,7 @@
"You have no ignored folders.": "你没有已忽略的文件夹。",
"You have unsaved changes. Do you really want to discard them?": "你有未保存的更改。你真的要丢弃它们吗?",
"You must keep at least one version.": "您必须保留至少一个版本。",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "You should never add or change anything locally in a \"{{receiveEncrypted}}\" folder.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "您绝对不应在“ {{receiveEncrypted}}”文件夹中添加或更改任何本地内容。",
"days": "天",
"directories": "目录",
"files": "文件",
@@ -414,5 +416,5 @@
"seconds": "秒",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} 想将 “{{folder}}” 文件夹共享给您。",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} 想要共享 \"{{folderlabel}}\" ({{folder}}) 文件夹给您。",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} might reintroduce this device."
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}}可能会重新引入此设备。"
}
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "清除版本",
"Cleanup Interval": "清除間隔",
"Click to see discovery failures": "點擊查看設備發現錯誤",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "關閉",
"Command": "命令",
"Comment, when used at the start of a line": "註釋,在行首使用",
@@ -153,6 +154,7 @@
"Help": "幫助",
"Home page": "主頁",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "我們已經為您關閉了自動崩潰報告發送功能,因為您當前的設置顯示您可能並不想啟用該功能。",
"Identification": "Identification",
"If untrusted, enter encryption password": "如果不受信任,請輸入加密密碼",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "如果要阻止此計算機上的其他用戶訪問Syncthing並通過它訪問文件,請考慮設置身份驗證。",
"Ignore": "忽略",
+2
View File
@@ -45,6 +45,7 @@
"Cleaning Versions": "正在清除歷史版本",
"Cleanup Interval": "清除間隔",
"Click to see discovery failures": "點擊以查閱失敗的探索",
"Click to see full identification string and QR code.": "Click to see full identification string and QR code.",
"Close": "關閉",
"Command": "指令",
"Comment, when used at the start of a line": "註解,當輸入在一行的開頭時",
@@ -153,6 +154,7 @@
"Help": "說明",
"Home page": "首頁",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "但是,當前設定表明您可能不希望啟用它。我們為您停用了當機自動回報。",
"Identification": "Identification",
"If untrusted, enter encryption password": "如未受信任,請輸入加密密碼",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "如果您想防止在此電腦上的其他使用者存取 Syncthing 及其文件,請考慮設定身份驗證。",
"Ignore": "忽略",
+36 -20
View File
@@ -102,7 +102,7 @@
</a>
<ul class="dropdown-menu">
<li><a href="" ng-click="showSettings()"><span class="fas fa-fw fa-cog"></span>&nbsp;<span translate>Settings</span></a></li>
<li><a href="" data-toggle="modal" data-target="#idqr" ng-click="currentDevice=thisDevice()"><span class="fas fa-fw fa-qrcode"></span>&nbsp;<span translate>Show ID</span></a></li>
<li><a href="" ng-click="showDeviceIdentification(thisDevice())"><span class="fas fa-fw fa-qrcode"></span>&nbsp;<span translate>Show ID</span></a></li>
<li class="divider" aria-hidden="true"></li>
<li><a href="" ng-click="shutdown()"><span class="fas fa-fw fa-power-off"></span>&nbsp;<span translate>Shutdown</span></a></li>
<li><a href="" ng-click="restart()"><span class="fas fa-fw fa-refresh"></span>&nbsp;<span translate>Restart</span></a></li>
@@ -209,10 +209,13 @@
</div>
<div class="panel-footer clearfix">
<div class="pull-right">
<button type="button" class="btn btn-sm btn-default" ng-click="dismissPendingDevice(deviceID)" tooltip data-original-title="{{'Do not add it to the ignore list, so this notification may recurr.' | translate}}">
<span class="far fa-clock"></span>&nbsp;<span translate>Dismiss</span>
</button>
<button type="button" class="btn btn-sm btn-success" ng-click="addDevice(deviceID, pendingDevice.name)">
<span class="fas fa-plus"></span>&nbsp;<span translate>Add Device</span>
</button>
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreDevice(deviceID, pendingDevice)">
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreDevice(deviceID, pendingDevice)" tooltip data-original-title="{{'Permanently add it to the ignore list, suppressing further notifications.' | translate}}">
<span class="fas fa-times"></span>&nbsp;<span translate>Ignore</span>
</button>
</div>
@@ -250,13 +253,16 @@
</div>
<div class="panel-footer clearfix">
<div class="pull-right">
<button type="button" class="btn btn-sm btn-default" ng-click="dismissPendingFolder(folderID, deviceID)" tooltip data-original-title="{{'Do not add it to the ignore list, so this notification may recurr.' | translate}}">
<span class="far fa-clock"></span>&nbsp;<span translate>Dismiss</span>
</button>
<button type="button" class="btn btn-sm btn-success" ng-click="addFolderAndShare(folderID, pendingFolder, deviceID)" ng-if="!folders[folderID]">
<span class="fas fa-check"></span>&nbsp;<span translate>Add</span>
</button>
<button type="button" class="btn btn-sm btn-success" ng-click="shareFolderWithDevice(folderID, deviceID)" ng-if="folders[folderID]">
<span class="fas fa-check"></span>&nbsp;<span translate>Share</span>
</button>
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreFolder(deviceID, folderID, offeringDevice)">
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreFolder(deviceID, folderID, offeringDevice)" tooltip data-original-title="{{'Permanently add it to the ignore list, suppressing further notifications.' | translate}}">
<span class="fas fa-times"></span>&nbsp;<span translate>Ignore</span>
</button>
</div>
@@ -560,7 +566,7 @@
<button ng-if="folder.paused" type="button" class="btn btn-sm btn-default" ng-click="setFolderPause(folder.id, false)">
<span class="fas fa-play"></span>&nbsp;<span translate>Resume</span>
</button>
<button type="button" class="btn btn-default btn-sm" ng-click="restoreVersions.show(folder.id)" ng-if="folder.versioning.type && folder.versioning.type != 'external'">
<button type="button" class="btn btn-default btn-sm" ng-click="restoreVersions.show(folder.id)" ng-if="folder.versioning.type && folder.versioning.type != 'external'" ng-disabled="folder.paused">
<span class="fas fa-undo"></span>&nbsp;<span translate>Versions</span>
</button>
<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">
@@ -655,26 +661,20 @@
<tr>
<th><span class="fas fa-fw fa-sitemap"></span>&nbsp;<span translate>Listeners</span></th>
<td class="text-right">
<span ng-if="listenersFailed.length == 0" class="data text-success">
<span>{{listenersTotal}}/{{listenersTotal}}</span>
</span>
<span ng-if="listenersFailed.length != 0" class="data" ng-class="{'text-danger': listenersFailed.length == listenersTotal}">
<span popover data-trigger="hover" data-placement="bottom" data-html="true" data-content="{{listenersFailed.join('<br>\n')}}">
{{listenersTotal-listenersFailed.length}}/{{listenersTotal}}
</span>
<span class="data" tooltip data-original-title="{{'Show detailed listener status' | translate}}.">
<a href="" style="color:inherit" ng-class="{'text-success': listenersFailed.length == 0, 'text-danger': listenersFailed.length == listenersTotal}" ng-click="showListenerStatus()">
{{listenersTotal-listenersFailed.length}}/{{listenersTotal}}
</a>
</span>
</td>
</tr>
<tr ng-if="system.discoveryEnabled">
<th><span class="fas fa-fw fa-map-signs"></span>&nbsp;<span translate>Discovery</span></th>
<td class="text-right">
<span ng-if="discoveryFailed.length == 0" class="data text-success">
<span>{{discoveryTotal}}/{{discoveryTotal}}</span>
</span>
<span ng-if="discoveryFailed.length != 0" class="data" ng-class="{'text-danger': discoveryFailed.length == discoveryTotal}">
<span popover data-trigger="hover" data-placement="bottom" data-content="{{'Click to see discovery failures' | translate}}.">
<a href="" style="color:inherit" ng-click="showDiscoveryFailures()">{{discoveryTotal-discoveryFailed.length}}/{{discoveryTotal}}</a>
</span>
<span class="data" tooltip data-original-title="{{'Show detailed discovery status' | translate}}.">
<a href="" style="color:inherit" ng-class="{'text-success': discoveryFailed.length == 0, 'text-danger': discoveryFailed.length == discoveryTotal}" ng-click="showDiscoveryStatus()">
{{discoveryTotal-discoveryFailed.length}}/{{discoveryTotal}}
</a>
</span>
</td>
</tr>
@@ -682,6 +682,14 @@
<th><span class="far fa-fw fa-clock"></span>&nbsp;<span translate>Uptime</span></th>
<td class="text-right">{{system.uptime | duration:"m"}}</td>
</tr>
<tr>
<th><span class="fas fa-fw fa-qrcode"></span>&nbsp;<span translate>Identification</span></th>
<td class="text-right">
<span tooltip data-original-title="{{'Click to see full identification string and QR code.' | translate}}">
<a href="" ng-click="showDeviceIdentification(thisDevice())">{{deviceShortID(deviceCfg.deviceID)}}</a>
</span>
</td>
</tr>
<tr>
<th><span class="fas fa-fw fa-tag"></span>&nbsp;<span translate>Version</span></th>
<td class="text-right">
@@ -713,7 +721,7 @@
<span ng-switch-when="disconnected"><span class="hidden-xs" translate>Disconnected</span><span class="visible-xs" aria-label="{{'Disconnected' | translate}}"><i class="fas fa-fw fa-power-off"></i></span></span>
<span ng-switch-when="unused-disconnected"><span class="hidden-xs" translate>Disconnected (Unused)</span><span class="visible-xs" aria-label="{{'Disconnected (Unused)' | translate}}"><i class="fas fa-fw fa-unlink"></i></span></span>
</span>
<span>{{deviceName(deviceCfg)}}</span>
<div class="panel-title-text">{{deviceName(deviceCfg)}}</div>
</h4>
</button>
<div id="device-{{$index}}" class="panel-collapse collapse">
@@ -806,6 +814,14 @@
<th><span class="far fa-fw fa-handshake-o"></span>&nbsp;<span translate>Introduced By</span></th>
<td class="text-right">{{ deviceName(devices[deviceCfg.introducedBy]) || deviceCfg.introducedBy.substring(0, 5) }}</td>
</tr>
<tr>
<th><span class="fas fa-fw fa-qrcode"></span>&nbsp;<span translate>Identification</span></th>
<td class="text-right">
<span tooltip data-original-title="{{'Click to see full identification string and QR code.' | translate}}">
<a href="" ng-click="showDeviceIdentification(deviceCfg)">{{deviceShortID(deviceCfg.deviceID)}}</a>
</span>
</td>
</tr>
<tr ng-if="connections[deviceCfg.deviceID].clientVersion">
<th><span class="fas fa-fw fa-tag"></span>&nbsp;<span translate>Version</span></th>
<td class="text-right">{{connections[deviceCfg.deviceID].clientVersion}}</td>
@@ -905,7 +921,7 @@
<ng-include src="'syncthing/core/upgradeModalView.html'"></ng-include>
<ng-include src="'syncthing/core/majorUpgradeModalView.html'"></ng-include>
<ng-include src="'syncthing/core/aboutModalView.html'"></ng-include>
<ng-include src="'syncthing/core/discoveryFailuresModalView.html'"></ng-include>
<ng-include src="'syncthing/core/connectivityStatusModalView.html'"></ng-include>
<ng-include src="'syncthing/folder/removeFolderDialogView.html'"></ng-include>
<ng-include src="'syncthing/folder/revertOverrideView.html'"></ng-include>
<ng-include src="'syncthing/device/removeDeviceDialogView.html'"></ng-include>
@@ -19,7 +19,7 @@
<h4 class="text-center" translate>The Syncthing Authors</h4>
<div class="row">
<div class="col-md-12" id="contributor-list">
Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Evgeny Kuznetsov, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Nate Morrison, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Tomasz Wilczyński, Wulf Weich, dependabot-preview[bot], greatroar, Aaron Bieber, Adam Piggott, Adel Qalieh, Alan Pope, Alberto Donato, Alessandro G., Alex Lindeman, Alex Xu, Aman Gupta, Andrew Dunham, Andrew Rabert, Andrey D, Anjan Momi, Antoine Lamielle, Aranjedeath, Arkadiusz Tymiński, Arthur Axel fREW Schmidt, Artur Zubilewicz, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benno Fünfstück, Benny Ng, Boqin Qin, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Choongkyu, Chris Howie, Chris Joel, Chris Tonkinson, Christian Prescott, Colin Kennedy, Cromefire_, Cyprien Devillez, Dale Visser, Dan, Daniel Bergmann, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dmitry Saveliev, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eric Lesiuta, Erik Meitner, Federico Castagnini, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Han Boetes, HansK-p, Harrison Jones, Heiko Zuerker, Hugo Locurcio, Iain Barnett, Ian Johnson, Ilya Brin, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jack Croft, Jacob, Jake Peterson, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaya Chithra, Jens Diemer, Jerry Jacobs, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jonathan Cross, Jonta, Jose Manuel Delicado, Jörg Thalheim, Jędrzej Kula, Kalle Laine, Karol Różycki, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., Kurt Fitzner, Lars Lehtonen, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Lukas Lihotzki, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Mateusz Naściszewski, Mateusz Ż, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max Schulze, MaximAL, Maxime Thirouin, MichaIng, Michael Jephcote, Michael Rienstra, Michael Tilli, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, Nicholas Rishel, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, Otiel, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Quentin Hibon, Rahmi Pruitt, Richard Hartmann, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, Ross Smith II, Ruslan Yevdokymov, Sacheendra Talluri, Scott Klupfel, Shaarad Dalvi, Simon Mwepu, Sly_tom_cat, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Taylor Khan, Thomas Hipp, Tim Abell, Tim Howes, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy Thorn, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, Vladimir Rusinov, William A. Kennington III, Xavier O., Yannic A., andresvia, andyleap, boomsquared, bt90, chenrui, chucic, deepsource-autofix[bot], dependabot[bot], derekriemer, desbma, georgespatton, ghjklw, janost, jaseg, jelle van der Waa, klemens, marco-m, mclang, mv1005, otbutz, perewa, rubenbe, wangguoliang, wouter bolsterlee, xarx00, xjtdy888, 佛跳墙
Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Evgeny Kuznetsov, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Nate Morrison, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Tomasz Wilczyński, Wulf Weich, dependabot-preview[bot], greatroar, Aaron Bieber, Adam Piggott, Adel Qalieh, Alan Pope, Alberto Donato, Alessandro G., Alex Lindeman, Alex Xu, Aman Gupta, Andrew Dunham, Andrew Rabert, Andrey D, Anjan Momi, Antoine Lamielle, Aranjedeath, Arkadiusz Tymiński, Arthur Axel fREW Schmidt, Artur Zubilewicz, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benno Fünfstück, Benny Ng, Boqin Qin, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Choongkyu, Chris Howie, Chris Joel, Chris Tonkinson, Christian Prescott, Colin Kennedy, Cromefire_, Cyprien Devillez, Dale Visser, Dan, Daniel Bergmann, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dmitry Saveliev, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eric Lesiuta, Erik Meitner, Federico Castagnini, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Han Boetes, HansK-p, Harrison Jones, Heiko Zuerker, Hugo Locurcio, Iain Barnett, Ian Johnson, Ikko Ashimine, Ilya Brin, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jack Croft, Jacob, Jake Peterson, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaya Chithra, Jens Diemer, Jerry Jacobs, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jonathan Cross, Jonta, Jose Manuel Delicado, Jörg Thalheim, Jędrzej Kula, Kalle Laine, Karol Różycki, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., Kurt Fitzner, Lars Lehtonen, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Lukas Lihotzki, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Mateusz Naściszewski, Mateusz Ż, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max Schulze, MaximAL, Maxime Thirouin, MichaIng, Michael Jephcote, Michael Rienstra, Michael Tilli, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, Nicholas Rishel, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, Otiel, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Quentin Hibon, Rahmi Pruitt, Richard Hartmann, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, Ross Smith II, Ruslan Yevdokymov, Sacheendra Talluri, Scott Klupfel, Shaarad Dalvi, Simon Mwepu, Sly_tom_cat, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Taylor Khan, Thomas Hipp, Tim Abell, Tim Howes, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy Thorn, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, Vladimir Rusinov, William A. Kennington III, Xavier O., Yannic A., andresvia, andyleap, boomsquared, bt90, chenrui, chucic, deepsource-autofix[bot], dependabot[bot], derekriemer, desbma, georgespatton, ghjklw, janost, jaseg, jelle van der Waa, klemens, marco-m, mclang, mv1005, otbutz, overkill, perewa, rubenbe, wangguoliang, wouter bolsterlee, xarx00, xjtdy888, 佛跳墙
</div>
</div>
<hr />
@@ -0,0 +1,60 @@
<modal id="connectivity-status" status="{{connectivityStatusParams.status}}" icon="fas fa-fw {{connectivityStatusParams.type == 'listeners' ? 'fa-sitemap' : 'fa-map-signs'}}" heading="{{connectivityStatusParams.heading}}" large="no" closeable="yes">
<div class="modal-body" ng-switch="connectivityStatusParams.type">
<div ng-switch-when="listeners">
<p translate ng-if="listenersRunning.length == 0">
Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.
</p>
<div ng-if="listenersRunning.length > 0">
<p translate>
Syncthing is listening on the following network addresses for connection attempts from other devices:
</p>
<ul>
<li ng-repeat="listener in listenersRunning">{{listener}}</li>
</ul>
</div>
<div ng-if="listenersFailed.length > 0">
<p translate>
Some listening addresses could not be enabled to accept connections:
</p>
<ul>
<li ng-repeat="listener in listenersFailed">{{listener}}</li>
</ul>
</div>
</div>
<div ng-switch-default><!-- discovery methods -->
<p translate ng-if="discoveryRunning.length == 0">
This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.
</p>
<div ng-if="discoveryRunning.length > 0">
<p translate>
The following methods are used to discover other devices on the network and announce this device to be found by others:
</p>
<ul>
<li ng-repeat="discovery in discoveryRunning">{{discovery}}</li>
</ul>
</div>
<div ng-if="discoveryFailed.length > 0">
<p translate>
Some discovery methods could not be established for finding other devices or announcing this device:
</p>
<ul>
<li ng-repeat="discovery in discoveryFailed">{{discovery}}</li>
</ul>
</div>
<div class="row">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default">
<div translate class="panel-body">
Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<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>
</modal>
@@ -1,21 +0,0 @@
<modal id="discovery-failures" status="danger" icon="fas fa-exclamation-circle" heading="{{'Discovery Failures' | translate}}" large="yes" closeable="yes">
<div class="modal-body">
<ul>
<li ng-repeat="failure in discoveryFailed">{{failure}}</li>
</ul>
</div>
<div class="row">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default">
<div translate class="panel-body">
Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.
</div>
</div>
</div>
</div>
<div class="modal-footer">
<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>
</modal>
@@ -42,7 +42,7 @@ angular.module('syncthing.core')
$scope.pendingFolders = {};
$scope.progress = {};
$scope.version = {};
$scope.needed = {}
$scope.needed = {};
$scope.neededFolder = '';
$scope.failed = {};
$scope.localChanged = {};
@@ -471,22 +471,30 @@ angular.module('syncthing.core')
}
var listenersFailed = [];
var listenersRunning = [];
for (var address in data.connectionServiceStatus) {
if (data.connectionServiceStatus[address].error) {
listenersFailed.push(address + ": " + data.connectionServiceStatus[address].error);
} else {
listenersRunning.push(address);
}
}
$scope.listenersFailed = listenersFailed;
$scope.listenersRunning = listenersRunning;
$scope.listenersTotal = $scope.sizeOf(data.connectionServiceStatus);
$scope.discoveryTotal = data.discoveryMethods;
var discoveryFailed = [];
for (var disco in data.discoveryErrors) {
if (data.discoveryErrors[disco]) {
discoveryFailed.push(disco + ": " + data.discoveryErrors[disco]);
var discoveryRunning = [];
for (var disco in data.discoveryStatus) {
if (data.discoveryStatus[disco] && data.discoveryStatus[disco].error) {
discoveryFailed.push(disco + ": " + data.discoveryStatus[disco].error);
} else {
discoveryRunning.push(disco);
}
}
$scope.discoveryFailed = discoveryFailed;
$scope.discoveryRunning = discoveryRunning;
$scope.discoveryTotal = $scope.sizeOf(data.discoveryStatus);
refreshNoAuthWarning();
@@ -673,7 +681,7 @@ angular.module('syncthing.core')
console.log("refreshNeed", $scope.neededFolder, data);
parseNeeded(data);
}).error($scope.emitHTTPError);
}
};
function needAction(file) {
var fDelete = 4096;
@@ -1010,7 +1018,7 @@ angular.module('syncthing.core')
if (days > 31) {
return '> 1 month';
}
res.push('' + days + 'd')
res.push('' + days + 'd');
seconds = seconds % 86400;
}
@@ -1018,7 +1026,7 @@ angular.module('syncthing.core')
var hours = 0;
if (seconds > 3600) {
hours = Math.floor(seconds / 3600);
res.push('' + hours + 'h')
res.push('' + hours + 'h');
seconds = seconds % 3600;
}
@@ -1202,13 +1210,20 @@ angular.module('syncthing.core')
};
$scope.deviceName = function (deviceCfg) {
if (typeof deviceCfg === 'undefined' || typeof deviceCfg.deviceID === 'undefined') {
if (typeof deviceCfg === 'undefined') {
return "";
}
if (deviceCfg.name) {
return deviceCfg.name;
}
return deviceCfg.deviceID.substr(0, 6);
return $scope.deviceShortID(deviceCfg.deviceID);
};
$scope.deviceShortID = function (deviceID) {
if (typeof deviceID === 'undefined') {
return "";
}
return deviceID.substr(0, 6);
};
$scope.thisDeviceName = function () {
@@ -1222,6 +1237,11 @@ angular.module('syncthing.core')
return device.deviceID.substr(0, 6);
};
$scope.showDeviceIdentification = function (deviceCfg) {
$scope.currentDevice = deviceCfg;
$('#idqr').modal();
};
$scope.setDevicePause = function (device, pause) {
$scope.devices[device].paused = pause;
$scope.config.devices = $scope.deviceList();
@@ -1237,8 +1257,34 @@ angular.module('syncthing.core')
}
};
$scope.showDiscoveryFailures = function () {
$('#discovery-failures').modal();
$scope.showListenerStatus = function () {
var params = {
type: 'listeners',
};
if ($scope.listenersFailed.length > 0) {
params.status = 'danger';
params.heading = $translate.instant("Listener Failures");
} else {
params.status = 'default';
params.heading = $translate.instant("Listener Status");
}
$scope.connectivityStatusParams = params;
$('#connectivity-status').modal();
};
$scope.showDiscoveryStatus = function () {
var params = {
type: 'discovery',
};
if ($scope.discoveryFailed.length > 0) {
params.status = 'danger';
params.heading = $translate.instant("Discovery Failures");
} else {
params.status = 'default';
params.heading = $translate.instant("Discovery Status");
}
$scope.connectivityStatusParams = params;
$('#connectivity-status').modal();
};
$scope.logging = {
@@ -1703,6 +1749,10 @@ angular.module('syncthing.core')
$scope.saveConfig();
};
$scope.dismissPendingDevice = function (deviceID) {
$http.delete(urlbase + '/cluster/pending/devices?device=' + encodeURIComponent(deviceID));
};
$scope.unignoreDeviceFromTemporaryConfig = function (ignoredDevice) {
$scope.tmpRemoteIgnoredDevices = $scope.tmpRemoteIgnoredDevices.filter(function (existingIgnoredDevice) {
return ignoredDevice.deviceID !== existingIgnoredDevice.deviceID;
@@ -1759,7 +1809,7 @@ angular.module('syncthing.core')
};
$scope.config.devices = deviceList($scope.devices);
$scope.saveConfig();
}
};
$scope.isAtleastOneDevicePausedStateSetTo = function (pause) {
for (var id in $scope.devices) {
@@ -1768,8 +1818,8 @@ angular.module('syncthing.core')
}
}
return false
}
return false;
};
$scope.errorList = function () {
if (!$scope.errors) {
@@ -2117,7 +2167,7 @@ angular.module('syncthing.core')
folderCfg.versioning.params.command = '' + folderCfg._guiVersioning.externalCommand;
break;
default:
delete folderCfg.versioning;
folderCfg.versioning = {type: ''};
}
delete folderCfg._guiVersioning;
@@ -2174,6 +2224,11 @@ angular.module('syncthing.core')
}
};
$scope.dismissPendingFolder = function (folderID, deviceID) {
$http.delete(urlbase + '/cluster/pending/folders?folder=' + encodeURIComponent(folderID)
+ '&device=' + encodeURIComponent(deviceID));
};
$scope.sharesFolder = function (folderCfg) {
var names = [];
folderCfg.devices.forEach(function (device) {
@@ -2779,7 +2834,7 @@ angular.module('syncthing.core')
var time = $filter('date')(status.when, "HH:mm:ss")
var err = status.error.replace(/.+: /, '');
return err + " (" + time + ")";
}
};
$scope.setCrashReportingEnabled = function (enabled) {
$scope.config.options.crashReportingEnabled = enabled;
@@ -2791,7 +2846,7 @@ angular.module('syncthing.core')
(address.indexOf('/') == 0 ||
address.indexOf('unix://') == 0 ||
address.indexOf('unixs://') == 0);
}
};
})
.directive('shareTemplate', function () {
return {
+70 -10
View File
@@ -32,7 +32,7 @@ import (
"unicode"
"github.com/julienschmidt/httprouter"
metrics "github.com/rcrowley/go-metrics"
"github.com/rcrowley/go-metrics"
"github.com/thejerf/suture/v4"
"github.com/vitrun/qart/qr"
"golang.org/x/text/runes"
@@ -162,7 +162,7 @@ func (s *service) getListener(guiCfg config.GUIConfiguration) (net.Listener, err
if err != nil {
return nil, err
}
tlsCfg := tlsutil.SecureDefault()
tlsCfg := tlsutil.SecureDefaultWithTLS12()
tlsCfg.Certificates = []tls.Certificate{cert}
if guiCfg.Network() == "unix" {
@@ -291,6 +291,10 @@ func (s *service) Serve(ctx context.Context) error {
restMux.HandlerFunc(http.MethodPost, "/rest/system/resume", s.makeDevicePauseHandler(false)) // [device]
restMux.HandlerFunc(http.MethodPost, "/rest/system/debug", s.postSystemDebug) // [enable] [disable]
// The DELETE handlers
restMux.HandlerFunc(http.MethodDelete, "/rest/cluster/pending/devices", s.deletePendingDevices) // device
restMux.HandlerFunc(http.MethodDelete, "/rest/cluster/pending/folders", s.deletePendingFolders) // folder [device]
// Config endpoints
configBuilder := &configMuxBuilder{
@@ -632,6 +636,21 @@ func (s *service) getPendingDevices(w http.ResponseWriter, r *http.Request) {
sendJSON(w, devices)
}
func (s *service) deletePendingDevices(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
device := qs.Get("device")
deviceID, err := protocol.DeviceIDFromString(device)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := s.model.DismissPendingDevice(deviceID); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func (s *service) getPendingFolders(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
@@ -650,6 +669,22 @@ func (s *service) getPendingFolders(w http.ResponseWriter, r *http.Request) {
sendJSON(w, folders)
}
func (s *service) deletePendingFolders(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
device := qs.Get("device")
deviceID, err := protocol.DeviceIDFromString(device)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
folderID := qs.Get("folder")
if err := s.model.DismissPendingFolder(deviceID, folderID); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func (s *service) restPing(w http.ResponseWriter, r *http.Request) {
sendJSON(w, map[string]string{"ping": "pong"})
}
@@ -915,11 +950,16 @@ func (s *service) getDBFile(w http.ResponseWriter, r *http.Request) {
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
mtimeMapping, mtimeErr := s.model.GetMtimeMapping(folder, file)
sendJSON(w, map[string]interface{}{
"global": jsonFileInfo(gf),
"local": jsonFileInfo(lf),
"availability": av,
"mtime": map[string]interface{}{
"err": mtimeErr,
"value": mtimeMapping,
},
})
}
@@ -934,6 +974,8 @@ func (s *service) getDebugFile(w http.ResponseWriter, r *http.Request) {
return
}
mtimeMapping, mtimeErr := s.model.GetMtimeMapping(folder, file)
lf, _ := snap.Get(protocol.LocalDeviceID, file)
gf, _ := snap.GetGlobal(file)
av := snap.Availability(file)
@@ -944,6 +986,10 @@ func (s *service) getDebugFile(w http.ResponseWriter, r *http.Request) {
"local": jsonFileInfo(lf),
"availability": av,
"globalVersions": vl.String(),
"mtime": map[string]interface{}{
"err": mtimeErr,
"value": mtimeMapping,
},
})
}
@@ -1012,16 +1058,16 @@ func (s *service) getSystemStatus(w http.ResponseWriter, r *http.Request) {
res["tilde"] = tilde
if s.cfg.Options().LocalAnnEnabled || s.cfg.Options().GlobalAnnEnabled {
res["discoveryEnabled"] = true
discoErrors := make(map[string]string)
discoMethods := 0
for disco, err := range s.discoverer.ChildErrors() {
discoMethods++
if err != nil {
discoErrors[disco] = err.Error()
discoStatus := s.discoverer.ChildErrors()
res["discoveryStatus"] = discoveryStatusMap(discoStatus)
res["discoveryMethods"] = len(discoStatus) // DEPRECATED: Redundant, only for backwards compatibility, should be removed.
discoErrors := make(map[string]*string, len(discoStatus))
for s, e := range discoStatus {
if e != nil {
discoErrors[s] = errorString(e)
}
}
res["discoveryMethods"] = discoMethods
res["discoveryErrors"] = discoErrors
res["discoveryErrors"] = discoErrors // DEPRECATED: Redundant, only for backwards compatibility, should be removed.
}
res["connectionServiceStatus"] = s.connectionsService.ListenerStatus()
@@ -1894,6 +1940,20 @@ func errorString(err error) *string {
return nil
}
type discoveryStatusEntry struct {
Error *string `json:"error"`
}
func discoveryStatusMap(errs map[string]error) map[string]discoveryStatusEntry {
out := make(map[string]discoveryStatusEntry, len(errs))
for s, e := range errs {
out[s] = discoveryStatusEntry{
Error: errorString(e),
}
}
return out
}
// sanitizedHostname returns the given name in a suitable form for use as
// the common name in a certificate, or an error.
func sanitizedHostname(name string) (string, error) {
+3 -13
View File
@@ -42,6 +42,7 @@ import (
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/ur"
"github.com/syncthing/syncthing/lib/util"
"github.com/thejerf/suture/v4"
)
@@ -126,6 +127,7 @@ func TestStopAfterBrokenConfig(t *testing.T) {
srv := New(protocol.LocalDeviceID, w, "", "syncthing", nil, nil, nil, events.NoopLogger, nil, nil, nil, nil, nil, nil, false).(*service)
defer os.Remove(token)
srv.started = make(chan string)
sup := suture.New("test", svcutil.SpecWithDebugLogger(l))
@@ -1178,7 +1180,7 @@ func TestBrowse(t *testing.T) {
for _, tc := range cases {
ret := browseFiles(tc.current, fs.FilesystemTypeBasic)
if !equalStrings(ret, tc.returns) {
if !util.EqualStrings(ret, tc.returns) {
t.Errorf("browseFiles(%q) => %q, expected %q", tc.current, ret, tc.returns)
}
}
@@ -1389,18 +1391,6 @@ func TestSanitizedHostname(t *testing.T) {
}
}
func equalStrings(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
// runningInContainer returns true if we are inside Docker or LXC. It might
// be prone to false negatives if things change in the future, but likely
// not false positives.
+44 -29
View File
@@ -17,6 +17,7 @@ import (
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/util"
)
type configMuxBuilder struct {
@@ -63,10 +64,15 @@ func (c *configMuxBuilder) registerFolders(path string) {
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
var folders []config.FolderConfiguration
if err := unmarshalTo(r.Body, &folders); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
data, err := unmarshalToRawMessages(r.Body)
folders := make([]config.FolderConfiguration, len(data))
defaultFolder := c.cfg.DefaultFolder()
for i, bs := range data {
folders[i] = defaultFolder.Copy()
if err := json.Unmarshal(bs, &folders[i]); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
}
waiter, err := c.cfg.Modify(func(cfg *config.Configuration) {
cfg.SetFolders(folders)
@@ -79,7 +85,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{}, false)
c.adjustFolder(w, r, c.cfg.DefaultFolder(), false)
})
}
@@ -89,10 +95,15 @@ func (c *configMuxBuilder) registerDevices(path string) {
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
var devices []config.DeviceConfiguration
if err := unmarshalTo(r.Body, &devices); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
data, err := unmarshalToRawMessages(r.Body)
devices := make([]config.DeviceConfiguration, len(data))
defaultDevice := c.cfg.DefaultDevice()
for i, bs := range data {
devices[i] = defaultDevice.Copy()
if err := json.Unmarshal(bs, &devices[i]); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
}
waiter, err := c.cfg.Modify(func(cfg *config.Configuration) {
cfg.SetDevices(devices)
@@ -105,19 +116,7 @@ func (c *configMuxBuilder) registerDevices(path string) {
})
c.HandlerFunc(http.MethodPost, path, func(w http.ResponseWriter, r *http.Request) {
var device config.DeviceConfiguration
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 err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
c.finish(w, waiter)
c.adjustDevice(w, r, c.cfg.DefaultDevice(), false)
})
}
@@ -132,7 +131,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{}, false)
c.adjustFolder(w, r, c.cfg.DefaultFolder(), false)
})
c.Handle(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
@@ -176,7 +175,7 @@ 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{}, false)
c.adjustDevice(w, r, c.cfg.DefaultDevice(), false)
})
c.Handle(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
@@ -206,7 +205,9 @@ func (c *configMuxBuilder) registerDefaultFolder(path string) {
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustFolder(w, r, config.FolderConfiguration{}, true)
var cfg config.FolderConfiguration
util.SetDefaults(&cfg)
c.adjustFolder(w, r, cfg, true)
})
c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -220,7 +221,9 @@ func (c *configMuxBuilder) registerDefaultDevice(path string) {
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustDevice(w, r, config.DeviceConfiguration{}, true)
var cfg config.DeviceConfiguration
util.SetDefaults(&cfg)
c.adjustDevice(w, r, cfg, true)
})
c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -234,7 +237,9 @@ func (c *configMuxBuilder) registerOptions(path string) {
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustOptions(w, r, config.OptionsConfiguration{})
var cfg config.OptionsConfiguration
util.SetDefaults(&cfg)
c.adjustOptions(w, r, cfg)
})
c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -248,7 +253,9 @@ func (c *configMuxBuilder) registerLDAP(path string) {
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustLDAP(w, r, config.LDAPConfiguration{})
var cfg config.LDAPConfiguration
util.SetDefaults(&cfg)
c.adjustLDAP(w, r, cfg)
})
c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -262,7 +269,9 @@ func (c *configMuxBuilder) registerGUI(path string) {
})
c.HandlerFunc(http.MethodPut, path, func(w http.ResponseWriter, r *http.Request) {
c.adjustGUI(w, r, config.GUIConfiguration{})
var cfg config.GUIConfiguration
util.SetDefaults(&cfg)
c.adjustGUI(w, r, cfg)
})
c.HandlerFunc(http.MethodPatch, path, func(w http.ResponseWriter, r *http.Request) {
@@ -403,6 +412,12 @@ func unmarshalTo(body io.ReadCloser, to interface{}) error {
return json.Unmarshal(bs, to)
}
func unmarshalToRawMessages(body io.ReadCloser) ([]json.RawMessage, error) {
var data []json.RawMessage
err := unmarshalTo(body, &data)
return data, err
}
func checkGUIPassword(oldPassword, newPassword string) (string, error) {
if newPassword == oldPassword {
return newPassword, nil
+29 -4
View File
@@ -163,19 +163,44 @@ func ReadXML(r io.Reader, myID protocol.DeviceID) (Configuration, int, error) {
}
func ReadJSON(r io.Reader, myID protocol.DeviceID) (Configuration, error) {
var cfg Configuration
util.SetDefaults(&cfg)
bs, err := ioutil.ReadAll(r)
if err != nil {
return Configuration{}, err
}
var cfg Configuration
util.SetDefaults(&cfg)
if err := json.Unmarshal(bs, &cfg); err != nil {
return Configuration{}, err
}
// Unmarshal list of devices and folders separately to set defaults
var rawFoldersDevices struct {
Folders []json.RawMessage
Devices []json.RawMessage
}
if err := json.Unmarshal(bs, &rawFoldersDevices); err != nil {
return Configuration{}, err
}
cfg.Folders = make([]FolderConfiguration, len(rawFoldersDevices.Folders))
for i, bs := range rawFoldersDevices.Folders {
cfg.Folders[i] = cfg.Defaults.Folder.Copy()
if err := json.Unmarshal(bs, &cfg.Folders[i]); err != nil {
return Configuration{}, err
}
}
cfg.Devices = make([]DeviceConfiguration, len(rawFoldersDevices.Devices))
for i, bs := range rawFoldersDevices.Devices {
cfg.Devices[i] = cfg.Defaults.Device.Copy()
if err := json.Unmarshal(bs, &cfg.Devices[i]); err != nil {
return Configuration{}, err
}
}
if err := cfg.prepare(myID); err != nil {
return Configuration{}, err
}
+2 -8
View File
@@ -721,10 +721,7 @@ func (m *Configuration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthConfig
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthConfig
}
if (iNdEx + skippy) > l {
@@ -840,10 +837,7 @@ func (m *Defaults) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthConfig
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthConfig
}
if (iNdEx + skippy) > l {
+27
View File
@@ -1343,3 +1343,30 @@ func TestInternalVersioningConfiguration(t *testing.T) {
}
}
}
func TestReceiveEncryptedFolderFixed(t *testing.T) {
cfg := Configuration{
Folders: []FolderConfiguration{
{
ID: "foo",
Path: "testdata",
Type: FolderTypeReceiveEncrypted,
DisableTempIndexes: false,
IgnorePerms: false,
},
},
}
cfg.prepare(device1)
if len(cfg.Folders) != 1 {
t.Fatal("Expected one folder")
}
f := cfg.Folders[0]
if !f.DisableTempIndexes {
t.Error("DisableTempIndexes should be true")
}
if !f.IgnorePerms {
t.Error("IgnorePerms should be true")
}
}
+1 -4
View File
@@ -924,10 +924,7 @@ func (m *DeviceConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthDeviceconfiguration
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDeviceconfiguration
}
if (iNdEx + skippy) > l {
+1
View File
@@ -214,6 +214,7 @@ func (f *FolderConfiguration) prepare(myID protocol.DeviceID, existingDevices ma
}
if f.Type == FolderTypeReceiveEncrypted {
f.DisableTempIndexes = true
f.IgnorePerms = true
}
}
+2 -8
View File
@@ -968,10 +968,7 @@ func (m *FolderDeviceConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthFolderconfiguration
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthFolderconfiguration
}
if (iNdEx + skippy) > l {
@@ -1823,10 +1820,7 @@ func (m *FolderConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthFolderconfiguration
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthFolderconfiguration
}
if (iNdEx + skippy) > l {
+1 -4
View File
@@ -702,10 +702,7 @@ func (m *GUIConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGuiconfiguration
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGuiconfiguration
}
if (iNdEx + skippy) > l {
+1 -4
View File
@@ -425,10 +425,7 @@ func (m *LDAPConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthLdapconfiguration
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthLdapconfiguration
}
if (iNdEx + skippy) > l {
+2 -8
View File
@@ -435,10 +435,7 @@ func (m *ObservedFolder) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthObserved
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthObserved
}
if (iNdEx + skippy) > l {
@@ -618,10 +615,7 @@ func (m *ObservedDevice) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthObserved
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthObserved
}
if (iNdEx + skippy) > l {
+245 -206
View File
@@ -81,6 +81,9 @@ type OptionsConfiguration struct {
// meaning no limit. Affects incoming connections and prevents
// attempting outgoing connections.
ConnectionLimitMax int `protobuf:"varint,52,opt,name=connection_limit_max,json=connectionLimitMax,proto3,casttype=int" json:"connectionLimitMax" xml:"connectionLimitMax"`
// When set, this allows TLS 1.2 on sync connections, where we otherwise
// default to TLS 1.3+ only.
InsecureAllowOldTLSVersions bool `protobuf:"varint,53,opt,name=insecure_allow_old_tls_versions,json=insecureAllowOldTlsVersions,proto3" json:"insecureAllowOldTLSVersions" xml:"insecureAllowOldTLSVersions"`
// Legacy deprecated
DeprecatedUPnPEnabled bool `protobuf:"varint,9000,opt,name=upnp_enabled,json=upnpEnabled,proto3" json:"-" xml:"upnpEnabled,omitempty"` // Deprecated: Do not use.
DeprecatedUPnPLeaseM int `protobuf:"varint,9001,opt,name=upnp_lease_m,json=upnpLeaseM,proto3,casttype=int" json:"-" xml:"upnpLeaseMinutes,omitempty"` // Deprecated: Do not use.
@@ -133,209 +136,213 @@ func init() {
}
var fileDescriptor_d09882599506ca03 = []byte{
// 3218 bytes of a gzipped FileDescriptorProto
// 3295 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,
0xd9, 0xce, 0x26, 0x4d, 0xda, 0x6c, 0x1c, 0x27, 0x1e, 0x3b, 0xf6, 0x36, 0x49, 0xbd, 0xee, 0xc9,
0x49, 0xeb, 0xfe, 0x25, 0xb6, 0x93, 0xe6, 0x4b, 0x23, 0x7d, 0xea, 0xe7, 0x9f, 0xfa, 0xab, 0x1b,
0x3b, 0xb1, 0xc6, 0xf6, 0xd7, 0x4f, 0x45, 0x68, 0x35, 0xde, 0x9d, 0x63, 0x2f, 0xde, 0x33, 0x7b,
0xba, 0x33, 0xeb, 0x9f, 0x16, 0x41, 0x55, 0x04, 0xe5, 0x0e, 0xb0, 0xf8, 0x91, 0x40, 0x42, 0x45,
0x80, 0x44, 0x29, 0x45, 0x48, 0x48, 0x48, 0x70, 0x43, 0x85, 0x84, 0x54, 0xc1, 0x85, 0x7d, 0x89,
0x44, 0x59, 0x54, 0xa7, 0x57, 0xe7, 0x82, 0x8b, 0x73, 0x69, 0x6e, 0xd0, 0xcc, 0xfe, 0xcd, 0xee,
0xce, 0x49, 0x72, 0x77, 0xf6, 0x7d, 0xde, 0x79, 0xe7, 0x79, 0xe7, 0xe7, 0x9d, 0xf7, 0x9d, 0x39,
0xfa, 0x65, 0xcf, 0x5d, 0xbd, 0x6a, 0xfb, 0xa4, 0xe1, 0xae, 0x5d, 0xf5, 0x5b, 0xcc, 0xf5, 0x09,
0x8d, 0xbf, 0xc2, 0x00, 0xf1, 0xaf, 0x2b, 0xad, 0xc0, 0x67, 0x3e, 0x38, 0x11, 0x0b, 0xcf, 0x0f,
0x49, 0xea, 0x2c, 0x24, 0x2e, 0x59, 0x8b, 0x15, 0xce, 0x9f, 0x93, 0x00, 0xea, 0xbe, 0x85, 0x13,
0xf1, 0x49, 0xbc, 0xcd, 0xe2, 0x9f, 0xb5, 0x83, 0xd7, 0xf4, 0x81, 0xbb, 0x71, 0x0f, 0xd3, 0x72,
0x0f, 0xe0, 0xc7, 0x9a, 0x7e, 0xd6, 0x73, 0x29, 0xc3, 0xc4, 0x42, 0x8e, 0x13, 0x60, 0x4a, 0x31,
0x35, 0xb4, 0x91, 0x63, 0xa3, 0x27, 0xa7, 0xe8, 0x41, 0x64, 0x02, 0x88, 0xb6, 0xe6, 0x05, 0x3c,
0x99, 0xa2, 0xed, 0xc8, 0x3c, 0xe3, 0x15, 0x45, 0x9d, 0xc8, 0xbc, 0xbc, 0xdd, 0xf4, 0x6e, 0xd5,
0x0a, 0xf2, 0xda, 0x88, 0x83, 0x1b, 0x28, 0xf4, 0xd8, 0xad, 0x5a, 0xf2, 0xa3, 0x76, 0xb8, 0x57,
0x7f, 0x34, 0xf9, 0xbd, 0xbb, 0x5f, 0x57, 0x18, 0x87, 0x65, 0xd3, 0xe0, 0x5f, 0x9a, 0x6e, 0xac,
0x79, 0xfe, 0x2a, 0xf2, 0x2c, 0xc7, 0xa5, 0xb6, 0xbf, 0x89, 0x83, 0x1d, 0x8b, 0xe2, 0x60, 0x13,
0x07, 0xd4, 0x38, 0x2a, 0x88, 0xfe, 0x56, 0x3b, 0x88, 0xcc, 0x7e, 0x88, 0xb6, 0xfe, 0x57, 0xe8,
0x4d, 0x12, 0xb2, 0x14, 0xe3, 0xed, 0xc8, 0x3c, 0xb7, 0x96, 0xca, 0xfc, 0x90, 0xd8, 0x38, 0x01,
0x3a, 0x91, 0xf9, 0xbc, 0x20, 0xac, 0x42, 0x15, 0xbc, 0xdb, 0x7b, 0xf5, 0x01, 0x95, 0x6a, 0x67,
0xaf, 0xae, 0xee, 0xa0, 0xe8, 0xa8, 0x8a, 0x1b, 0x1c, 0x8c, 0x1b, 0xce, 0xa4, 0x4e, 0x25, 0x72,
0xf0, 0xb9, 0xca, 0x61, 0x4c, 0xd0, 0xaa, 0x87, 0x1d, 0xe3, 0xd8, 0x88, 0x36, 0xfa, 0xd8, 0xd4,
0x07, 0xdc, 0xe1, 0xb3, 0x99, 0xc5, 0x57, 0x62, 0xb0, 0xea, 0x6d, 0x02, 0x74, 0x22, 0xf3, 0x59,
0x85, 0xb7, 0x09, 0x2a, 0xb9, 0xcb, 0x82, 0x10, 0x73, 0x5f, 0xbb, 0x98, 0xe9, 0x06, 0x1c, 0xee,
0xd5, 0x1f, 0xe1, 0x4d, 0x77, 0xf7, 0xeb, 0x15, 0x52, 0x15, 0x37, 0x13, 0x39, 0xf8, 0x54, 0xd3,
0x87, 0x3c, 0xdf, 0x56, 0x7a, 0xf9, 0x88, 0xf0, 0xf2, 0xa7, 0xdc, 0xcb, 0x33, 0xf3, 0x5c, 0xa7,
0xe0, 0xe4, 0x80, 0x97, 0x88, 0x4a, 0x3e, 0x3e, 0x13, 0x2f, 0x41, 0x05, 0xa8, 0x70, 0x51, 0x6d,
0xa4, 0x8b, 0x5c, 0x72, 0xb0, 0xcc, 0x07, 0x9e, 0x13, 0x0d, 0x2a, 0xee, 0xfd, 0x55, 0xd3, 0xfb,
0x63, 0xf7, 0x50, 0x62, 0xcb, 0x6a, 0xf9, 0x01, 0x33, 0x8e, 0x8f, 0x68, 0xa3, 0xc7, 0xa7, 0x7e,
0xc8, 0x5d, 0xeb, 0x49, 0x4d, 0x2d, 0xfa, 0x01, 0x6b, 0x47, 0x66, 0x5f, 0xa1, 0x6b, 0x2e, 0xec,
0x44, 0xe6, 0xd3, 0x55, 0xa7, 0x38, 0x22, 0x79, 0x34, 0x31, 0x3e, 0x36, 0xf1, 0x5f, 0xb5, 0xc3,
0xc8, 0x3c, 0xe6, 0x12, 0xd6, 0xde, 0xab, 0x2b, 0xcc, 0xa8, 0x84, 0x87, 0x7b, 0xf5, 0xe3, 0xa2,
0xe9, 0xee, 0x7e, 0xbd, 0xc0, 0x04, 0x56, 0x75, 0xc1, 0xd7, 0x8e, 0xea, 0x23, 0x25, 0x6f, 0x9a,
0xa1, 0xc7, 0x5c, 0x1b, 0x51, 0x96, 0xc6, 0x0d, 0xe3, 0xc4, 0x88, 0x36, 0x7a, 0x72, 0xea, 0xf7,
0xdc, 0xb5, 0xde, 0xd4, 0xe0, 0xc2, 0x34, 0xdf, 0xc9, 0xed, 0xc8, 0xec, 0x2f, 0x18, 0x8d, 0xc5,
0x9d, 0xc8, 0xbc, 0x51, 0x75, 0x2f, 0xc6, 0x24, 0x07, 0xbf, 0xd0, 0x68, 0x8c, 0x4f, 0xdc, 0xba,
0x75, 0xf3, 0xda, 0xcd, 0xeb, 0x5f, 0xbc, 0x15, 0x7b, 0xdb, 0xde, 0xab, 0x2b, 0x0d, 0xaa, 0xc5,
0x87, 0x7b, 0x75, 0x50, 0x35, 0xb2, 0xbb, 0x5f, 0x2f, 0xd1, 0x84, 0x4f, 0x14, 0x1b, 0xa7, 0x1e,
0x26, 0xc1, 0x08, 0xdc, 0xd5, 0x4f, 0x37, 0xd1, 0xb6, 0x45, 0x31, 0x71, 0xac, 0x8d, 0xd5, 0x16,
0x35, 0x1e, 0x15, 0x93, 0xf9, 0x5c, 0x3b, 0x32, 0x4f, 0x35, 0xd1, 0xf6, 0x12, 0x26, 0xce, 0xed,
0xd5, 0x16, 0x0f, 0x2e, 0x7d, 0xc2, 0x2d, 0x49, 0x96, 0xce, 0x0f, 0x94, 0x15, 0x53, 0x83, 0x01,
0xb6, 0x37, 0x63, 0x83, 0x8f, 0x15, 0x0c, 0x42, 0x6c, 0x6f, 0x96, 0x0d, 0xa6, 0xb2, 0x82, 0xc1,
0x54, 0x08, 0x7e, 0xa7, 0xe9, 0x43, 0x01, 0xb6, 0x7d, 0x42, 0xb0, 0xcd, 0xc3, 0xbb, 0xe5, 0x12,
0x86, 0x83, 0x4d, 0xe4, 0x59, 0xd4, 0x38, 0x29, 0x6c, 0x7f, 0x45, 0x04, 0xf5, 0x54, 0x65, 0x2e,
0x81, 0x97, 0x78, 0xec, 0x90, 0x1b, 0x66, 0x40, 0x27, 0x32, 0x47, 0x45, 0xdf, 0x4a, 0x54, 0x9a,
0xa5, 0x1b, 0x63, 0x29, 0xa5, 0xc3, 0xbd, 0xfa, 0xd1, 0x1b, 0x63, 0x22, 0xbe, 0x57, 0xfa, 0x81,
0xea, 0x5e, 0x40, 0x43, 0xef, 0x0d, 0xb0, 0x87, 0x76, 0x68, 0x16, 0x03, 0x74, 0x11, 0x03, 0x5e,
0x6e, 0x47, 0xe6, 0xe9, 0x18, 0xc9, 0x37, 0x7a, 0x2d, 0x21, 0x24, 0x49, 0xcb, 0x3b, 0x3c, 0xdd,
0xb1, 0xb0, 0xd8, 0x18, 0xbc, 0x7b, 0x54, 0xbf, 0x90, 0x74, 0x94, 0x11, 0xc9, 0x07, 0xa9, 0x69,
0x9c, 0x12, 0x83, 0xf4, 0x27, 0xbe, 0x86, 0x87, 0x20, 0xd7, 0xab, 0xb8, 0xb0, 0xd0, 0x8e, 0xcc,
0xa1, 0x40, 0x0d, 0x65, 0x81, 0xb6, 0x0b, 0x2e, 0xb1, 0x1c, 0x1f, 0x93, 0xb6, 0x6c, 0x57, 0x7b,
0xdd, 0x21, 0x3e, 0xc8, 0xe3, 0x7c, 0x90, 0xbb, 0xd1, 0x84, 0x46, 0xec, 0x67, 0x15, 0x01, 0xab,
0xfa, 0x69, 0xca, 0x50, 0xc0, 0xac, 0xd5, 0xc0, 0xdf, 0xa2, 0x38, 0x30, 0x7a, 0xc4, 0x58, 0xff,
0x77, 0x3b, 0x32, 0x7b, 0x04, 0x30, 0x15, 0xcb, 0x3b, 0x91, 0xf9, 0xa4, 0x70, 0x47, 0x16, 0x76,
0x1d, 0xe9, 0x42, 0x53, 0xf0, 0x73, 0x4d, 0x3f, 0x47, 0x10, 0xb3, 0x58, 0x80, 0xf8, 0xa9, 0x86,
0xbc, 0x6c, 0x62, 0x7b, 0x45, 0x67, 0x6f, 0x1e, 0x44, 0xa6, 0x7e, 0x67, 0x72, 0x39, 0x0f, 0xeb,
0x3a, 0x41, 0x2c, 0x9f, 0x63, 0x53, 0x74, 0x9c, 0x8b, 0x14, 0x21, 0x5c, 0x6e, 0x50, 0xf8, 0x92,
0xc2, 0xb5, 0xd4, 0x05, 0xec, 0x27, 0x88, 0x2d, 0xa7, 0x74, 0xd2, 0x05, 0xf1, 0x87, 0x0a, 0x4f,
0x0f, 0x23, 0x8a, 0xad, 0xa6, 0x71, 0x46, 0x2c, 0x85, 0x6f, 0xf0, 0xa5, 0x70, 0xf2, 0xce, 0xe4,
0xf2, 0x3c, 0x17, 0xf3, 0xc9, 0x3f, 0x43, 0x10, 0x8b, 0x3f, 0x5c, 0x12, 0x32, 0x91, 0xfc, 0xd4,
0x52, 0xb2, 0xb2, 0x5c, 0xb9, 0x37, 0xda, 0x7b, 0xf5, 0x4a, 0xfb, 0xaa, 0x28, 0xdb, 0x41, 0x79,
0xc7, 0x10, 0xc8, 0xec, 0x63, 0x19, 0xf8, 0x8b, 0xa6, 0x0f, 0x15, 0xc9, 0x07, 0x98, 0xe0, 0x2d,
0xb1, 0x92, 0xcf, 0x0a, 0xfa, 0xbb, 0x9c, 0xfe, 0xa9, 0x3b, 0x93, 0xcb, 0x30, 0x06, 0xb8, 0x03,
0x7d, 0x04, 0xb1, 0xf4, 0x33, 0x73, 0xa1, 0x9e, 0xba, 0x50, 0x44, 0x24, 0x27, 0xae, 0xc9, 0x4e,
0x28, 0x6c, 0xa8, 0x84, 0xdc, 0x91, 0x6b, 0xdc, 0x11, 0x99, 0x02, 0x1c, 0x90, 0x5d, 0x49, 0xa5,
0x0a, 0x67, 0x98, 0xdb, 0xc4, 0x7e, 0xc8, 0x2c, 0x6a, 0xf4, 0x15, 0x9d, 0x59, 0x8e, 0x81, 0xa5,
0xc4, 0x99, 0xf4, 0x93, 0xaf, 0x74, 0xa7, 0xe0, 0x4c, 0x11, 0xe9, 0xb6, 0xfd, 0x14, 0x36, 0x54,
0xc2, 0x6c, 0xcb, 0xc9, 0x14, 0x8a, 0xce, 0xa4, 0x52, 0xf0, 0x23, 0x4d, 0x37, 0x42, 0x8a, 0xd6,
0xb0, 0x15, 0x60, 0x7e, 0xee, 0xbb, 0x64, 0xcd, 0x42, 0xb6, 0x8d, 0x5b, 0x0c, 0x3b, 0x06, 0x10,
0xde, 0x20, 0xbe, 0x03, 0x56, 0xe0, 0x64, 0x22, 0xe5, 0x3b, 0x20, 0x0c, 0xd2, 0xaf, 0x4e, 0x64,
0x9e, 0x15, 0x4e, 0xe4, 0x22, 0x89, 0xb0, 0xac, 0x58, 0xf8, 0xe2, 0x2b, 0x3e, 0x37, 0x09, 0x07,
0x05, 0x05, 0x98, 0x32, 0x48, 0xe5, 0xe0, 0x6d, 0x7d, 0xa0, 0x4c, 0x8e, 0x62, 0x4c, 0x8c, 0x7e,
0x41, 0x6c, 0xee, 0x20, 0x32, 0x4f, 0xac, 0xc0, 0x25, 0x8c, 0x49, 0x3b, 0x32, 0x4f, 0x84, 0x01,
0xff, 0xd5, 0x89, 0xcc, 0x9e, 0x84, 0x10, 0xff, 0x94, 0xc8, 0xa4, 0x0a, 0xd9, 0xaf, 0xdd, 0xfd,
0x7a, 0xd2, 0x1c, 0x82, 0x22, 0x01, 0x2e, 0x03, 0xdf, 0xd3, 0xf4, 0xc7, 0xcb, 0xbd, 0x87, 0xc4,
0x7d, 0x33, 0xc4, 0x96, 0xeb, 0x18, 0x03, 0x22, 0x89, 0x78, 0x23, 0x1e, 0x9b, 0x15, 0x21, 0x9e,
0x9b, 0x89, 0xc7, 0x26, 0xf9, 0x92, 0xc7, 0x26, 0x55, 0xa8, 0xc5, 0x83, 0x92, 0x7e, 0x76, 0xe4,
0xaf, 0x64, 0x50, 0x52, 0xac, 0x3c, 0x28, 0xa9, 0x16, 0xf8, 0x58, 0xd3, 0xfb, 0x2b, 0xbc, 0x02,
0xcf, 0x38, 0x27, 0x18, 0x7d, 0x8b, 0xaf, 0xbd, 0xe3, 0x2b, 0x70, 0x05, 0xce, 0xb7, 0x23, 0xf3,
0x78, 0x18, 0xac, 0xc0, 0xf9, 0x4e, 0x64, 0xde, 0x4c, 0x89, 0xc0, 0x79, 0x69, 0x75, 0xad, 0x33,
0xd6, 0xa2, 0xb7, 0xae, 0x5e, 0x75, 0x10, 0x43, 0x57, 0xe8, 0x0e, 0xb1, 0xd9, 0x3a, 0x2f, 0xd6,
0x08, 0x66, 0x57, 0x09, 0xde, 0xe2, 0x52, 0x4e, 0x38, 0x31, 0x92, 0xfe, 0x38, 0xdc, 0xab, 0x3f,
0x44, 0xc3, 0xdd, 0xfd, 0x7a, 0xcc, 0x02, 0xf6, 0x95, 0xfc, 0x08, 0x3c, 0xf0, 0x4f, 0x4d, 0x37,
0xcb, 0x2e, 0xb4, 0x7c, 0xca, 0x4f, 0x38, 0x8a, 0xed, 0x30, 0xc0, 0xde, 0x8e, 0x31, 0x28, 0xc2,
0xef, 0x0f, 0x44, 0x05, 0xb1, 0x02, 0x17, 0x7d, 0xca, 0xe6, 0x32, 0xb0, 0x1d, 0x99, 0x67, 0xc3,
0xa0, 0x28, 0xeb, 0x44, 0xe6, 0x53, 0x89, 0x93, 0x45, 0x40, 0xf2, 0xb7, 0x81, 0x3c, 0x2a, 0x42,
0x72, 0xb5, 0xb5, 0x42, 0xc6, 0x33, 0x4f, 0xd1, 0x82, 0xd7, 0x0b, 0x65, 0x0a, 0xf0, 0x62, 0xd1,
0xad, 0x22, 0x0a, 0xfe, 0xa1, 0xf0, 0xd0, 0x25, 0x2e, 0x73, 0x79, 0x1d, 0xc1, 0xcf, 0x3b, 0x8b,
0x1a, 0x43, 0x62, 0x15, 0x7f, 0x5f, 0x54, 0x0f, 0x2b, 0x70, 0x2e, 0x46, 0x67, 0x38, 0xc8, 0x03,
0xc6, 0x99, 0x30, 0x28, 0x88, 0xb2, 0x70, 0x51, 0x92, 0xcb, 0xc1, 0xe2, 0xe6, 0x58, 0x21, 0x80,
0x97, 0x2d, 0x54, 0x45, 0xfc, 0x04, 0xe2, 0xad, 0x78, 0xc1, 0x50, 0xa2, 0x00, 0x2f, 0x14, 0x1d,
0x2c, 0x80, 0xc0, 0xd7, 0xfb, 0x02, 0x1c, 0x1f, 0xce, 0x3e, 0xb1, 0xb6, 0xd0, 0x06, 0x0e, 0x5b,
0x86, 0x21, 0xa6, 0x6c, 0x9a, 0x93, 0x4f, 0xc0, 0xbb, 0xe4, 0x75, 0x01, 0x65, 0xe4, 0x4b, 0xf2,
0xae, 0x87, 0x74, 0xd9, 0x00, 0x78, 0x4f, 0xd3, 0x87, 0x50, 0xc8, 0x7c, 0x2b, 0x6c, 0xad, 0x05,
0xc8, 0xc1, 0x79, 0x32, 0xb4, 0x6e, 0x3c, 0x2e, 0x06, 0x72, 0x91, 0x97, 0x5c, 0x5c, 0x65, 0x25,
0xd6, 0x48, 0xf3, 0x88, 0x57, 0xb3, 0xea, 0x44, 0x05, 0xca, 0xc3, 0x37, 0x21, 0x67, 0x86, 0xe3,
0x13, 0x50, 0x69, 0x0d, 0x34, 0xf5, 0xa1, 0x94, 0x03, 0xf3, 0xad, 0x56, 0xc0, 0xa7, 0x58, 0x9c,
0xc5, 0xd4, 0x38, 0x2f, 0x06, 0xe0, 0x06, 0x27, 0x92, 0xa8, 0x2c, 0xfb, 0x8b, 0x01, 0x86, 0x09,
0xde, 0x89, 0xcc, 0xf3, 0xf1, 0x14, 0x2a, 0xc0, 0x1a, 0x54, 0xb6, 0x01, 0x9b, 0x3a, 0xd8, 0xc0,
0xb8, 0x65, 0x31, 0xdc, 0x6c, 0xf9, 0x01, 0x0a, 0x5c, 0x4c, 0xad, 0x75, 0xe3, 0x82, 0x70, 0xf9,
0x55, 0xbe, 0x11, 0x38, 0xba, 0x9c, 0x83, 0xdc, 0xdd, 0x4b, 0xa2, 0x97, 0x32, 0x20, 0xd7, 0x62,
0xd7, 0x65, 0x57, 0x27, 0xae, 0xc3, 0x8a, 0x15, 0xb0, 0xa3, 0xf7, 0xdb, 0xc8, 0x5e, 0xc7, 0x96,
0xbb, 0x46, 0xfc, 0x00, 0x3b, 0x56, 0xc3, 0xf5, 0x30, 0x35, 0x2e, 0x0a, 0x17, 0xe7, 0xf8, 0x89,
0x26, 0xe0, 0xb9, 0x18, 0x9d, 0xe5, 0x60, 0x36, 0xd0, 0x15, 0xa4, 0xb2, 0x07, 0xb3, 0xbd, 0x05,
0xab, 0x66, 0xc0, 0x77, 0x34, 0xfd, 0x7c, 0x2b, 0xf0, 0xd7, 0x78, 0x31, 0x63, 0x85, 0x2d, 0x07,
0x31, 0x2c, 0x17, 0x08, 0x4f, 0x08, 0xdf, 0x97, 0x79, 0x7e, 0x9b, 0x6a, 0xad, 0x08, 0x25, 0xb9,
0x18, 0x88, 0x8b, 0xec, 0x2e, 0xb8, 0x44, 0xe7, 0x45, 0x69, 0x20, 0xb4, 0x17, 0x61, 0x37, 0x8b,
0xe0, 0x5d, 0x4d, 0x1f, 0xf4, 0xdc, 0xa6, 0xcb, 0xac, 0x55, 0x44, 0x9c, 0x2d, 0xd7, 0x61, 0xeb,
0x96, 0x4b, 0x2c, 0x0f, 0x11, 0x63, 0x58, 0x0c, 0xc9, 0x82, 0x28, 0x1e, 0xb9, 0xc6, 0x54, 0xaa,
0x30, 0x47, 0xe6, 0x11, 0xc9, 0x0b, 0xfe, 0x2a, 0x76, 0x9f, 0x61, 0x51, 0x99, 0x02, 0xef, 0x68,
0x3a, 0x68, 0xba, 0xc4, 0x5a, 0xf7, 0x9b, 0xd8, 0x72, 0x5c, 0xba, 0x61, 0x35, 0x02, 0x8c, 0x0d,
0x73, 0x44, 0x1b, 0x3d, 0x35, 0xd1, 0x73, 0x25, 0xbe, 0x59, 0xbb, 0xb2, 0xe4, 0xbe, 0x85, 0xa7,
0x5e, 0xf9, 0x24, 0x32, 0x8f, 0xf0, 0x9d, 0xd8, 0x74, 0xc9, 0xab, 0x7e, 0x13, 0xcf, 0xb8, 0x74,
0x63, 0x36, 0xc0, 0x38, 0x5b, 0x1d, 0x25, 0xb9, 0xbc, 0x0f, 0x46, 0x2e, 0x73, 0x22, 0xc7, 0xc6,
0x47, 0x2e, 0xc3, 0x72, 0x73, 0x70, 0x4f, 0xd3, 0x7b, 0xd2, 0xf5, 0x2e, 0x8e, 0x9d, 0x11, 0x71,
0xec, 0xfc, 0x51, 0xa4, 0x3c, 0xe9, 0xa2, 0x8d, 0x0f, 0x9f, 0x53, 0x41, 0xfe, 0xd9, 0x89, 0xcc,
0x99, 0xb4, 0xe2, 0x48, 0x65, 0x8a, 0x83, 0x28, 0xd9, 0x01, 0xb4, 0x74, 0xa6, 0x34, 0x31, 0x43,
0x57, 0xbe, 0x44, 0x7d, 0xc2, 0x63, 0x77, 0xc1, 0x6c, 0xf1, 0xf3, 0x70, 0xaf, 0x3e, 0xfa, 0xb0,
0xa6, 0x78, 0x7e, 0x24, 0xf1, 0x85, 0xb9, 0x9d, 0xc0, 0x03, 0xaf, 0xeb, 0x7d, 0xc8, 0xdb, 0xe2,
0xd5, 0x57, 0x7c, 0x9b, 0x40, 0x30, 0xa3, 0xc6, 0x93, 0xe2, 0x12, 0x8f, 0x17, 0xbd, 0x67, 0x62,
0x50, 0x54, 0xe5, 0x77, 0x30, 0xe3, 0x0b, 0x7f, 0x20, 0x8e, 0x30, 0x05, 0x79, 0x0d, 0x96, 0x15,
0xc1, 0xbf, 0x35, 0x7d, 0xd4, 0xdf, 0xc4, 0xc1, 0x56, 0xe0, 0x32, 0x1e, 0x38, 0x9a, 0x3e, 0xc3,
0x96, 0x83, 0x37, 0x5d, 0x1b, 0x5b, 0x04, 0x35, 0x31, 0xe5, 0xe1, 0x34, 0x29, 0x84, 0x8c, 0x5a,
0x7e, 0xbd, 0x34, 0x74, 0x37, 0x6d, 0x04, 0x45, 0x9b, 0x19, 0xbc, 0x79, 0x87, 0xab, 0xb7, 0x23,
0xf3, 0x92, 0x5f, 0x81, 0x5c, 0x1b, 0x0b, 0xf4, 0x2e, 0x99, 0x8e, 0x4d, 0x75, 0x22, 0xf3, 0x25,
0x41, 0xf0, 0x21, 0x74, 0xbb, 0x2f, 0x4a, 0x5e, 0xc5, 0x75, 0xe1, 0x01, 0x1f, 0x86, 0x05, 0xf8,
0xaa, 0x7e, 0x8e, 0x87, 0x31, 0xcb, 0x25, 0x0e, 0xde, 0xb6, 0xf8, 0x4a, 0x5e, 0xf5, 0x7c, 0x7b,
0x83, 0x1a, 0x97, 0xc4, 0x96, 0xe6, 0x8b, 0x06, 0x70, 0x85, 0x39, 0x8e, 0x2f, 0xb8, 0x64, 0x4a,
0xa0, 0xd9, 0xad, 0x6d, 0x15, 0x52, 0x66, 0xca, 0x71, 0xfe, 0x0b, 0x15, 0x96, 0xc0, 0xdf, 0x79,
0xba, 0x4b, 0x90, 0xbd, 0x81, 0x1d, 0x8b, 0xf8, 0xcc, 0x6d, 0xb8, 0x36, 0x8a, 0xef, 0x1f, 0x1c,
0x6a, 0xd4, 0xc5, 0xfc, 0xbe, 0xcf, 0x87, 0x7b, 0x70, 0x25, 0x56, 0xba, 0x23, 0xe9, 0xcc, 0xcd,
0xf0, 0xd1, 0x1e, 0x0c, 0x95, 0x48, 0x27, 0x32, 0x2f, 0xc4, 0xa1, 0x5d, 0x05, 0x8b, 0xbb, 0x4a,
0x25, 0xd2, 0xd9, 0xab, 0x77, 0xb1, 0xb8, 0xbb, 0x5f, 0xef, 0xc2, 0x02, 0x2a, 0x5b, 0x38, 0x14,
0x40, 0xfd, 0x34, 0x0b, 0x50, 0xa3, 0xe1, 0xda, 0x96, 0xed, 0x21, 0x4a, 0x8d, 0xcb, 0x62, 0x58,
0x5f, 0xe0, 0xf5, 0x72, 0x02, 0x4c, 0x73, 0x79, 0x27, 0x32, 0x41, 0x3c, 0xa0, 0x92, 0x30, 0xbb,
0xa8, 0x29, 0xa8, 0x82, 0xb7, 0xf5, 0xfe, 0x64, 0x88, 0xad, 0x86, 0xef, 0x39, 0x38, 0xb0, 0x5a,
0x88, 0xad, 0x1b, 0x4f, 0x89, 0x5d, 0x7f, 0xfb, 0x20, 0x32, 0x2f, 0xcc, 0xe0, 0x56, 0x80, 0x6d,
0xc4, 0xb0, 0x33, 0x13, 0x2b, 0xce, 0x0a, 0xbd, 0x45, 0xc4, 0xd6, 0xdb, 0x91, 0xa9, 0xbd, 0x90,
0x55, 0xe7, 0x4e, 0x19, 0x7e, 0xde, 0x6f, 0xba, 0x7c, 0x92, 0xd8, 0x4e, 0xcd, 0xd0, 0x60, 0x5f,
0x05, 0x07, 0x1b, 0xfa, 0x59, 0x8a, 0x99, 0xe5, 0xf9, 0x5b, 0x56, 0x2b, 0x70, 0xfd, 0xc0, 0x65,
0x3b, 0xc6, 0xd3, 0x62, 0x53, 0x4c, 0xb6, 0x23, 0xb3, 0x97, 0x62, 0x36, 0xef, 0x6f, 0x2d, 0x26,
0x48, 0x16, 0xd9, 0x8a, 0xe2, 0xae, 0x29, 0x46, 0xa9, 0x39, 0xf8, 0x40, 0xd3, 0x07, 0x9b, 0x68,
0x3b, 0x75, 0xd3, 0xf6, 0x89, 0x1d, 0x06, 0x01, 0x26, 0xf6, 0x8e, 0x31, 0x2a, 0xc6, 0x91, 0x8a,
0xcb, 0x16, 0xb4, 0xb5, 0x80, 0xb6, 0x63, 0x8e, 0xd3, 0xb9, 0x0a, 0x3f, 0xf2, 0x9b, 0x0a, 0x79,
0x76, 0xe4, 0xab, 0xc0, 0x74, 0xc8, 0xc5, 0xed, 0x88, 0xda, 0x2e, 0x54, 0x5a, 0x05, 0x9f, 0x6a,
0x7a, 0xbf, 0x1d, 0x20, 0xba, 0x5e, 0xaa, 0x01, 0x9e, 0x11, 0xd3, 0xf2, 0xa1, 0xa8, 0x01, 0xa6,
0xd3, 0x1a, 0xc0, 0x4e, 0x6a, 0x80, 0xd9, 0xf8, 0x6c, 0xe6, 0xcd, 0xf2, 0x6c, 0x5c, 0x19, 0x86,
0x85, 0x4e, 0x35, 0xaf, 0x17, 0x62, 0xbe, 0x96, 0xfb, 0x2a, 0x46, 0x78, 0x75, 0x60, 0x27, 0xd5,
0x41, 0xfd, 0x61, 0xcc, 0xf0, 0xfa, 0x60, 0x3a, 0xae, 0x0f, 0x4a, 0xc6, 0x02, 0x0f, 0xfc, 0x44,
0xd3, 0x87, 0xca, 0xee, 0xa5, 0xd7, 0x32, 0xcf, 0x8a, 0xf9, 0x77, 0x0f, 0x22, 0xf3, 0xe4, 0x34,
0x94, 0x5e, 0x14, 0x8a, 0x56, 0xca, 0x2f, 0x0a, 0x4a, 0xb4, 0xdb, 0xd2, 0xd8, 0xdd, 0xaf, 0xe7,
0xb6, 0xa1, 0xda, 0x32, 0xf8, 0xba, 0xa6, 0x0f, 0x52, 0x16, 0x12, 0x8b, 0x67, 0x4e, 0xc8, 0x73,
0x37, 0xb1, 0x15, 0xe7, 0xc3, 0xd4, 0x78, 0x2e, 0xcb, 0x47, 0xfb, 0xb9, 0xc6, 0xed, 0x54, 0x61,
0x89, 0xe3, 0x4b, 0x59, 0x96, 0xa4, 0xc0, 0x8a, 0xc9, 0xbc, 0x14, 0xd0, 0x8e, 0x8d, 0xdf, 0x1c,
0x83, 0x2a, 0x6b, 0xbc, 0x46, 0x2e, 0xd1, 0xe0, 0x71, 0x95, 0x1a, 0xcf, 0x0b, 0x12, 0xaf, 0xf1,
0x44, 0xad, 0xd0, 0x6c, 0xc1, 0x25, 0x79, 0x2d, 0x51, 0x41, 0xe4, 0x1c, 0xb1, 0x10, 0x50, 0x27,
0xc6, 0x60, 0xd5, 0x0e, 0xcf, 0xca, 0x7b, 0x44, 0xef, 0xe9, 0x43, 0xd7, 0x0b, 0x22, 0x86, 0x3a,
0x07, 0x91, 0xd9, 0x0b, 0xd1, 0xd6, 0x12, 0x0b, 0xa5, 0x27, 0xae, 0x53, 0x34, 0xff, 0xcc, 0x2e,
0xa3, 0x72, 0xd9, 0x03, 0x9f, 0xe1, 0x4a, 0x16, 0xa1, 0x6c, 0x0f, 0x6c, 0xea, 0x67, 0x78, 0xd9,
0xb9, 0x8a, 0x28, 0xb6, 0xe2, 0x37, 0x47, 0xe3, 0xca, 0x88, 0x36, 0xda, 0x3b, 0xd1, 0x9b, 0xa6,
0x45, 0xcb, 0x42, 0x2a, 0x6e, 0x0f, 0x7b, 0x53, 0xd5, 0x58, 0x96, 0x45, 0x8e, 0xa2, 0xb8, 0x36,
0x92, 0x14, 0x21, 0xc9, 0xf2, 0x78, 0x67, 0xbf, 0xae, 0xc1, 0x52, 0x53, 0xf0, 0xdd, 0xa3, 0xfa,
0x25, 0x1e, 0x35, 0xb2, 0x70, 0xc1, 0x8b, 0x58, 0xdb, 0x6f, 0xf2, 0x25, 0x1b, 0xe0, 0x37, 0x43,
0x4c, 0x99, 0xb5, 0xe1, 0xae, 0x1a, 0x57, 0xc5, 0x74, 0xfc, 0x59, 0x4b, 0xde, 0x2a, 0x17, 0xd0,
0xf6, 0xf4, 0x1c, 0x8c, 0xf1, 0xdb, 0xee, 0x54, 0x3b, 0x32, 0xcd, 0x26, 0xda, 0xce, 0xb6, 0x38,
0x9b, 0x4b, 0x6c, 0xe4, 0x2a, 0xd9, 0x29, 0xf8, 0x00, 0x3d, 0xa9, 0x00, 0x7c, 0xa0, 0xc9, 0x07,
0xab, 0x24, 0xaf, 0x9f, 0x25, 0xba, 0xf0, 0x01, 0xcd, 0x56, 0xc1, 0xe7, 0x9a, 0x3e, 0x98, 0x3d,
0xc1, 0x78, 0x48, 0x7e, 0xb4, 0x1d, 0x13, 0x1b, 0xf8, 0x23, 0x3e, 0x12, 0x03, 0xe9, 0x13, 0xc6,
0xfc, 0xe4, 0x1d, 0xf9, 0xdd, 0x76, 0x00, 0x29, 0xe4, 0x59, 0x22, 0xad, 0x02, 0x55, 0x2f, 0x67,
0x4a, 0x23, 0x5d, 0xe4, 0xd2, 0xd6, 0x57, 0x92, 0x82, 0x79, 0x2b, 0x24, 0x3d, 0xfa, 0x6e, 0xea,
0xe7, 0xc5, 0x2b, 0x4b, 0x23, 0xf4, 0xbc, 0x24, 0xab, 0xf1, 0x49, 0x5a, 0xa2, 0x1a, 0xe3, 0xc2,
0xd3, 0x5b, 0x3c, 0x6b, 0xe0, 0x5a, 0xb3, 0xa1, 0xe7, 0x89, 0x7c, 0xe4, 0x2e, 0x49, 0x8a, 0xca,
0x4e, 0x64, 0x5e, 0x4c, 0x8e, 0x2c, 0x15, 0x5c, 0x83, 0x5d, 0xda, 0x81, 0xd7, 0xf4, 0xd3, 0x0d,
0x8c, 0x58, 0x18, 0x60, 0xab, 0xe1, 0xa1, 0x35, 0x6a, 0x4c, 0x88, 0x7d, 0x77, 0x99, 0x9f, 0xf4,
0x09, 0x30, 0xcb, 0xe5, 0xd9, 0x8b, 0x8c, 0x24, 0xac, 0xc1, 0x82, 0x0a, 0xd8, 0xd2, 0x87, 0xa4,
0x87, 0x98, 0xb8, 0xc6, 0xc1, 0xc4, 0x0f, 0xd7, 0xd6, 0x8d, 0x6b, 0x62, 0xd1, 0xbe, 0x2c, 0xc2,
0x6b, 0xa6, 0x32, 0xcf, 0x35, 0x5e, 0x11, 0x0a, 0x59, 0xd6, 0xa3, 0x44, 0xb3, 0x8c, 0x42, 0xdd,
0x18, 0x6c, 0xe8, 0x03, 0x95, 0x8e, 0x9b, 0x68, 0xdb, 0xb8, 0x2e, 0x7a, 0x7d, 0x89, 0x27, 0x83,
0xa5, 0x86, 0x0b, 0x68, 0xbb, 0x13, 0x99, 0x86, 0xaa, 0xcb, 0x05, 0xb4, 0x9d, 0xf5, 0xa7, 0x68,
0x06, 0xde, 0x3b, 0xaa, 0x9b, 0xe9, 0xed, 0x92, 0x85, 0x3c, 0x9e, 0x52, 0xf8, 0x9e, 0x63, 0x31,
0x8f, 0x5a, 0x3c, 0x7e, 0xb8, 0x3e, 0xa1, 0xc6, 0x8b, 0x62, 0xbe, 0x3e, 0xe6, 0x2b, 0xf3, 0x42,
0x7a, 0x97, 0x33, 0xc9, 0x55, 0xef, 0x7a, 0xce, 0xf2, 0xfc, 0xd2, 0xff, 0x25, 0x7a, 0xed, 0xc8,
0xbc, 0xe0, 0x76, 0x87, 0xb3, 0x7c, 0xe7, 0x3e, 0x3a, 0x7c, 0x7d, 0xde, 0xd7, 0xc6, 0xfd, 0xe1,
0xdd, 0xfd, 0xfa, 0xfd, 0x08, 0xc2, 0x6a, 0x5b, 0x8f, 0xa6, 0x20, 0xf8, 0xb2, 0xde, 0x13, 0xb6,
0x48, 0x2b, 0x3b, 0x50, 0x7f, 0x31, 0x2b, 0xdc, 0xfe, 0xff, 0x83, 0xc8, 0x3c, 0x97, 0xe7, 0x72,
0x2b, 0x8b, 0x64, 0x31, 0x3f, 0x5d, 0x45, 0x16, 0x97, 0x24, 0xb8, 0x2d, 0xd2, 0x4a, 0x00, 0x29,
0x7f, 0xdb, 0xdd, 0xaf, 0xab, 0x1b, 0x1b, 0x1a, 0x3c, 0x25, 0x35, 0x01, 0x3f, 0xd3, 0x92, 0xee,
0xd3, 0xe7, 0x8b, 0x0f, 0x66, 0xc5, 0x74, 0xbf, 0x23, 0xe2, 0x41, 0xd1, 0x44, 0xf6, 0x94, 0x21,
0xba, 0x1f, 0xc9, 0xba, 0x97, 0x9f, 0x20, 0x24, 0x0e, 0x79, 0xe0, 0x3b, 0xdf, 0x5d, 0x8b, 0x6f,
0x70, 0x55, 0x2f, 0x86, 0x06, 0xf5, 0xbc, 0x15, 0xf8, 0x8d, 0xa6, 0xf7, 0x0a, 0x9a, 0xf9, 0x43,
0xc5, 0x2f, 0x63, 0xa2, 0xdf, 0x14, 0xf5, 0x41, 0xd1, 0x84, 0xf4, 0x68, 0x21, 0xa8, 0xd6, 0x32,
0xaa, 0xc5, 0x67, 0x06, 0x25, 0xd9, 0x8b, 0xf7, 0xd3, 0xe3, 0x55, 0x80, 0xba, 0x2f, 0x43, 0x83,
0x3d, 0x72, 0xcb, 0x9c, 0x72, 0xfe, 0x1c, 0xf1, 0x61, 0x77, 0xca, 0xd2, 0xd3, 0x44, 0x89, 0x72,
0xf1, 0x31, 0xa1, 0x3b, 0xe5, 0x6e, 0x7a, 0x55, 0xca, 0xa9, 0x66, 0x4a, 0x39, 0x7b, 0x7d, 0x68,
0xe8, 0xf1, 0xb3, 0x67, 0x96, 0x3e, 0xfc, 0x6a, 0x56, 0xc4, 0xb1, 0xff, 0x29, 0xf2, 0x15, 0x2f,
0x87, 0x79, 0x1e, 0x21, 0x2d, 0xc6, 0x20, 0x47, 0x8a, 0xc5, 0x44, 0x8f, 0x84, 0x50, 0x71, 0x79,
0x53, 0xbd, 0x37, 0xb1, 0x5a, 0x36, 0x33, 0x3e, 0xe2, 0x43, 0xa4, 0x4d, 0x2d, 0x1c, 0x44, 0xe6,
0xc5, 0xbc, 0xc7, 0x85, 0xe2, 0xad, 0xc7, 0xa2, 0xcd, 0x8a, 0xe3, 0xd4, 0xac, 0xe0, 0xc5, 0xee,
0x41, 0x55, 0x81, 0xe7, 0x4a, 0x03, 0xa5, 0x4c, 0x81, 0xda, 0x88, 0x50, 0xe3, 0xd7, 0xf1, 0x2c,
0x2d, 0x97, 0x28, 0xc8, 0x27, 0xec, 0x12, 0x57, 0x2c, 0x51, 0xa8, 0xe0, 0xd5, 0xa9, 0x12, 0x4c,
0x2a, 0x7a, 0x53, 0xb7, 0x3f, 0xf9, 0x6c, 0xf8, 0xc8, 0xfe, 0x67, 0xc3, 0x47, 0x3e, 0x39, 0x18,
0xd6, 0xf6, 0x0f, 0x86, 0xb5, 0x6f, 0xdf, 0x1b, 0x3e, 0xf2, 0xfe, 0xbd, 0x61, 0x6d, 0xff, 0xde,
0xf0, 0x91, 0xbf, 0xdd, 0x1b, 0x3e, 0xf2, 0xc6, 0x33, 0x6b, 0x2e, 0x5b, 0x0f, 0x57, 0xaf, 0xd8,
0x7e, 0xf3, 0x6a, 0x96, 0xbf, 0x4b, 0xbf, 0xf2, 0xff, 0x71, 0xad, 0x9e, 0x10, 0x7f, 0xdc, 0xba,
0xf6, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1c, 0x3d, 0xe9, 0x4b, 0x24, 0x26, 0x00, 0x00,
}
func (m *OptionsConfiguration) Marshal() (dAtA []byte, err error) {
@@ -431,6 +438,18 @@ func (m *OptionsConfiguration) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0xc0
}
if m.InsecureAllowOldTLSVersions {
i--
if m.InsecureAllowOldTLSVersions {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x3
i--
dAtA[i] = 0xa8
}
if m.ConnectionLimitMax != 0 {
i = encodeVarintOptionsconfiguration(dAtA, i, uint64(m.ConnectionLimitMax))
i--
@@ -1072,6 +1091,9 @@ func (m *OptionsConfiguration) ProtoSize() (n int) {
if m.ConnectionLimitMax != 0 {
n += 2 + sovOptionsconfiguration(uint64(m.ConnectionLimitMax))
}
if m.InsecureAllowOldTLSVersions {
n += 3
}
if m.DeprecatedUPnPEnabled {
n += 4
}
@@ -2288,6 +2310,26 @@ func (m *OptionsConfiguration) Unmarshal(dAtA []byte) error {
break
}
}
case 53:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field InsecureAllowOldTLSVersions", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOptionsconfiguration
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.InsecureAllowOldTLSVersions = bool(v != 0)
case 9000:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedUPnPEnabled", wireType)
@@ -2433,10 +2475,7 @@ func (m *OptionsConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthOptionsconfiguration
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthOptionsconfiguration
}
if (iNdEx + skippy) > l {
+1 -4
View File
@@ -235,10 +235,7 @@ func (m *Size) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthSize
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthSize
}
if (iNdEx + skippy) > l {
+2 -5
View File
@@ -403,7 +403,7 @@ func (m *VersioningConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthVersioningconfiguration
}
if (iNdEx + skippy) > postIndex {
@@ -490,10 +490,7 @@ func (m *VersioningConfiguration) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthVersioningconfiguration
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthVersioningconfiguration
}
if (iNdEx + skippy) > l {
+1
View File
@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:generate -command counterfeiter go run github.com/maxbrunsfeld/counterfeiter/v6
//go:generate counterfeiter -o mocks/mocked_wrapper.go --fake-name Wrapper . Wrapper
package config
+207
View File
@@ -8,12 +8,26 @@ package connections
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/url"
"os"
"strings"
"testing"
"time"
"github.com/thejerf/suture/v4"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/nat"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
)
func TestFixupPort(t *testing.T) {
@@ -216,3 +230,196 @@ func TestConnectionStatus(t *testing.T) {
check(nil, nil)
}
func BenchmarkConnections(pb *testing.B) {
addrs := []string{
"tcp://127.0.0.1:0",
"quic://127.0.0.1:0",
"relay://127.0.0.1:22067",
}
sizes := []int{
1 << 10,
1 << 15,
1 << 20,
1 << 22,
}
haveRelay := false
// Check if we have a relay running locally
conn, err := net.DialTimeout("tcp", "127.0.0.1:22067", 100*time.Millisecond)
if err == nil {
haveRelay = true
_ = conn.Close()
}
for _, addr := range addrs {
for _, sz := range sizes {
for _, direction := range []string{"cs", "sc"} {
proto := strings.SplitN(addr, ":", 2)[0]
pb.Run(fmt.Sprintf("%s_%d_%s", proto, sz, direction), func(b *testing.B) {
if proto == "relay" && !haveRelay {
b.Skip("could not connect to relay")
}
withConnectionPair(b, addr, func(client, server internalConn) {
if direction == "sc" {
server, client = client, server
}
data := make([]byte, sz)
if _, err := rand.Read(data); err != nil {
b.Fatal(err)
}
total := 0
wg := sync.NewWaitGroup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
wg.Add(2)
go func() {
if err := sendMsg(client, data); err != nil {
b.Fatal(err)
}
wg.Done()
}()
go func() {
if err := recvMsg(server, data); err != nil {
b.Fatal(err)
}
total += sz
wg.Done()
}()
wg.Wait()
}
b.ReportAllocs()
b.SetBytes(int64(total / b.N))
})
})
}
}
}
}
func sendMsg(c internalConn, buf []byte) error {
n, err := c.Write(buf)
if n != len(buf) || err != nil {
return err
}
return nil
}
func recvMsg(c internalConn, buf []byte) error {
for read := 0; read != len(buf); {
n, err := c.Read(buf)
read += n
if err != nil {
return err
}
}
return nil
}
func withConnectionPair(b *testing.B, connUri string, h func(client, server internalConn)) {
// Root of the service tree.
supervisor := suture.New("main", suture.Spec{
PassThroughPanics: true,
})
cert := mustGetCert(b)
deviceId := protocol.NewDeviceID(cert.Certificate[0])
tlsCfg := tlsutil.SecureDefaultTLS13()
tlsCfg.Certificates = []tls.Certificate{cert}
tlsCfg.NextProtos = []string{"bench"}
tlsCfg.ClientAuth = tls.RequestClientCert
tlsCfg.SessionTicketsDisabled = true
tlsCfg.InsecureSkipVerify = true
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
supervisor.ServeBackground(ctx)
cfg := config.Configuration{
Options: config.OptionsConfiguration{
RelaysEnabled: true,
},
}
wcfg := config.Wrap("", cfg, deviceId, events.NoopLogger)
uri, err := url.Parse(connUri)
if err != nil {
b.Fatal(err)
}
lf, err := getListenerFactory(cfg, uri)
if err != nil {
b.Fatal(err)
}
natSvc := nat.NewService(deviceId, wcfg)
conns := make(chan internalConn, 1)
listenSvc := lf.New(uri, wcfg, tlsCfg, conns, natSvc)
supervisor.Add(listenSvc)
var addr *url.URL
for {
addrs := listenSvc.LANAddresses()
if len(addrs) > 0 {
if !strings.HasSuffix(addrs[0].Host, ":0") {
addr = addrs[0]
break
}
}
time.Sleep(time.Millisecond)
}
df, err := getDialerFactory(cfg, addr)
if err != nil {
b.Fatal(err)
}
dialer := df.New(cfg.Options, tlsCfg)
// Relays might take some time to register the device, so dial multiple times
clientConn, err := dialer.Dial(ctx, deviceId, addr)
if err != nil {
for i := 0; i < 10 && err != nil; i++ {
clientConn, err = dialer.Dial(ctx, deviceId, addr)
time.Sleep(100 * time.Millisecond)
}
if err != nil {
b.Fatal(err)
}
}
data := []byte("hello")
// Quic does not start a stream until some data is sent through, so send something for the AcceptStream
// to fire on the other side.
if err := sendMsg(clientConn, data); err != nil {
b.Fatal(err)
}
serverConn := <-conns
if err := recvMsg(serverConn, data); err != nil {
b.Fatal(err)
}
h(clientConn, serverConn)
_ = clientConn.Close()
_ = serverConn.Close()
}
func mustGetCert(b *testing.B) tls.Certificate {
f1, err := ioutil.TempFile("", "")
if err != nil {
b.Fatal(err)
}
f1.Close()
f2, err := ioutil.TempFile("", "")
if err != nil {
b.Fatal(err)
}
f2.Close()
cert, err := tlsutil.NewCertificate(f1.Name(), f2.Name(), "bench", 10)
if err != nil {
b.Fatal(err)
}
_ = os.Remove(f1.Name())
_ = os.Remove(f2.Name())
return cert
}
+8 -1
View File
@@ -93,8 +93,15 @@ func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL
type quicDialerFactory struct{}
func (quicDialerFactory) New(opts config.OptionsConfiguration, tlsCfg *tls.Config) genericDialer {
// So the idea is that we should probably try dialing every 20 seconds.
// However it would still be nice if this was adjustable/proportional to ReconnectIntervalS
// But prevent something silly like 1/3 = 0 etc.
quicInterval := opts.ReconnectIntervalS / 3
if quicInterval < 10 {
quicInterval = 10
}
return &quicDialer{commonDialer{
reconnectInterval: time.Duration(opts.ReconnectIntervalS) * time.Second,
reconnectInterval: time.Duration(quicInterval) * time.Second,
tlsCfg: tlsCfg,
}}
}
+61 -17
View File
@@ -48,6 +48,7 @@ type quicListener struct {
factory listenerFactory
address *url.URL
laddr net.Addr
mut sync.Mutex
}
@@ -82,18 +83,33 @@ func (t *quicListener) OnExternalAddressChanged(address *stun.Host, via string)
func (t *quicListener) serve(ctx context.Context) error {
network := strings.ReplaceAll(t.uri.Scheme, "quic", "udp")
packetConn, err := net.ListenPacket(network, t.uri.Host)
udpAddr, err := net.ResolveUDPAddr(network, t.uri.Host)
if err != nil {
l.Infoln("Listen (BEP/quic):", err)
return err
}
defer func() { _ = packetConn.Close() }()
svc, conn := stun.New(t.cfg, t, packetConn)
defer func() { _ = conn.Close() }()
wrapped := &stunConnQUICWrapper{
udpConn, err := net.ListenUDP(network, udpAddr)
if err != nil {
l.Infoln("Listen (BEP/quic):", err)
return err
}
defer func() { _ = udpConn.Close() }()
svc, conn := stun.New(t.cfg, t, udpConn)
defer conn.Close()
quicWrapper := quicWrapper{
PacketConn: conn,
underlying: packetConn.(*net.UDPConn),
underlying: udpConn,
}
var wrapped net.PacketConn = &quicWrapper
if oobConn, ok := conn.(oobConn); ok {
l.Debugf("wrapping in oob conn")
wrapped = &oobConnWrapper{
quicWrapper, oobConn,
}
}
go svc.Serve(ctx)
@@ -106,12 +122,22 @@ func (t *quicListener) serve(ctx context.Context) error {
l.Infoln("Listen (BEP/quic):", err)
return err
}
t.notifyAddressesChanged(t)
defer listener.Close()
t.notifyAddressesChanged(t)
defer t.clearAddresses(t)
l.Infof("QUIC listener (%v) starting", packetConn.LocalAddr())
defer l.Infof("QUIC listener (%v) shutting down", packetConn.LocalAddr())
l.Infof("QUIC listener (%v) starting", udpConn.LocalAddr())
defer l.Infof("QUIC listener (%v) shutting down", udpConn.LocalAddr())
t.mut.Lock()
t.laddr = udpConn.LocalAddr()
t.mut.Unlock()
defer func() {
t.mut.Lock()
t.laddr = nil
t.mut.Unlock()
}()
acceptFailures := 0
const maxAcceptFailures = 10
@@ -164,8 +190,8 @@ func (t *quicListener) URI() *url.URL {
}
func (t *quicListener) WANAddresses() []*url.URL {
uris := []*url.URL{t.uri}
t.mut.Lock()
uris := []*url.URL{maybeReplacePort(t.uri, t.laddr)}
if t.address != nil {
uris = append(uris, t.address)
}
@@ -174,9 +200,12 @@ func (t *quicListener) WANAddresses() []*url.URL {
}
func (t *quicListener) LANAddresses() []*url.URL {
addrs := []*url.URL{t.uri}
network := strings.ReplaceAll(t.uri.Scheme, "quic", "udp")
addrs = append(addrs, getURLsForAllAdaptersIfUnspecified(network, t.uri)...)
t.mut.Lock()
uri := maybeReplacePort(t.uri, t.laddr)
t.mut.Unlock()
addrs := []*url.URL{uri}
network := strings.ReplaceAll(uri.Scheme, "quic", "udp")
addrs = append(addrs, getURLsForAllAdaptersIfUnspecified(network, uri)...)
return addrs
}
@@ -219,17 +248,32 @@ func (quicListenerFactory) Enabled(cfg config.Configuration) bool {
return true
}
type stunConnQUICWrapper struct {
// quicWrapper provides methods used by quic
// https://github.com/lucas-clemente/quic-go/blob/master/packet_handler_map.go#L85
type quicWrapper struct {
net.PacketConn
underlying *net.UDPConn
}
// SetReadBuffer is required by QUIC < v0.20.0
func (s *stunConnQUICWrapper) SetReadBuffer(size int) error {
// SetReadBuffer is required by QUIC
func (s *quicWrapper) SetReadBuffer(size int) error {
return s.underlying.SetReadBuffer(size)
}
// SyscallConn is required by QUIC
func (s *stunConnQUICWrapper) SyscallConn() (syscall.RawConn, error) {
func (s *quicWrapper) SyscallConn() (syscall.RawConn, error) {
return s.underlying.SyscallConn()
}
// oobConn is used to assert that stun package returned a net.PacketConn that implements this interface.
// If it does, we then wrap quicWrapper in oobConnWrapper, to expose those methods to QUIC package.
type oobConn interface {
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
}
// See: https://pkg.go.dev/github.com/lucas-clemente/quic-go#OOBCapablePacketConn
type oobConnWrapper struct {
quicWrapper
oobConn
}
+17 -16
View File
@@ -44,38 +44,39 @@ type relayListener struct {
}
func (t *relayListener) serve(ctx context.Context) error {
clnt, err := client.NewClient(t.uri, t.tlsCfg.Certificates, nil, 10*time.Second)
clnt, err := client.NewClient(t.uri, t.tlsCfg.Certificates, 10*time.Second)
if err != nil {
l.Infoln("Listen (BEP/relay):", err)
return err
}
invitations := clnt.Invitations()
t.mut.Lock()
t.client = clnt
go clnt.Serve(ctx)
t.mut.Unlock()
// Start with nil, so that we send a addresses changed notification as soon as we connect somewhere.
var oldURI *url.URL
l.Infof("Relay listener (%v) starting", t)
defer l.Infof("Relay listener (%v) shutting down", t)
defer t.clearAddresses(t)
invitationCtx, cancel := context.WithCancel(ctx)
defer cancel()
go t.handleInvitations(invitationCtx, clnt)
return clnt.Serve(ctx)
}
func (t *relayListener) handleInvitations(ctx context.Context, clnt client.RelayClient) {
invitations := clnt.Invitations()
// Start with nil, so that we send a addresses changed notification as soon as we connect somewhere.
var oldURI *url.URL
for {
select {
case inv, ok := <-invitations:
if !ok {
if err := clnt.Error(); err != nil {
l.Infoln("Listen (BEP/relay):", err)
}
return err
}
case inv := <-invitations:
conn, err := client.JoinSession(ctx, inv)
if err != nil {
if errors.Cause(err) != context.Canceled {
if !errors.Is(err, context.Canceled) {
l.Infoln("Listen (BEP/relay): joining session:", err)
}
continue
@@ -119,7 +120,7 @@ func (t *relayListener) serve(ctx context.Context) error {
}
case <-ctx.Done():
return ctx.Err()
return
}
}
}
+43 -23
View File
@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:generate -command counterfeiter go run github.com/maxbrunsfeld/counterfeiter/v6
//go:generate counterfeiter -o mocks/service.go --fake-name Service . Service
package connections
@@ -141,10 +142,10 @@ type service struct {
natService *nat.Service
evLogger events.Logger
listenersMut sync.RWMutex
listeners map[string]genericListener
listenerTokens map[string]suture.ServiceToken
listenerSupervisor *suture.Supervisor
deviceAddressesChanged chan struct{}
listenersMut sync.RWMutex
listeners map[string]genericListener
listenerTokens map[string]suture.ServiceToken
}
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder, bepProtocolName string, tlsDefaultCommonName string, evLogger events.Logger) Service {
@@ -165,22 +166,10 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
natService: nat.NewService(myID, cfg),
evLogger: evLogger,
listenersMut: sync.NewRWMutex(),
listeners: make(map[string]genericListener),
listenerTokens: make(map[string]suture.ServiceToken),
// A listener can fail twice, rapidly. Any more than that and it
// will be put on suspension for ten minutes. Restarts and changes
// due to config are done by removing and adding services, so are
// not subject to these limitations.
listenerSupervisor: suture.New("c.S.listenerSupervisor", suture.Spec{
EventHook: func(e suture.Event) {
l.Infoln(e)
},
FailureThreshold: 2,
FailureBackoff: 600 * time.Second,
PassThroughPanics: true,
}),
deviceAddressesChanged: make(chan struct{}, 1),
listenersMut: sync.NewRWMutex(),
listeners: make(map[string]genericListener),
listenerTokens: make(map[string]suture.ServiceToken),
}
cfg.Subscribe(service)
@@ -198,7 +187,6 @@ func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *t
service.Add(svcutil.AsService(service.connect, fmt.Sprintf("%s/connect", service)))
service.Add(svcutil.AsService(service.handle, fmt.Sprintf("%s/handle", service)))
service.Add(service.listenerSupervisor)
service.Add(service.natService)
svcutil.OnSupervisorDone(service.Supervisor, func() {
@@ -392,6 +380,7 @@ func (s *service) connect(ctx context.Context) error {
l.Debugln("Next connection loop in", sleep)
select {
case <-s.deviceAddressesChanged:
case <-time.After(sleep):
case <-ctx.Done():
return ctx.Err()
@@ -644,8 +633,18 @@ func (s *service) createListener(factory listenerFactory, uri *url.URL) bool {
listener := factory.New(uri, s.cfg, s.tlsCfg, s.conns, s.natService)
listener.OnAddressesChanged(s.logListenAddressesChangedEvent)
// Retrying a listener many times in rapid succession is unlikely to help,
// thus back off quickly. A listener may soon be functional again, e.g. due
// to a network interface coming back online - retry every minute.
spec := svcutil.SpecWithInfoLogger(l)
spec.FailureThreshold = 2
spec.FailureBackoff = time.Minute
sup := suture.New(fmt.Sprintf("listenerSupervisor@%v", listener), spec)
sup.Add(listener)
s.listeners[uri.String()] = listener
s.listenerTokens[uri.String()] = s.listenerSupervisor.Add(listener)
s.listenerTokens[uri.String()] = s.Add(sup)
return true
}
@@ -675,6 +674,8 @@ func (s *service) CommitConfiguration(from, to config.Configuration) bool {
}
}
s.checkAndSignalConnectLoopOnUpdatedDevices(from, to)
s.listenersMut.Lock()
seen := make(map[string]struct{})
for _, addr := range to.Options.ListenAddresses() {
@@ -723,7 +724,7 @@ func (s *service) CommitConfiguration(from, to config.Configuration) bool {
for addr, listener := range s.listeners {
if _, ok := seen[addr]; !ok || listener.Factory().Valid(to) != nil {
l.Debugln("Stopping listener", addr)
s.listenerSupervisor.Remove(s.listenerTokens[addr])
s.Remove(s.listenerTokens[addr])
delete(s.listenerTokens, addr)
delete(s.listeners, addr)
}
@@ -733,6 +734,25 @@ func (s *service) CommitConfiguration(from, to config.Configuration) bool {
return true
}
func (s *service) checkAndSignalConnectLoopOnUpdatedDevices(from, to config.Configuration) {
oldDevices := make(map[protocol.DeviceID]config.DeviceConfiguration, len(from.Devices))
for _, dev := range from.Devices {
oldDevices[dev.DeviceID] = dev
}
for _, dev := range to.Devices {
oldDev, ok := oldDevices[dev.DeviceID]
if !ok || !util.EqualStrings(oldDev.Addresses, dev.Addresses) {
select {
case s.deviceAddressesChanged <- struct{}{}:
default:
// channel is blocked - a config update is already pending for the connection loop.
}
break
}
}
}
func (s *service) AllAddresses() []string {
s.listenersMut.RLock()
var addrs []string
+26 -11
View File
@@ -40,6 +40,7 @@ type tcpListener struct {
natService *nat.Service
mapping *nat.Mapping
laddr net.Addr
mut sync.RWMutex
}
@@ -60,25 +61,37 @@ func (t *tcpListener) serve(ctx context.Context) error {
l.Infoln("Listen (BEP/tcp):", err)
return err
}
t.notifyAddressesChanged(t)
registry.Register(t.uri.Scheme, tcaddr)
defer listener.Close()
// We might bind to :0, so use the port we've been given.
tcaddr = listener.Addr().(*net.TCPAddr)
t.notifyAddressesChanged(t)
defer t.clearAddresses(t)
registry.Register(t.uri.Scheme, tcaddr)
defer registry.Unregister(t.uri.Scheme, tcaddr)
l.Infof("TCP listener (%v) starting", listener.Addr())
defer l.Infof("TCP listener (%v) shutting down", listener.Addr())
l.Infof("TCP listener (%v) starting", tcaddr)
defer l.Infof("TCP listener (%v) shutting down", tcaddr)
mapping := t.natService.NewMapping(nat.TCP, tcaddr.IP, tcaddr.Port)
mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) {
t.notifyAddressesChanged(t)
})
// Should be called after t.mapping is nil'ed out.
defer t.natService.RemoveMapping(mapping)
t.mut.Lock()
t.mapping = mapping
t.laddr = tcaddr
t.mut.Unlock()
defer func() {
t.mut.Lock()
t.mapping = nil
t.laddr = nil
t.mut.Unlock()
}()
acceptFailures := 0
const maxAcceptFailures = 10
@@ -94,9 +107,6 @@ func (t *tcpListener) serve(ctx context.Context) error {
if err == nil {
conn.Close()
}
t.mut.Lock()
t.mapping = nil
t.mut.Unlock()
return nil
default:
}
@@ -146,8 +156,10 @@ func (t *tcpListener) URI() *url.URL {
}
func (t *tcpListener) WANAddresses() []*url.URL {
uris := []*url.URL{t.uri}
t.mut.RLock()
uris := []*url.URL{
maybeReplacePort(t.uri, t.laddr),
}
if t.mapping != nil {
addrs := t.mapping.ExternalAddresses()
for _, addr := range addrs {
@@ -179,8 +191,11 @@ func (t *tcpListener) WANAddresses() []*url.URL {
}
func (t *tcpListener) LANAddresses() []*url.URL {
addrs := []*url.URL{t.uri}
addrs = append(addrs, getURLsForAllAdaptersIfUnspecified(t.uri.Scheme, t.uri)...)
t.mut.RLock()
uri := maybeReplacePort(t.uri, t.laddr)
t.mut.RUnlock()
addrs := []*url.URL{uri}
addrs = append(addrs, getURLsForAllAdaptersIfUnspecified(uri.Scheme, uri)...)
return addrs
}
+27
View File
@@ -117,3 +117,30 @@ func isV4Local(ip net.IP) bool {
}
return false
}
func maybeReplacePort(uri *url.URL, laddr net.Addr) *url.URL {
if laddr == nil {
return uri
}
host, portStr, err := net.SplitHostPort(uri.Host)
if err != nil {
return uri
}
port, err := strconv.Atoi(portStr)
if err != nil {
return uri
}
if port != 0 {
return uri
}
_, lportStr, err := net.SplitHostPort(laddr.String())
if err != nil {
return uri
}
uriCopy := *uri
uriCopy.Host = net.JoinHostPort(host, lportStr)
return &uriCopy
}
+1 -1
View File
@@ -36,7 +36,7 @@ const (
// KeyTypeFolderStatistic <folder ID as string> <some string> = some value
KeyTypeFolderStatistic byte = 4
// KeyTypeVirtualMtime <int32 folder ID> <file name> = dbMtime
// KeyTypeVirtualMtime <int32 folder ID> <file name> = mtimeMapping
KeyTypeVirtualMtime byte = 5
// KeyTypeFolderIdx <int32 id> = string value
+90 -24
View File
@@ -70,6 +70,9 @@ type Lowlevel struct {
recheckInterval time.Duration
oneFileSetCreated chan struct{}
evLogger events.Logger
blockFilter *bloomFilter
versionFilter *bloomFilter
}
func NewLowlevel(backend backend.Backend, evLogger events.Logger, opts ...Option) (*Lowlevel, error) {
@@ -587,6 +590,18 @@ func (db *Lowlevel) dropFolderIndexIDs(folder []byte) error {
return t.Commit()
}
func (db *Lowlevel) dropIndexIDs() error {
t, err := db.newReadWriteTransaction()
if err != nil {
return err
}
defer t.close()
if err := t.deleteKeyPrefix([]byte{KeyTypeIndexID}); err != nil {
return err
}
return t.Commit()
}
func (db *Lowlevel) dropMtimes(folder []byte) error {
key, err := db.keyer.GenerateMtimesKey(nil, folder)
if err != nil {
@@ -663,7 +678,7 @@ func (db *Lowlevel) timeUntil(key string, every time.Duration) time.Duration {
return sleepTime
}
func (db *Lowlevel) gcIndirect(ctx context.Context) error {
func (db *Lowlevel) gcIndirect(ctx context.Context) (err error) {
// The indirection GC uses bloom filters to track used block lists and
// versions. This means iterating over all items, adding their hashes to
// the filter, then iterating over the indirected items and removing
@@ -674,8 +689,29 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
// Indirection GC needs to run when there are no modifications to the
// FileInfos or indirected items.
l.Debugln("Starting database GC")
// Create a new set of bloom filters, while holding the gcMut which
// guarantees that no other modifications are happening concurrently.
db.gcMut.Lock()
defer db.gcMut.Unlock()
capacity := indirectGCBloomCapacity
if db.gcKeyCount > capacity {
capacity = db.gcKeyCount
}
db.blockFilter = newBloomFilter(capacity)
db.versionFilter = newBloomFilter(capacity)
db.gcMut.Unlock()
defer func() {
// Forget the bloom filters on the way out.
db.gcMut.Lock()
db.blockFilter = nil
db.versionFilter = nil
db.gcMut.Unlock()
}()
var discardedBlocks, matchedBlocks, discardedVersions, matchedVersions int
t, err := db.newReadWriteTransaction()
if err != nil {
@@ -688,16 +724,13 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
// items. For simplicity's sake we track just one count, which is the
// highest of the various indirected items.
capacity := indirectGCBloomCapacity
if db.gcKeyCount > capacity {
capacity = db.gcKeyCount
}
blockFilter := newBloomFilter(capacity)
versionFilter := newBloomFilter(capacity)
// Iterate the FileInfos, unmarshal the block and version hashes and
// add them to the filter.
// This happens concurrently with normal database modifications, though
// those modifications will now also add their blocks and versions to
// the bloom filters.
it, err := t.NewPrefixIterator([]byte{KeyTypeDevice})
if err != nil {
return err
@@ -714,18 +747,35 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
if err := hashes.Unmarshal(it.Value()); err != nil {
return err
}
if len(hashes.BlocksHash) > 0 {
blockFilter.add(hashes.BlocksHash)
}
if len(hashes.VersionHash) > 0 {
versionFilter.add(hashes.VersionHash)
}
db.recordIndirectionHashes(hashes)
}
it.Release()
if err := it.Error(); err != nil {
return err
}
// For the next phase we grab the GC lock again and hold it for the rest
// of the method call. Now there can't be any further modifications to
// the database or the bloom filters.
db.gcMut.Lock()
defer db.gcMut.Unlock()
// Only print something if the process takes more than "a moment".
logWait := make(chan struct{})
logTimer := time.AfterFunc(10*time.Second, func() {
l.Infoln("Database GC in progress - many Syncthing operations will be unresponsive until it's finished")
close(logWait)
})
defer func() {
if logTimer.Stop() {
return
}
<-logWait // Make sure messages are sent in order.
l.Infof("Database GC complete (discarded/remaining: %v/%v blocks, %v/%v versions)",
discardedBlocks, matchedBlocks, discardedVersions, matchedVersions)
}()
// Iterate over block lists, removing keys with hashes that don't match
// the filter.
@@ -734,7 +784,6 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
return err
}
defer it.Release()
matchedBlocks := 0
for it.Next() {
select {
case <-ctx.Done():
@@ -743,13 +792,14 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
}
key := blockListKey(it.Key())
if blockFilter.has(key.Hash()) {
if db.blockFilter.has(key.Hash()) {
matchedBlocks++
continue
}
if err := t.Delete(key); err != nil {
return err
}
discardedBlocks++
}
it.Release()
if err := it.Error(); err != nil {
@@ -763,7 +813,6 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
if err != nil {
return err
}
matchedVersions := 0
for it.Next() {
select {
case <-ctx.Done():
@@ -772,13 +821,14 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
}
key := versionKey(it.Key())
if versionFilter.has(key.Hash()) {
if db.versionFilter.has(key.Hash()) {
matchedVersions++
continue
}
if err := t.Delete(key); err != nil {
return err
}
discardedVersions++
}
it.Release()
if err := it.Error(); err != nil {
@@ -795,15 +845,31 @@ func (db *Lowlevel) gcIndirect(ctx context.Context) error {
return err
}
return db.Compact()
l.Debugf("Finished GC (discarded/remaining: %v/%v blocks, %v/%v versions)", discardedBlocks, matchedBlocks, discardedVersions, matchedVersions)
return nil
}
func newBloomFilter(capacity int) bloomFilter {
func (db *Lowlevel) recordIndirectionHashesForFile(f *protocol.FileInfo) {
db.recordIndirectionHashes(IndirectionHashesOnly{BlocksHash: f.BlocksHash, VersionHash: f.VersionHash})
}
func (db *Lowlevel) recordIndirectionHashes(hs IndirectionHashesOnly) {
// must be called with gcMut held (at least read-held)
if db.blockFilter != nil && len(hs.BlocksHash) > 0 {
db.blockFilter.add(hs.BlocksHash)
}
if db.versionFilter != nil && len(hs.VersionHash) > 0 {
db.versionFilter.add(hs.VersionHash)
}
}
func newBloomFilter(capacity int) *bloomFilter {
var buf [16]byte
io.ReadFull(rand.Reader, buf[:])
return bloomFilter{
f: blobloom.NewOptimized(blobloom.Config{
return &bloomFilter{
f: blobloom.NewSyncOptimized(blobloom.Config{
Capacity: uint64(capacity),
FPRate: indirectGCBloomFalsePositiveRate,
MaxBits: 8 * indirectGCBloomMaxBytes,
@@ -815,7 +881,7 @@ func newBloomFilter(capacity int) bloomFilter {
}
type bloomFilter struct {
f *blobloom.Filter
f *blobloom.SyncFilter
k0, k1 uint64 // Random key for SipHash.
}
+11 -6
View File
@@ -26,11 +26,13 @@ func (db *Lowlevel) AddOrUpdatePendingDevice(device protocol.DeviceID, name, add
return db.Put(key, bs)
}
func (db *Lowlevel) RemovePendingDevice(device protocol.DeviceID) {
func (db *Lowlevel) RemovePendingDevice(device protocol.DeviceID) error {
key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
if err := db.Delete(key); err != nil {
l.Warnf("Failed to remove pending device entry: %v", err)
return err
}
return nil
}
// PendingDevices enumerates all entries. Invalid ones are dropped from the database
@@ -79,32 +81,35 @@ func (db *Lowlevel) AddOrUpdatePendingFolder(id string, of ObservedFolder, devic
}
// RemovePendingFolderForDevice removes entries for specific folder / device combinations.
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) {
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) error {
key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
if err != nil {
return
return err
}
if err := db.Delete(key); err != nil {
l.Warnf("Failed to remove pending folder entry: %v", err)
return err
}
return nil
}
// RemovePendingFolder removes all entries matching a specific folder ID.
func (db *Lowlevel) RemovePendingFolder(id string) {
func (db *Lowlevel) RemovePendingFolder(id string) error {
iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
if err != nil {
l.Infof("Could not iterate through pending folder entries: %v", err)
return
return err
}
defer iter.Release()
for iter.Next() {
if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
continue
}
if err := db.Delete(iter.Key()); err != nil {
if err = db.Delete(iter.Key()); err != nil {
l.Warnf("Failed to remove pending folder entry: %v", err)
}
}
return err
}
// Consolidated information about a pending folder
+54 -1
View File
@@ -20,7 +20,7 @@ import (
// do not put restrictions on downgrades (e.g. for repairs after a bugfix).
const (
dbVersion = 14
dbMigrationVersion = 16
dbMigrationVersion = 18
dbMinSyncthingVersion = "v1.9.0"
)
@@ -101,6 +101,8 @@ func (db *schemaUpdater) updateSchema() error {
{13, 13, "v1.7.0", db.updateSchemaTo13},
{14, 14, "v1.9.0", db.updateSchemaTo14},
{14, 16, "v1.9.0", db.checkRepairMigration},
{14, 17, "v1.9.0", db.migration17},
{14, 18, "v1.9.0", db.dropIndexIDsMigration},
}
for _, m := range migrations {
@@ -783,6 +785,57 @@ func (db *schemaUpdater) checkRepairMigration(_ int) error {
return nil
}
// migration17 finds all files that were pulled as invalid from an invalid
// global and make sure they get scanned/pulled again.
func (db *schemaUpdater) migration17(prev int) error {
if prev < 16 {
// Issue was introduced in migration to 16
return nil
}
t, err := db.newReadOnlyTransaction()
if err != nil {
return err
}
defer t.close()
for _, folderStr := range db.ListFolders() {
folder := []byte(folderStr)
meta, err := db.loadMetadataTracker(folderStr)
if err != nil {
return err
}
batch := NewFileInfoBatch(func(fs []protocol.FileInfo) error {
return db.updateLocalFiles(folder, fs, meta)
})
var innerErr error
err = t.withHave(folder, protocol.LocalDeviceID[:], nil, false, func(fi protocol.FileIntf) bool {
if fi.IsInvalid() && fi.FileLocalFlags() == 0 {
f := fi.(protocol.FileInfo)
f.SetMustRescan()
f.Version = protocol.Vector{}
batch.Append(f)
innerErr = batch.FlushIfFull()
return innerErr == nil
}
return true
})
if innerErr != nil {
return innerErr
}
if err != nil {
return err
}
if err := batch.Flush(); err != nil {
return err
}
}
return nil
}
func (db *schemaUpdater) dropIndexIDsMigration(_ int) error {
return db.dropIndexIDs()
}
func (db *schemaUpdater) rewriteGlobals(t readWriteTransaction) error {
it, err := t.NewPrefixIterator([]byte{KeyTypeGlobal})
if err != nil {
+1 -10
View File
@@ -451,21 +451,12 @@ func DropDeltaIndexIDs(db *Lowlevel) {
}
opStr := "DropDeltaIndexIDs"
l.Debugf(opStr)
dbi, err := db.NewPrefixIterator([]byte{KeyTypeIndexID})
err := db.dropIndexIDs()
if backend.IsClosed(err) {
return
} else if err != nil {
fatalError(err, opStr, db)
}
defer dbi.Release()
for dbi.Next() {
if err := db.Delete(dbi.Key()); err != nil && !backend.IsClosed(err) {
fatalError(err, opStr, db)
}
}
if err := dbi.Error(); err != nil && !backend.IsClosed(err) {
fatalError(err, opStr, db)
}
}
func normalizeFilenamesAndDropDuplicates(fs []protocol.FileInfo) []protocol.FileInfo {
-1
View File
@@ -472,7 +472,6 @@ func TestNeedWithInvalid(t *testing.T) {
remote0Have[0],
remote1Have[0],
remote0Have[2],
remote1Have[2],
}
replace(s, protocol.LocalDeviceID, localHave)
+11 -44
View File
@@ -1652,10 +1652,7 @@ func (m *FileVersion) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -1739,10 +1736,7 @@ func (m *VersionList) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -2222,10 +2216,7 @@ func (m *FileInfoTruncated) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -2309,10 +2300,7 @@ func (m *BlockList) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -2430,10 +2418,7 @@ func (m *IndirectionHashesOnly) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -2650,10 +2635,7 @@ func (m *Counts) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -2756,10 +2738,7 @@ func (m *CountsSet) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -2916,10 +2895,7 @@ func (m *FileVersionDeprecated) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -3003,10 +2979,7 @@ func (m *VersionListDeprecated) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -3141,10 +3114,7 @@ func (m *ObservedFolder) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
@@ -3291,10 +3261,7 @@ func (m *ObservedDevice) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
+18 -4
View File
@@ -398,12 +398,16 @@ func (t *readOnlyTransaction) withBlocksHash(folder, hash []byte, iterator Itera
f.Name = osutil.NativeFilename(f.Name)
if !bytes.Equal(f.BlocksHash, hash) {
l.Warnf("Mismatching block map list hashes: got %x expected %x", f.BlocksHash, hash)
msg := "Mismatching block map list hashes"
t.evLogger.Log(events.Failure, fmt.Sprintln(msg, "in withBlocksHash"))
l.Warnf("%v: got %x expected %x", msg, f.BlocksHash, hash)
continue
}
if f.IsDeleted() || f.IsInvalid() || f.IsDirectory() || f.IsSymlink() {
l.Warnf("Found something of unexpected type in block list map: %s", f)
msg := "Found something of unexpected type in block list map"
t.evLogger.Log(events.Failure, fmt.Sprintln(msg, "in withBlocksHash"))
l.Warnf("%v: %s", msg, f)
continue
}
@@ -534,6 +538,11 @@ func (t *readOnlyTransaction) withNeedLocal(folder []byte, truncate bool, fn Ite
type readWriteTransaction struct {
backend.WriteTransaction
readOnlyTransaction
indirectionTracker
}
type indirectionTracker interface {
recordIndirectionHashesForFile(f *protocol.FileInfo)
}
func (db *Lowlevel) newReadWriteTransaction(hooks ...backend.CommitHook) (readWriteTransaction, error) {
@@ -547,6 +556,7 @@ func (db *Lowlevel) newReadWriteTransaction(hooks ...backend.CommitHook) (readWr
ReadTransaction: tran,
keyer: db.keyer,
},
indirectionTracker: db,
}, nil
}
@@ -606,6 +616,8 @@ func (t readWriteTransaction) putFile(fkey []byte, fi protocol.FileInfo) error {
fi.VersionHash = nil
}
t.indirectionTracker.recordIndirectionHashesForFile(&fi)
fiBs := mustMarshal(&fi)
return t.Put(fkey, fiBs)
}
@@ -774,8 +786,10 @@ func (t readWriteTransaction) updateLocalNeed(keyBuf, folder, name []byte, add b
}
func Need(global FileVersion, haveLocal bool, localVersion protocol.Vector) bool {
// We never need a file without a valid version.
if global.Version.IsEmpty() {
// We never need an invalid file or a file without a valid version (just
// another way of expressing "invalid", really, until we fix that
// part...).
if global.IsInvalid() || global.Version.IsEmpty() {
return false
}
// We don't need a deleted file if we don't have it.
+70
View File
@@ -0,0 +1,70 @@
// Copyright (C) 2021 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package db
import "github.com/syncthing/syncthing/lib/protocol"
// How many files to send in each Index/IndexUpdate message.
const (
MaxBatchSizeBytes = 250 * 1024 // Aim for making index messages no larger than 250 KiB (uncompressed)
MaxBatchSizeFiles = 1000 // Either way, don't include more files than this
)
// FileInfoBatch is a utility to do file operations on the database in suitably
// sized batches.
type FileInfoBatch struct {
infos []protocol.FileInfo
size int
flushFn func([]protocol.FileInfo) error
}
func NewFileInfoBatch(fn func([]protocol.FileInfo) error) *FileInfoBatch {
return &FileInfoBatch{
infos: make([]protocol.FileInfo, 0, MaxBatchSizeFiles),
flushFn: fn,
}
}
func (b *FileInfoBatch) SetFlushFunc(fn func([]protocol.FileInfo) error) {
b.flushFn = fn
}
func (b *FileInfoBatch) Append(f protocol.FileInfo) {
b.infos = append(b.infos, f)
b.size += f.ProtoSize()
}
func (b *FileInfoBatch) Full() bool {
return len(b.infos) >= MaxBatchSizeFiles || b.size >= MaxBatchSizeBytes
}
func (b *FileInfoBatch) FlushIfFull() error {
if b.Full() {
return b.Flush()
}
return nil
}
func (b *FileInfoBatch) Flush() error {
if len(b.infos) == 0 {
return nil
}
if err := b.flushFn(b.infos); err != nil {
return err
}
b.Reset()
return nil
}
func (b *FileInfoBatch) Reset() {
b.infos = b.infos[:0]
b.size = 0
}
func (b *FileInfoBatch) Size() int {
return b.size
}
+1 -4
View File
@@ -298,10 +298,7 @@ func (m *Announce) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthLocal
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthLocal
}
if (iNdEx + skippy) > l {
+1
View File
@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:generate -command counterfeiter go run github.com/maxbrunsfeld/counterfeiter/v6
//go:generate counterfeiter -o mocks/manager.go --fake-name Manager . Manager
package discover
+1
View File
@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:generate -command counterfeiter go run github.com/maxbrunsfeld/counterfeiter/v6
//go:generate counterfeiter -o mocks/buffered_subscription.go --fake-name BufferedSubscription . BufferedSubscription
// Package events provides event subscription and polling functionality.
+8
View File
@@ -330,6 +330,14 @@ func (f *BasicFilesystem) SameFile(fi1, fi2 FileInfo) bool {
return os.SameFile(f1.osFileInfo(), f2.osFileInfo())
}
func (f *BasicFilesystem) underlying() (Filesystem, bool) {
return nil, false
}
func (f *BasicFilesystem) wrapperType() filesystemWrapperType {
return filesystemWrapperTypeNone
}
// basicFile implements the fs.File interface on top of an os.File
type basicFile struct {
*os.File
+3 -2
View File
@@ -10,8 +10,9 @@ package fs
import "github.com/syncthing/notify"
// notify.InAttrib is not only required for permissions, but also mod. time changes
const (
subEventMask = notify.InCreate | notify.InMovedTo | notify.InDelete | notify.InDeleteSelf | notify.InModify | notify.InMovedFrom | notify.InMoveSelf
permEventMask = notify.InAttrib
subEventMask = notify.InCreate | notify.InMovedTo | notify.InDelete | notify.InDeleteSelf | notify.InModify | notify.InMovedFrom | notify.InMoveSelf | notify.InAttrib
permEventMask = 0
rmEventMask = notify.InDelete | notify.InDeleteSelf | notify.InMovedFrom | notify.InMoveSelf
)
+3 -2
View File
@@ -13,7 +13,8 @@ import "github.com/syncthing/notify"
const (
// Platform independent notify.Create is required, as kqueue does not have
// any event signalling file creation, but notify does generate those internally.
subEventMask = notify.NoteDelete | notify.NoteWrite | notify.NoteRename | notify.Create
permEventMask = notify.NoteAttrib | notify.NoteExtend
// NoteAttrib is not only required for permissions, but also mod. time changes
subEventMask = notify.NoteDelete | notify.NoteWrite | notify.NoteRename | notify.Create | notify.NoteAttrib | notify.NoteExtend
permEventMask = 0
rmEventMask = notify.NoteDelete | notify.NoteRename
)
+39 -7
View File
@@ -87,7 +87,7 @@ func TestWatchIgnore(t *testing.T) {
{name, NonRemove},
}
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{ignore: filepath.Join(name, ignored), skipIgnoredDirs: true})
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{ignore: filepath.Join(name, ignored), skipIgnoredDirs: true}, false)
}
func TestWatchInclude(t *testing.T) {
@@ -114,7 +114,7 @@ func TestWatchInclude(t *testing.T) {
{name, NonRemove},
}
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{ignore: filepath.Join(name, ignored), include: filepath.Join(name, included)})
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{ignore: filepath.Join(name, ignored), include: filepath.Join(name, included)}, false)
}
func TestWatchRename(t *testing.T) {
@@ -146,7 +146,7 @@ func TestWatchRename(t *testing.T) {
// set the "allow others" flag because we might get the create of
// "oldfile" initially
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{})
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, false)
}
// TestWatchWinRoot checks that a watch at a drive letter does not panic due to
@@ -308,7 +308,7 @@ func TestWatchOverflow(t *testing.T) {
}
}
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{})
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, false)
}
func TestWatchErrorLinuxInterpretation(t *testing.T) {
@@ -413,7 +413,39 @@ func TestWatchIssue4877(t *testing.T) {
testFs = origTestFs
}()
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{})
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, false)
}
func TestWatchModTime(t *testing.T) {
name := "modtime"
file := createTestFile(name, "foo")
path := filepath.Join(name, file)
now := time.Now()
before := now.Add(-10 * time.Second)
if err := testFs.Chtimes(path, before, before); err != nil {
t.Fatal(err)
}
testCase := func() {
if err := testFs.Chtimes(path, now, now); err != nil {
t.Error(err)
}
}
expectedEvents := []Event{
{file, NonRemove},
}
var allowedEvents []Event
// Apparently an event for the parent is also sent on mac
if runtime.GOOS == "darwin" {
allowedEvents = []Event{
{name, NonRemove},
}
}
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, true)
}
// path relative to folder root, also creates parent dirs if necessary
@@ -442,7 +474,7 @@ func sleepMs(ms int) {
time.Sleep(time.Duration(ms) * time.Millisecond)
}
func testScenario(t *testing.T, name string, testCase func(), expectedEvents, allowedEvents []Event, fm fakeMatcher) {
func testScenario(t *testing.T, name string, testCase func(), expectedEvents, allowedEvents []Event, fm fakeMatcher, ignorePerms bool) {
if err := testFs.MkdirAll(name, 0755); err != nil {
panic(fmt.Sprintf("Failed to create directory %s: %s", name, err))
}
@@ -451,7 +483,7 @@ func testScenario(t *testing.T, name string, testCase func(), expectedEvents, al
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventChan, errChan, err := testFs.Watch(name, fm, ctx, false)
eventChan, errChan, err := testFs.Watch(name, fm, ctx, ignorePerms)
if err != nil {
panic(err)
}
+5 -5
View File
@@ -157,9 +157,9 @@ func (f *BasicFilesystem) Roots() ([]string, error) {
// pathseparator.
func (f *BasicFilesystem) unrootedChecked(absPath string, roots []string) (string, error) {
absPath = f.resolveWin83(absPath)
lowerAbsPath := UnicodeLowercase(absPath)
lowerAbsPath := UnicodeLowercaseNormalized(absPath)
for _, root := range roots {
lowerRoot := UnicodeLowercase(root)
lowerRoot := UnicodeLowercaseNormalized(root)
if lowerAbsPath+string(PathSeparator) == lowerRoot {
return ".", nil
}
@@ -171,7 +171,7 @@ func (f *BasicFilesystem) unrootedChecked(absPath string, roots []string) (strin
}
func rel(path, prefix string) string {
lowerRel := strings.TrimPrefix(strings.TrimPrefix(UnicodeLowercase(path), UnicodeLowercase(prefix)), string(PathSeparator))
lowerRel := strings.TrimPrefix(strings.TrimPrefix(UnicodeLowercaseNormalized(path), UnicodeLowercaseNormalized(prefix)), string(PathSeparator))
return path[len(path)-len(lowerRel):]
}
@@ -193,8 +193,8 @@ func (f *BasicFilesystem) resolveWin83(absPath string) string {
}
// Failed getting the long path. Return the part of the path which is
// already a long path.
lowerRoot := UnicodeLowercase(f.root)
for absPath = filepath.Dir(absPath); strings.HasPrefix(UnicodeLowercase(absPath), lowerRoot); absPath = filepath.Dir(absPath) {
lowerRoot := UnicodeLowercaseNormalized(f.root)
for absPath = filepath.Dir(absPath); strings.HasPrefix(UnicodeLowercaseNormalized(absPath), lowerRoot); absPath = filepath.Dir(absPath) {
if !isMaybeWin83(absPath) {
return absPath
}
+15 -3
View File
@@ -15,6 +15,7 @@ import (
"time"
lru "github.com/hashicorp/golang-lru"
"golang.org/x/text/unicode/norm"
)
const (
@@ -339,6 +340,14 @@ func (f *caseFilesystem) Unhide(name string) error {
return f.Filesystem.Unhide(name)
}
func (f *caseFilesystem) underlying() (Filesystem, bool) {
return f.Filesystem, true
}
func (f *caseFilesystem) wrapperType() filesystemWrapperType {
return filesystemWrapperTypeCase
}
func (f *caseFilesystem) checkCase(name string) error {
var err error
if name, err = Canonicalize(name); err != nil {
@@ -367,7 +376,10 @@ func (f *caseFilesystem) checkCaseExisting(name string) error {
if err != nil {
return err
}
if realName != name {
// We normalize the normalization (hah!) of the strings before
// comparing, as we don't want to treat a normalization difference as a
// case conflict.
if norm.NFC.String(realName) != norm.NFC.String(name) {
return &ErrCaseConflict{name, realName}
}
return nil
@@ -416,7 +428,7 @@ func (r *defaultRealCaser) realCase(name string) (string, error) {
lastLower := ""
for _, n := range dirNames {
node.children[n] = struct{}{}
lower := UnicodeLowercase(n)
lower := UnicodeLowercaseNormalized(n)
if lower != lastLower {
node.lowerToReal[lower] = n
lastLower = n
@@ -429,7 +441,7 @@ func (r *defaultRealCaser) realCase(name string) (string, error) {
// Try to find a direct or case match
if _, ok := node.children[comp]; !ok {
comp, ok = node.lowerToReal[UnicodeLowercase(comp)]
comp, ok = node.lowerToReal[UnicodeLowercaseNormalized(comp)]
if !ok {
return "", ErrNotExist
}
+12 -3
View File
@@ -161,7 +161,10 @@ func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
b.Fatal(err)
}
b.Run("rawfs", func(b *testing.B) {
fakefs := unwrapFilesystem(fsys).(*fakefs)
var fakefs *fakeFS
if ffs, ok := unwrapFilesystem(fsys, filesystemWrapperTypeNone); ok {
fakefs = ffs.(*fakeFS)
}
fakefs.resetCounters()
benchmarkWalkFakeFS(b, fsys, paths, 0, "")
fakefs.reportMetricsPerOp(b)
@@ -174,7 +177,10 @@ func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
Filesystem: fsys,
realCaser: newDefaultRealCaser(fsys),
}
fakefs := unwrapFilesystem(fsys).(*fakefs)
var fakefs *fakeFS
if ffs, ok := unwrapFilesystem(fsys, filesystemWrapperTypeNone); ok {
fakefs = ffs.(*fakeFS)
}
fakefs.resetCounters()
benchmarkWalkFakeFS(b, casefs, paths, 0, "")
fakefs.reportMetricsPerOp(b)
@@ -197,7 +203,10 @@ func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
Filesystem: fsys,
realCaser: newDefaultRealCaser(fsys),
}
fakefs := unwrapFilesystem(fsys).(*fakefs)
var fakefs *fakeFS
if ffs, ok := unwrapFilesystem(fsys, filesystemWrapperTypeNone); ok {
fakefs = ffs.(*fakeFS)
}
fakefs.resetCounters()
benchmarkWalkFakeFS(b, casefs, paths, otherOpEvery, otherOpPath)
fakefs.reportMetricsPerOp(b)
+2 -1
View File
@@ -18,7 +18,8 @@ import (
// reason for existence is the Windows version, which allows creating
// symlinks when non-elevated.
func DebugSymlinkForTestsOnly(oldFs, newFs Filesystem, oldname, newname string) error {
if caseFs, ok := unwrapFilesystem(newFs).(*caseFilesystem); ok {
if fs, ok := unwrapFilesystem(newFs, filesystemWrapperTypeCase); ok {
caseFs := fs.(*caseFilesystem)
if err := caseFs.checkCase(newname); err != nil {
return err
}
+8
View File
@@ -52,3 +52,11 @@ func (fs *errorFilesystem) SameFile(fi1, fi2 FileInfo) bool { return false }
func (fs *errorFilesystem) Watch(path string, ignore Matcher, ctx context.Context, ignorePerms bool) (<-chan Event, <-chan error, error) {
return nil, nil, fs.err
}
func (fs *errorFilesystem) underlying() (Filesystem, bool) {
return nil, false
}
func (fs *errorFilesystem) wrapperType() filesystemWrapperType {
return filesystemWrapperTypeError
}

Some files were not shown because too many files have changed in this diff Show More