Compare commits

...

947 Commits

Author SHA1 Message Date
Jonathan
490ec4350c lib/model: Fix config deadlock when deleting a paused folder (#7854) 2021-07-30 14:41:57 +02:00
Simon Frei
dc0dd09e93 lib/model: Don't try to delete deleted item on revert (#7843) 2021-07-23 14:26:20 +02:00
Simon Frei
7ec76095e6 gui, script: Parse JS files for translation values (fixes #7845) (#7846) 2021-07-23 14:24:08 +02:00
Simon Frei
cb26552440 gui, script: Fix various gui string/translation issues (fixes #7839) (#7842) 2021-07-22 11:47:03 +02:00
Simon Frei
1ae5ac7d0b cmd/stcrashreceiver: Sanitize failure report fingerprints (#7840) 2021-07-22 11:16:24 +02:00
Simon Frei
eeb7091180 lib/model: Missing fmut-lock on encryption failures (#7841) 2021-07-22 11:15:25 +02:00
greatroar
dc38e6ae88 lib/relay/client: Stricter typing and remove unused code (#7819) 2021-07-21 09:49:09 +02:00
Jakob Borg
eb6cad7f93 gui, man, authors: Update docs, translations, and contributors 2021-07-21 07:45:25 +02:00
jtagcat
ae30b46bfe gui: advanced: On open collapse all, inc. GUI section. (#7820) 2021-07-16 06:40:30 +02:00
Jakob Borg
eab268f5f8 gui, man, authors: Update docs, translations, and contributors 2021-07-14 07:45:27 +02:00
greatroar
1e21042138 lib/connections: switch statement to get the QUIC network (#7816) 2021-07-10 13:53:51 +02:00
Jakob Borg
a56f70ab94 gui, man, authors: Update docs, translations, and contributors 2021-07-07 07:45:25 +02:00
Chih-Hsuan Yen
11c57b9097 lib/connections: Resolve IPv6 for quic6:// peers (fixes #7809) (#7810)
Before this patch, IPv4-compatible addresses (::ffff:aaa.bbb.ccc.ddd)
may be used if a quic6://some.domain:port is specified and both IPv4 and
IPv6 addresses exist for that domain name.
2021-07-05 13:19:56 +02:00
Simon Frei
1921533c4c lib/connections: Fully dial resumed devices (#7798) 2021-07-03 18:26:55 +02:00
Simon Frei
89e762fd6e lib/model: Prevent folder-type change from/to encrypted (fixes #7704) (#7796) 2021-07-03 13:47:04 +02:00
Simon Frei
a63d3ee625 lib/model: Scan removed dirs when reverting recv-enc (fixes #7706) (#7797) 2021-07-03 13:46:24 +02:00
Jakob Borg
82741ad207 gui, man, authors: Update docs, translations, and contributors 2021-06-30 07:45:30 +02:00
greatroar
bd363fe0b7 lib/protocol: Write uncompressible messages uncompressed (#7790) 2021-06-27 17:59:30 +02:00
Vladimir Rusinov
7a4c6d262f build: Remove no longer used temporaryBuildDir (#7795) 2021-06-27 17:59:02 +02:00
Simon Frei
445a82f120 lib/model: Compare all items with global on scan (fixes #7740) (#7791) 2021-06-27 08:48:54 +02:00
Simon Frei
69ce121267 lib/db: Missing event-logger in write-transaction (#7793) 2021-06-27 08:43:49 +02:00
Simon Frei
08e3cd1cce lib/fs: Set expiry after DirNames in case-fs (#7794) 2021-06-27 08:30:02 +02:00
André Colomb
da0e5edbec gui: Fix typo "recurr", again and for real (#7788) 2021-06-25 12:08:18 +02:00
Simon Frei
c78fa42f31 lib/connections: Dial devices in parallel (#7783) 2021-06-25 11:38:04 +02:00
Jakob Borg
993a3ebe73 lib/api: Always include usage reporting data in support bundle (#7786) 2021-06-24 22:00:14 +04:00
Jakob Borg
8040502599 gui, man, authors: Update docs, translations, and contributors 2021-06-23 07:45:27 +02:00
Simon Frei
c84e8d1e09 gui: Consider size 0 items in remote completion (fixes #7741) (#7781) 2021-06-21 22:53:50 +02:00
Simon Frei
5fb72eed85 gui: Make listener/discovery modal more discoverable (#7780) 2021-06-21 21:44:28 +02:00
Simon Frei
400d62c1e6 lib/connections: Missed map init in nextDialAt (ref #7753) (#7778) 2021-06-17 21:13:57 +04:00
Simon Frei
857caf3637 lib/connections: Trigger dialer when connection gets closed (#7753) 2021-06-17 13:57:44 +02:00
Simon Frei
aeca1fb575 lib/db: Check if sequences change when repairing metadata (#7770) 2021-06-17 13:53:39 +02:00
Simon Frei
ac2988a485 gui, lib: Handle pw adding remote encrypted folder (fixes #7705) (#7772) 2021-06-17 13:53:02 +02:00
Simon Frei
cb5ef250f4 build: Add codecov upload script to repo (#7776) 2021-06-17 13:52:10 +02:00
Simon Frei
23a0e18292 lib/db: Fix accounting bug when dropping indexes (#7774) 2021-06-17 10:15:11 +02:00
Simon Frei
aa6c55dec1 lib/model: Remove bogus failureevent when restarting folder (#7773) 2021-06-17 08:57:24 +02:00
André Colomb
7e0c24ec89 gui: Move the QR code button next to device ID in editDevice modal (#7653) 2021-06-16 21:10:16 +02:00
Simon Frei
2c7d9b59c6 gui: Fix race in online event callback (fixes #7733) (#7771) 2021-06-16 19:32:30 +02:00
Jakob Borg
adb7763f87 gui, man, authors: Update docs, translations, and contributors 2021-06-16 07:45:27 +02:00
André Colomb
89740490ac gui: Fix typo in new tooltip. (#7769) 2021-06-14 23:06:24 +02:00
greatroar
0b290f7206 all: go mod tidy (#7758) 2021-06-10 13:16:44 +02:00
Simon Frei
1e7a3997e3 lib/db, lib/model: Improve error handling on pending items (#7754) 2021-06-09 13:35:17 +02:00
Anur
e7f8538e4d lib/fs: Add bitmasks for Darwin to handle change to empty files (fixes #7731) (#7756) 2021-06-09 12:57:06 +02:00
Jakob Borg
18a608a6ff gui, man, authors: Update docs, translations, and contributors 2021-06-09 07:45:34 +02:00
Simon Frei
1a22689328 lib/db: Add failure reports to failures iterating over hashes (#7755) 2021-06-07 23:10:35 +02:00
Jakob Borg
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é Colomb
45edad867c all: Allow dismissing pending devices / folders without ignoring (fixes #7700) (#7712) 2021-06-07 10:29:24 +02:00
André Colomb
ea0a408849 gui: Modal dialog for listeners and discovery status (#7539) 2021-06-07 09:08:44 +02:00
Simon Frei
18592af993 lib/model: Fix wrongly hardcoded arguments in test helper (#7749) 2021-06-05 17:01:23 +02:00
Simon Frei
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 Frei
6494a9332d lib/model: Fix test introduced in #7714 failing due to #7689 (#7745) 2021-06-04 15:32:47 +02:00
Simon Frei
41baccb85d lib/model: Fix passwords on receive-enc needing token (ref #7518) (#7739) 2021-06-03 15:39:49 +02:00
Simon Frei
52eb7392c4 lib/api, lib/config: Apply defaults before deserializing json (#7690) 2021-06-03 15:09:35 +02:00
Simon Frei
855c53ad02 lib/model: Fix reverting when version has only our own ID (fixes #7708) (#7714) 2021-06-03 15:08:56 +02:00
Simon Frei
004eded398 lib/model: Don't share with introduced device if encrypted (fixes #7724) (#7734) 2021-06-03 15:02:57 +02:00
Simon Frei
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é Colomb
de6fe4dc6f gui: Show ID under each device section (local / remote), clickable for QR code (#7728) 2021-06-01 18:04:11 +02:00
Ikko Ashimine
08f6a91441 contributing: Fix GitHub format (#7713) 2021-05-31 10:27:35 +02:00
greatroar
95c9561e97 lib/db: Clean up Timer and wait for logging before return in GC (#7720) 2021-05-31 09:50:21 +02:00
Simon Frei
fcb19518c7 build, lib/model: Add flag to run tests without -short and fix failure (#7716) 2021-05-28 22:20:18 +02:00
Jakob Borg
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 Frei
22e09334ec lib/model: Fix incoming request on receive-enc (fixes #7699) (#7702) 2021-05-22 21:38:49 +02:00
Simon Frei
58592e3ef1 lib/db: Add logging for GC (#7707) 2021-05-22 21:36:43 +02:00
Simon Frei
0126188ba7 lib/config: Set DisableTempIndexes to true on receive-encrypted (#7701) 2021-05-20 22:33:23 +02:00
Simon Frei
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 Butkevicius
58e81fdffb cmd/syncthing/cli: Update recli, fix stdin handling (fixes #7685, fixes #7673) (#7694) 2021-05-18 20:09:48 +01:00
tomasz1986
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
greatroar
0e52ce830a lib/fs: Fix UnicodeLowercaseNormalized on lowercase NFD (#7692)
Co-authored-by: greatroar <@>
2021-05-17 20:43:07 +02:00
Jakob Borg
97437cad64 lib/fs: Ignore normalization differences in case insensitive lookup (fixes #7677) (#7678) 2021-05-17 12:35:03 +02:00
Simon Frei
5b90a98650 lib/model: Fix addFakeConn and other test improvements (#7684) 2021-05-16 17:23:27 +02:00
Audrius Butkevicius
96dae7bfec cmd/uraggregate: Optimise queries (#7679)
* cmd/uraggregate: Optimise queries

* Update main.go
2021-05-16 12:34:46 +01:00
Simon Frei
93a02c677e lib/scanner: Do not drop all not-exist-errors and debug logging (#7675) 2021-05-15 11:51:35 +02:00
Simon Frei
0d054f9b64 lib/model: Don't use empty folder cfg for index sender (fixes #7649) (#7671) 2021-05-15 11:13:39 +02:00
Audrius Butkevicius
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
bt90
086508f51a docker: Remove sysctl from README (#7670) 2021-05-12 22:17:51 +02:00
Audrius Butkevicius
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 Frei
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 Frei
c494ced21f lib/connections: Actually remove listenerSupervisor (ref #7644) (#7663) 2021-05-11 14:35:13 +02:00
Audrius Butkevicius
a8e2fc6f61 cmd/uraggregate: Handle malformed data, dont abort on error (fixes #7639) (#7659) 2021-05-11 08:02:19 +02:00
Audrius Butkevicius
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 Frei
5cb2a10138 lib/model: Improve encryption cluster-config errors (#7658) 2021-05-11 07:55:44 +02:00
Audrius Butkevicius
411796606c lib/connections: Correct service termination order (#7657) 2021-05-10 22:29:27 +02:00
Simon Frei
1a9b54c9fa lib/connections: Separate listener supervisors and lower backoff time (#7644) 2021-05-10 22:26:51 +02:00
Simon Frei
c7f4f15272 lib/relay, lib/svcutil: Improve service logging (fixes #7580) (#7647) 2021-05-10 22:26:25 +02:00
Simon Frei
713527facf all: Refactor relay invitations (#7646) 2021-05-10 22:25:43 +02:00
Simon Frei
6e662dc9fc lib/suture: Use ServeBackground to start main supervisor (#7626) 2021-05-10 16:50:45 +02:00
Audrius Butkevicius
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 Butkevicius
adf3f641ce Ignore GoLand cruft 2021-05-09 23:56:18 +01:00
Simon Frei
6157c766de lib/connections: Correct comments on quic wrapper type (#7652) 2021-05-09 19:15:10 +01:00
Audrius Butkevicius
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 Frei
faf15b4567 lib/connections: Add more methods to the quic conn wrapper (#7643) 2021-05-09 12:45:08 +01:00
greatroar
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 Frei
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 Frei
f4e112f404 build: Ignore error from pkill on apt upgrade (fixes #7628) (#7629) 2021-05-04 18:33:25 +02:00
Audrius Butkevicius
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
overkill
f09dcb98eb gui: Semicolons (#7597) 2021-05-03 12:14:54 +02:00
dependabot[bot]
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 Frei
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 Borg
ed9cb923fb build: Update most dependencies (fixes: all the dependabot PRs) (#7622) 2021-04-30 09:11:11 +02:00
Simon Frei
dd39556759 lib: Revert needing invalid files (fixes #7608, ref #7476) (#7609) 2021-04-29 22:01:46 +02:00
dependabot[bot]
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]
5675644341 build: Upgrade to GitHub-native Dependabot (#7607) 2021-04-29 21:19:06 +02:00
Simon Frei
1f30383866 lib/model: Remove path from enc errors and report only once (#7610) 2021-04-29 19:21:07 +02:00
tomasz1986
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 Weich
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
Gahl Saraf
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 Frei
ec86db176e lib/model: Handle invalid needed items on send-only (ref #7476) (#7596) 2021-04-26 15:38:08 +02:00
Simon Frei
60e8630413 gui: Handle empty path in validation (ref #7379) (#7595) 2021-04-26 15:38:08 +02:00
Simon Frei
9d29dbbe5d 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-26 15:38:08 +02:00
Simon Frei
8734fa65fc lib/model: Handle invalid needed items on send-only (ref #7476) (#7596) 2021-04-26 15:36:51 +02:00
Simon Frei
c53e5c5f17 gui: Handle empty path in validation (ref #7379) (#7595) 2021-04-26 15:35:12 +02:00
Jakob Borg
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 Frei
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
Simon Frei
54e27f551d cmd/syncthing: Add debug commands to cli (#7503) 2021-04-22 11:14:25 +02:00
Jakob Borg
59bdcdabba gui, man, authors: Update docs, translations, and contributors 2021-04-21 07:45:43 +02:00
Simon Frei
f6375ecbfc gui: Unset current folder on modal close (fixes #7584) (#7586) 2021-04-20 17:29:38 +02:00
Simon Frei
031b91c0ed gui: Fix folder path validation (fixes #7379) (#7585) 2021-04-20 17:29:06 +02:00
Jakob Borg
e4c995a321 lib/model: Don't remove non-empty .stfolder (#7578) 2021-04-15 18:13:35 +02:00
André Colomb
130d14cec9 api: Log API authorization failures. (#7575) 2021-04-15 07:33:02 +02:00
Jakob Borg
e893ca1c9a gui, man, authors: Update docs, translations, and contributors 2021-04-14 07:45:37 +02:00
Simon Frei
156d96e582 gui: Add missing file (fixes #7571, ref #7567) (#7573) 2021-04-13 20:22:55 +02:00
Simon Frei
9ba7611537 build: Bump go-stun to v0.1.3 (fixes #7568) (#7572) 2021-04-13 17:10:52 +01:00
Simon Frei
15d2dc3a4f lib/connections: Add SyscallConn() to quic conn (fixes #7551) (#7570) 2021-04-13 12:59:58 +01:00
André Colomb
f6df1a760d lib/api: Log the remote address on login attempts (#7560)
This enables usage of the audit log to e.g. automatically block remote
addresses from connecting after repeated login failures.
2021-04-13 10:14:44 +02:00
Simon Frei
f71fcd440a all: Remove untrusted feature flag (fixes #109) (#7567)
No longer hide the web UI controls for the new untrusted/encrypted
device feature. Testing hasn't been very widespread, but there has been
some and quite a few bugs have been caught and fixed. I believe its time
to not hide it anymore, and cautiously recommend usage. E.g. mention
that the feature hasn't been widely used yet and anyone using it is an
early adopter, but drop the bit about not using it with production data.
We can maybe stress the need for backups in general and especially
using this.
2021-04-13 10:12:56 +02:00
Simon Frei
c2bb11a794 build: Do not use --deb-systemd with fpm (fixes #7548) (#7564) 2021-04-11 20:04:15 +02:00
Simon Frei
1a00ea7c6e lib: Prevent using protocol method with native path (fixes #7557) (#7563) 2021-04-11 15:29:43 +02:00
Simon Frei
ec0a66c75b lib/db, lib/model: Refactor removing expired pending folders (#7537) 2021-04-11 15:24:08 +02:00
Jakob Borg
1658afc883 gui, man, authors: Update docs, translations, and contributors 2021-04-07 07:45:38 +02:00
Jakob Borg
67aaeef537 Merge branch 'release'
* release:
  cmd/syncthing: Rename --conf back to --config
  lib/db: Fix comparison of pending folder timestamps (fixes #7532) (#7535)
2021-04-06 10:47:00 +02:00
Jakob Borg
13679284ac cmd/syncthing: Rename --conf back to --config
This was inadvertently changed in the flag migration.
2021-04-06 10:42:29 +02:00
Jakob Borg
a514b65d81 cmd/syncthing: Rename --conf back to --config (fixes #7549) (#7550) 2021-04-06 10:40:52 +02:00
André Colomb
7931af1078 lib/db: Fix comparison of pending folder timestamps (fixes #7532) (#7535) 2021-04-06 10:37:11 +02:00
Jakob Borg
4fc3446f24 Merge branch 'release'
* release:
  Merge pull request from GHSA-x462-89pf-6r5h
2021-04-06 08:05:57 +02:00
Jakob Borg
fb4fdaf4c0 Merge pull request from GHSA-x462-89pf-6r5h 2021-04-06 08:03:22 +02:00
Jakob Borg
8e38ecdeb2 Merge pull request from GHSA-x462-89pf-6r5h 2021-04-06 08:00:00 +02:00
tomasz1986
04623718ce gui: Remove download animation from Out of Sync Items modal (fixes #3322) (#7388)
Remove the animation due to its excessive CPU usage, especially when a
large number of files is being downloaded and listed at the same time.
Also, remove the stripes, as they serve no purpose in the now-static
progress bar.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-04-05 10:28:06 +02:00
Simon Frei
9e857ed2d4 build: Add test coverage info (#7502) 2021-04-05 10:25:39 +02:00
Simon Frei
f30f9c50f8 lib/db: Handle indirection error repairing sequences (fixes #7026) (#7525) 2021-04-05 10:24:16 +02:00
mclang
96ba5c2b23 docker: Add docker-compose example (#7355)
Co-authored-by: bt90 <btom1990@googlemail.com>
2021-04-01 13:04:15 +02:00
Simon Frei
0dcd9794d4 lib/protocol: Deterministic encrypted version (fixes #7533) (#7538) 2021-03-31 08:59:15 +02:00
bt90
34f0feb13a docker: Raise UDP buffer size in example (#7536) 2021-03-31 08:57:46 +02:00
Jakob Borg
7778f50b50 gui, man, authors: Update docs, translations, and contributors 2021-03-31 07:45:27 +02:00
André Colomb
fb2d85b9d5 lib/db: Fix comparison of pending folder timestamps (fixes #7532) (#7535) 2021-03-30 21:24:53 +02:00
Simon Frei
7f0d4f6ba8 lib/db: Don't panic debugging an inexistent file (#7534) 2021-03-30 20:06:01 +02:00
MichaIng
33212716cf etc: Fix start-limit parameters location in systemd units (ref #7439) (#7529) 2021-03-28 14:14:10 +02:00
Simon Frei
707001c403 gui: Add confirmation dialog for revert/override (fixes #7520) (#7522) 2021-03-26 16:56:15 +01:00
Jonta
f93c6fbe4a readme: Larger link for Fitt's law, still semantic (#7523) 2021-03-26 07:24:40 +01:00
Jakob Borg
70b9654671 gui, man, authors: Update docs, translations, and contributors 2021-03-24 07:45:32 +01:00
Simon Frei
0d7a77ba85 lib/model: Reset conn when enc token is missing (fixes #7198) (#7518) 2021-03-23 10:38:40 +01:00
Simon Frei
924b96856f lib: Handle adding enc folders on an existing conn (fixes #7509) (#7510) 2021-03-22 21:50:19 +01:00
Audrius Butkevicius
f7929229c8 cmd/strelaysrv: Increase default strelaysrv network buffer size (fixes #7514) (#7517)
Increases throughput at the cost of more memory per connection
2021-03-22 21:47:51 +01:00
Simon Frei
6b25eb2e79 lib/ur: Prevent panic when blocksResult is nil (ref #7495) (#7515) 2021-03-22 15:07:41 +01:00
Simon Frei
bc08a951f1 lib/model: Encrypted fileinfo trailer needs to be in wire format (#7505) 2021-03-21 10:34:08 +01:00
Lars Lehtonen
a87c5515bd lib/model: Error check in test (#7508) 2021-03-21 10:32:17 +01:00
Jakob Borg
ebcd22b02b lib/osutil: Fix raising max FDs on macOS (#7507)
There was a logic mistake, so the limit in question wasn't used. On my
macOS this doesn't seem to matter, the hard limit returned is 2^63-1 and
setting the soft limit to that works. However I'm assuming that's not
the case for older macOSes since it was so nicely documented, so we
should still have this working. (10240 FDs should be enough for
anybody.)
2021-03-20 16:32:36 +01:00
Audrius Butkevicius
4b02b7e6f1 lib/connections: Silence "connected to myself" messages. (#7500) 2021-03-17 23:53:20 +01:00
Jakob Borg
fdd823d2cb lib/osutil: Remove unused code 2021-03-17 23:18:07 +01:00
Jakob Borg
8ef504f745 all: Simplify some method calls (#7499)
strings.Replace(a, b, c, -1) -> strings.ReplaceAll(a, b, c)

(Go 1.12) and who knows what was up with that dialQueue.Sort() thing.
2021-03-17 23:12:26 +01:00
Jakob Borg
960e850a78 cmd/uraggregate: Ignore errors harder (#7498)
We were already ignoring them, it just didn't look like it.
2021-03-17 22:55:43 +01:00
Jakob Borg
ea701a4e9e cmd/syncthing: Error handling on upgrade (#7497)
dat innocuous little colon
2021-03-17 22:52:43 +01:00
deepsource-autofix[bot]
6c573a5762 Remove unnecessary guard around delete (#7496)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2021-03-17 22:23:36 +01:00
Jakob Borg
3ac858b150 all: Remove miscellaneous vestigial code (#7495) 2021-03-17 22:23:12 +01:00
Jakob Borg
f4372710bf all: Remove crypto/md5 (#7493)
This is a mostly pointless change to make security scanners and static
analysis tools happy, as they all hate seeing md5. None of our md5 uses
were security relevant, but still. Only visible effect of this change is
that our temp file names for very long file names become slightly longer
than they were previously...
2021-03-17 22:22:49 +01:00
Jakob Borg
f39477bbd5 lib/api: Missing error handling in API delete-device (#7494) 2021-03-17 22:08:44 +01:00
Jakob Borg
6e5514419d lib/db: Fix some omitted error checks, unused variable (#7489) 2021-03-17 21:41:07 +01:00
tomasz1986
f014b7b919 gui: Improve Receive Encrypted folder type requirements text (#7473)
The current text gives an impression that we are currently using a
Receive Encrypted folder, even if we are not. Thus, make the current
text displayed only when the folder is in fact Receive Encrypted, and
add a new string to be displayed when using different folder types.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-03-17 21:36:11 +01:00
Jakob Borg
81484699db lib/model: Actually break puller loop on context cancel (#7492)
Current break does nothing (breaks the select).
2021-03-17 21:34:52 +01:00
Jakob Borg
6d93d9c488 deepsource: Test patterns 2021-03-17 21:12:51 +01:00
deepsource-autofix[bot]
0930bccf88 cmd/ursrv, lib/scanner: Remove unnecessary slicing of slices (#7491)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2021-03-17 21:04:36 +01:00
Jakob Borg
e321bd3941 lib/*/auto: Add noassets files (#7490)
This adds a couple of dummy asset files protected by the "noassets"
build tag. The purpose is that it should be possible for, for example,
CI tools and static analysis things to compile and analyze the source
tree without our custom asset generation step. Also makes `go test -tags
noassets ./...` work without building assets first.
2021-03-17 21:03:35 +01:00
Simon Frei
4b02937862 lib/model: Add missing lock on availability func (#7487) 2021-03-17 20:46:13 +01:00
Jakob Borg
21e6849f2d Add DeepSource for static analysis 2021-03-17 20:05:20 +01:00
Simon Frei
39c2d1bc1a cmd/syncthing: Check os.Args length (fixes #7486) 2021-03-17 15:51:14 +01:00
Simon Frei
cd21b8dfa5 cmd/syncthing/cli: Remove db reset and adjust others (#7484) 2021-03-17 09:06:37 +01:00
Simon Frei
40fbdc87ce cmd/syncthing: Refactor cli subcommand to allow flags (#7454) 2021-03-17 09:04:50 +01:00
Jakob Borg
1814f4693d gui, man, authors: Update docs, translations, and contributors 2021-03-17 07:45:40 +01:00
Simon Frei
3f2b584c4e lib/model: Don't use ignore patterns for recv-enc folders (fixes #7469) (#7472) 2021-03-16 15:04:11 +01:00
Jakob Borg
e0dd737822 gui: Fix validation and help texts in versioning editor (fixes #7481) (#7482) 2021-03-16 09:30:07 +01:00
Simon Frei
d2d4fcc1df lib/protocol: Improve messages when an error occurs receiving (ref #7466) (#7470) 2021-03-15 19:14:09 +01:00
Simon Frei
273ee09925 lib/db, lib/model: Allow needing invalid files (fixes #7474) (#7476) 2021-03-15 07:58:01 +01:00
tomasz1986
bb886868d2 gui: Use grey background for disabled options in form-control (#7468)
Disabled options are currently barely distinguishable from enabled
ones. This changes their background to grey, following the Bootstrap
defaults already used for disabled <select>.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-03-14 08:14:19 +01:00
Simon Frei
f80ee472c2 lib/protocol: Set invalid flag on encrypted file infos (fixes #7466) (#7467) 2021-03-13 16:57:36 +01:00
tomasz1986
a12ede3bbe gui: Fix missing trashcanClean in simple versioning (#7465) 2021-03-13 10:14:26 +01:00
Simon Frei
97a8777d03 lib/fs: Check both old and new path when renaming (fixes #7426) (#7463) 2021-03-12 21:15:50 +01:00
Simon Frei
8a4c00d82e lib/model: Send failure report on CC encryption check error (#7460) 2021-03-12 12:21:54 +01:00
Simon Frei
31f859e909 lib/model: Return correct error in puller-iteration (ref #7424) (#7461) 2021-03-12 12:21:28 +01:00
Jakob Borg
4d979a1ce9 all: Truncate some timestamps (fixes #7457) (#7459)
This truncates times meant for API consumption to second precision,
where fractions won't typically matter or add any value. Exception to
this is timestamps on logs and events, and of course I'm not touching
things like file metadata.

I'm not 100% certain this is an exhaustive change, but it's the things I
found by grepping and following the breadcrumbs from lib/api...

I also considered general-but-ugly solutions, like having the API
serializer itself do reflection magic or even regexps on returned
objects, but decided against it because aurgh...
2021-03-12 10:35:10 +01:00
Simon Frei
4465cdf8bc lib/api: Fix body of renamed config/restart-required endpoint (ref #7402) (#7453) 2021-03-11 15:54:05 +01:00
Simon Frei
3938b61c3f lib/fs: Expose fs option on interface (fixes #7385, ref #7381) (#7389) 2021-03-11 15:23:56 +01:00
Jakob Borg
cdef503db6 all: Make config.Wrapper an actual suture.Service (fixes #7451) (#7452) 2021-03-11 14:51:00 +01:00
Jakob Borg
df08984a58 lib/api: Sanitize names used in certificates (fixes #7434) (#7435) 2021-03-11 13:15:03 +01:00
Simon Frei
cf838c71f7 gui: Check if versioning object exists (fixes #7449) (#7450) 2021-03-11 11:21:35 +01:00
Simon Frei
9a001051d6 cmd/ursrv, lib/ur: Collect and present encryption usage (#7448) 2021-03-10 22:26:56 +00:00
Jakob Borg
5548a8eb7a gui, man, authors: Update docs, translations, and contributors 2021-03-10 07:45:45 +01:00
Simon Frei
727df34aa1 cmd/syncthing: Correct name of HiddenConsole flag (fixes #7446) (#7447) 2021-03-10 07:31:31 +01:00
Simon Frei
9587a523b3 build: Update notify (#7444) 2021-03-08 13:36:03 +01:00
Jakob Borg
22e44642a0 next-gen-gui: Add button to restore default theme (#7433)
This adds a button in the top right that changes the config back to the
default theme.

Code wise, it takes the header that was previously a part of the
dashboard component and moves it to the app component, and then adds the
button there. Possibly the header should be a component of it's own, but
that's more of refactor that can happen separately I think.

The config change uses the new config API to just patch the relevant
setting.

I'm not doing an automatic reload because 1) I don't want to figure out
how to do it correctly and 2) this doesn't work reliably anyway, as
for example the current gen GUI does a reload and ends up with
connection refused as the API service is still reloading...
2021-03-08 12:54:08 +01:00
greatroar
c00520281b lib/protocol: Optimize FileKey (#7440) 2021-03-07 18:44:21 +01:00
Simon Frei
587c89d979 cmd/syncthing, etc: Consistent failure restart backoff (#7439) 2021-03-07 15:25:55 +01:00
Simon Frei
310fba4c12 lib: Return error from db.FileSet.Snapshot (fixes #7419, ref #5907) (#7424) 2021-03-07 13:43:22 +01:00
bt90
c1d06d9501 build: Package sysctl configuration to raise UDP buffer size on Linux (#7417)
* Provide a sysctl config to raise max UDP buffer size

* Add sysctl config to deb

* Check if `deb-systemd-invoke` is available

Co-authored-by: otbutz <tbutz@optitool.de>
2021-03-05 08:08:29 +01:00
Simon Frei
4735575e8d cmd/syncthing: Set flag defaults through kong vars (#7431) 2021-03-05 08:06:54 +01:00
Simon Frei
767e1c6f58 lib/connections: Expose SetReadBuffer on conn passed to quic (ref #7417) (#7432) 2021-03-05 08:06:37 +01:00
Simon Frei
83fcb49894 gui: Apply #7430 to untrusted 2021-03-04 21:09:18 +01:00
André Colomb
5fd88481b6 gui: Fix hidden Ignore Patterns tab for folder editing (fixes #7429) (#7430) 2021-03-04 21:08:15 +01:00
Simon Frei
69c63e94bf scripts: Remove unused import (ref #7375) 2021-03-03 09:00:43 +01:00
Simon Frei
3d91f7c975 lib: Use counterfeiter to mock interfaces in tests (#7375) 2021-03-03 08:53:50 +01:00
Jakob Borg
7945430e64 gui, man, authors: Update docs, translations, and contributors 2021-03-03 07:45:37 +01:00
bt90
e2120c4728 docker: Expose 22000/udp (#7421)
Co-authored-by: otbutz <tbutz@optitool.de>
2021-03-02 20:42:25 +01:00
greatroar
56b5352f64 all: Use crypt/rand through its buffered version, but not in benchmarks (#7420) 2021-03-02 19:17:20 +01:00
Jakob Borg
55d5e03639 lib/db: Remove Badger experiment (#7413) 2021-03-01 09:16:08 +01:00
tomasz1986
cca17f5306 gui: Allow to resize command in External Versioning (#7410) 2021-02-27 09:41:16 +01:00
greatroar
ffcaffa32f lib/protocol: Optimize encrypted filename handling + make it more strict (#7408) 2021-02-27 08:57:12 +01:00
Simon Frei
0ffd80f380 lib/protocol: Alwasy return buffers to the pool (#7409) 2021-02-27 08:55:51 +01:00
wouter bolsterlee
25151b14e7 lib/api: Treat *.localhost as valid localhost addresses (#7412) (ref #4815)
This loosens the ‘is this localhost?’ check to include *.localhost host
names.

This allows for clearer (hence better) names to be used in browsers,
e.g. when accessing a remote syncthing instance ‘foo’ using a ssh port
forward, one can use foo.localhost to remind oneself which one is which.
💡 Without these changes, Syncthing shows a ‘Host check error’ when
pointing a browser at http://foo.localhost/, and with these changes, the
interface loads as usual.

The .localhost top level domain is a reserved top-level domain (RFC 2606):

> The ".localhost" TLD has traditionally been statically defined in
> host DNS implementations as having an A record pointing to the
> loop back IP address and is reserved for such use.  Any other use
> would conflict with widely deployed code which assumes this use.
> – https://tools.ietf.org/html/rfc2606

As Wikipedia puts it:

> This allows the use of these names for either documentation purposes
or in local testing scenarios. – https://en.wikipedia.org/wiki/.localhost

On Linux systems, systemd-resolved resolves *.localhost, on purpose:
https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html

See also #4815, #4816.
2021-02-27 08:52:49 +01:00
Simon Frei
428c5c02ce Merge branch 'release' 2021-02-26 13:47:03 +01:00
Simon Frei
e2e5643c3c all: Fix versioning path handling (#7407) 2021-02-26 13:21:13 +01:00
Simon Frei
956d212e99 gui: Folder versioning editing cleanup (#7384) 2021-02-26 13:20:53 +01:00
Simon Frei
fff8805ff6 all: Fix versioning path handling (#7407) 2021-02-26 12:04:05 +01:00
Simon Frei
a69afc9eeb gui: Folder versioning editing cleanup (#7384) 2021-02-25 18:24:18 +01:00
Simon Frei
0bf9645f2f lib/api: Rename config insync endpoint to restart-required (#7402) 2021-02-25 09:29:44 +01:00
Steven Eckhoff
6bfad8fce8 build: Make stupgrades build target conditional (fixes #7199) (#7404) 2021-02-25 09:29:14 +01:00
Jakob Borg
6ebab5db07 gui, man, authors: Update docs, translations, and contributors 2021-02-24 07:45:23 +01:00
bt90
34aa89a7d6 Allow QUIC traffic (#7400) 2021-02-23 20:39:03 +00:00
Jakob Borg
44e4f754dd Merge branch 'release'
* release:
  all: Fix Microsoft documentation links in code comments (#7387)
  gui: Handle info labels that are longer than available space (fixes #944) (#7386)
  gui: Show "Last seen" at the top when device is disconnected (ref #7166) (#7373)
  gui: Remove cleanupIntervalS leftovers from External Versioning (ref #7360) (#7378)
  gui: Allow setting custom path for all versioning except external (#7377)
  lib/fs: Consider options in case-fs caching (fixes #7371) (#7381)
  lib/scanner: Pass on errors while hashing (#7380)
  build: Update pfilter (#7376)
  gui: Hide the Rescan All button when no folders exist (#7367)
  lib/connections: Allow QUIC with Go 1.16 (#7372)
  gui: Hide non-functional Versions button when using External Versioning (#7365)
  gui, man, authors: Update docs, translations, and contributors
  gui: Fix setting external versioning command (fixes #7361) (#7362)
  lib/versioner: Improve error messages (fixes #7354) (#7357)
  gui: Disable Cleanup Interval with External File Versioning as unsupported (#7360)
2021-02-23 07:37:07 +01:00
tomasz1986
60c218efdb all: Fix Microsoft documentation links in code comments (#7387) 2021-02-22 18:27:41 +01:00
tomasz1986
8d290eb055 gui: Handle info labels that are longer than available space (fixes #944) (#7386)
Apply to table headers the same code as already used for table data.
This way, the headers will be either pushed to the next line, or cut
with an ellipsis if the single word is too long.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-22 18:27:41 +01:00
tomasz1986
cd17aa2cab gui: Show "Last seen" at the top when device is disconnected (ref #7166) (#7373)
Move the "Last seen" field to the very top in the device information.
This way, if a device has disconnected unexpectly, we can quickly check
the time when it was last available. Right now, due to the very long
address field, it is usually necessary to scroll down in order to view
the "Last seen" field.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-22 18:27:41 +01:00
tomasz1986
edaff81c0a gui: Remove cleanupIntervalS leftovers from External Versioning (ref #7360) (#7378) 2021-02-22 18:27:41 +01:00
tomasz1986
dd7d6188f2 gui: Allow setting custom path for all versioning except external (#7377) 2021-02-22 18:27:41 +01:00
Simon Frei
9be6f1a70e lib/fs: Consider options in case-fs caching (fixes #7371) (#7381) 2021-02-22 18:27:40 +01:00
Simon Frei
b0cce98648 lib/scanner: Pass on errors while hashing (#7380) 2021-02-22 18:27:40 +01:00
Simon Frei
e159f76ced build: Update pfilter (#7376) 2021-02-22 18:27:40 +01:00
tomasz1986
07d3af21c2 gui: Hide the Rescan All button when no folders exist (#7367)
If there are no folders present, show only the "Add Folder" button, and
hide the "Rescan All" button. Only show the latter when at least one
folder exists.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-22 18:27:40 +01:00
tomasz1986
1ed0116147 all: Fix Microsoft documentation links in code comments (#7387) 2021-02-20 14:56:45 +01:00
tomasz1986
c5663689a3 gui: Handle info labels that are longer than available space (fixes #944) (#7386)
Apply to table headers the same code as already used for table data.
This way, the headers will be either pushed to the next line, or cut
with an ellipsis if the single word is too long.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-20 10:28:08 +00:00
tomasz1986
9caaaa49b6 gui: Show "Last seen" at the top when device is disconnected (ref #7166) (#7373)
Move the "Last seen" field to the very top in the device information.
This way, if a device has disconnected unexpectly, we can quickly check
the time when it was last available. Right now, due to the very long
address field, it is usually necessary to scroll down in order to view
the "Last seen" field.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-20 10:26:34 +00:00
otbutz
c18dc6a629 cmd/strelaysrv: Load map tiles over HTTPS (#7382) 2021-02-19 22:07:05 +01:00
tomasz1986
b1fbd87680 gui: Remove cleanupIntervalS leftovers from External Versioning (ref #7360) (#7378) 2021-02-19 17:49:56 +01:00
tomasz1986
be630691b1 gui: Allow setting custom path for all versioning except external (#7377) 2021-02-19 17:48:46 +01:00
Simon Frei
aa1c274231 lib/fs: Consider options in case-fs caching (fixes #7371) (#7381) 2021-02-19 11:06:25 +01:00
Simon Frei
78c2844e3f lib/scanner: Pass on errors while hashing (#7380) 2021-02-19 08:51:39 +01:00
Simon Frei
57a7f4391f build: Update pfilter (#7376) 2021-02-18 15:09:46 +00:00
Simon Frei
0970aed596 cmd/stcrashreceiver: Add tag for report type (crash/failure) (#7374) 2021-02-18 13:16:32 +00:00
tomasz1986
342ade501a gui: Hide the Rescan All button when no folders exist (#7367)
If there are no folders present, show only the "Add Folder" button, and
hide the "Rescan All" button. Only show the latter when at least one
folder exists.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 18:02:55 +01:00
Jakob Borg
35316e9142 lib/connections: Allow QUIC with Go 1.16 (#7372) 2021-02-17 11:17:45 +01:00
tomasz1986
2a0775da03 gui: Hide non-functional Versions button when using External Versioning (#7365)
The button does nothing when the External Versioning is being used, so
it should not be displayed at all to avoid confusing the users.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 11:17:45 +01:00
Jakob Borg
8bd67f72dd gui, man, authors: Update docs, translations, and contributors 2021-02-17 11:17:45 +01:00
Simon Frei
82f190285a gui: Fix setting external versioning command (fixes #7361) (#7362) 2021-02-17 11:17:44 +01:00
Simon Frei
f5590c3345 lib/versioner: Improve error messages (fixes #7354) (#7357) 2021-02-17 11:17:44 +01:00
tomasz1986
9be07de7c6 gui: Disable Cleanup Interval with External File Versioning as unsupported (#7360)
As for right now, the External File Versioning does not support Cleanup
Interval. Therefore, the option should no be available at all when using
it.

Ref: https://forum.syncthing.net/t/16346

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 11:17:44 +01:00
Jakob Borg
327604719a lib/connections: Allow QUIC with Go 1.16 (#7372) 2021-02-17 11:09:16 +01:00
tomasz1986
e8ef586cef gui: Hide non-functional Versions button when using External Versioning (#7365)
The button does nothing when the External Versioning is being used, so
it should not be displayed at all to avoid confusing the users.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 08:29:25 +01:00
Jakob Borg
c014fc5ec5 gui, man, authors: Update docs, translations, and contributors 2021-02-17 07:45:43 +01:00
Audrius Butkevicius
fb078068b4 cmd/syncthing: Add cli as a subcommand (fixes #6566, fixes #4719) (#7364)
* cmd/syncthing: Add cli as a subcommand (fixes #6566, fixes #4719)

* Hijack help

* Add comment

* Revert go.mod/go.sum
2021-02-15 18:50:53 +01:00
Jakob Borg
b2c9e7b07b build: Add build process for newgui (#7351) 2021-02-15 14:52:28 +01:00
Simon Frei
d117b4b570 gui: Fix setting external versioning command (fixes #7361) (#7362) 2021-02-14 09:54:49 +01:00
Simon Frei
80fc238bec all: Automatic/disabled folder-config when receive-encrypted (#7327) 2021-02-12 22:51:29 +01:00
Simon Frei
7e4e2f3720 lib/versioner: Improve error messages (fixes #7354) (#7357) 2021-02-12 20:30:51 +01:00
tomasz1986
5e9c7bc022 gui: Disable Cleanup Interval with External File Versioning as unsupported (#7360)
As for right now, the External File Versioning does not support Cleanup
Interval. Therefore, the option should no be available at all when using
it.

Ref: https://forum.syncthing.net/t/16346

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-12 17:32:25 +00:00
Jakob Borg
55afa625fc cmd/syncthing: Add decrypt subcommand (#7332)
This adds the `syncthing decrypt` subcommand that is used to
(offline-)decrypt or just verify the contents of an encrypted folder.
2021-02-12 08:38:43 +01:00
Simon Frei
f2e9b40ad1 etc: Adjust all the startup scripts to new cmd (ref #7330) (#7353) 2021-02-11 12:18:47 +01:00
Simon Frei
6697b8fde3 cmd/syncthing: Fix hyphenated flag names (ref #7330) (#7352) 2021-02-11 11:37:48 +01:00
Jakob Borg
4f20c900d0 cmd/syncthing: Refactor command line parsing (#7330) 2021-02-10 20:35:37 +01:00
Jakob Borg
0471daf771 newgui: Merge separate repo into syncthing/syncthing
Co-authored-by: Audrius Butkevicius <audrius.butkevicius@gmail.com>
Co-authored-by: Simon Frei <freisim93@gmail.com>
2021-02-10 14:04:28 +01:00
Jakob Borg
5788ad2529 Reassign copyright to the Syncthing Authors 2021-02-10 13:58:51 +01:00
Jakob Borg
472affb6a3 Move all into newgui/ 2021-02-10 13:58:08 +01:00
Jakob Borg
802b933778 gui, man, authors: Update docs, translations, and contributors 2021-02-10 07:45:27 +01:00
Simon Frei
f1ec7fe55b gui: Check that connection exists on event (fixes #7347) (#7348) 2021-02-09 12:37:35 +01:00
Simon Frei
d842197931 lib/model: Disable tests involving scrypt with -short (fixes #7344) (#7346) 2021-02-08 17:13:28 +01:00
tomasz1986
4e7510dea9 build: Fix strings in versioninfo for Windows (fixes #7340) (#7342) 2021-02-08 15:48:05 +01:00
Simon Frei
c0f353c0e8 lib: Do not set ModifiedBy on meta only changes (#7345) 2021-02-08 15:30:39 +01:00
Simon Frei
e95d005c21 gui: Add defaults config to advanced menu (ref #7131) (#7343) 2021-02-08 12:59:02 +01:00
Simon Frei
11e9d575c8 lib/model: Refactor folder.scanSubdirs into smaller parts (#7321) 2021-02-08 08:40:57 +01:00
Simon Frei
46bbc78e82 lib/db: Fix and improve removing entries from global (ref #6501) (#7336) 2021-02-08 08:38:41 +01:00
Simon Frei
50a621bc7b gui: Apply #7339 to untrusted 2021-02-07 10:53:55 +01:00
Christian Prescott
d0c84916c7 gui: fix setDeviceConfig updating devices with undefined key (#7339) 2021-02-07 10:52:36 +01:00
Jakob Borg
6db8dc33f2 lib/model: Correctly verify short read blocks (fixes #7333) (#7334)
An untrusted device will receive padded info for small blocks, and hence
sometimes request a larger block than actually exists on disk.
Previously we let this pass because we didn't have a hash to compare to
in that case and we ignored the EOF error based on that.

Now the untrusted device does pass an encrypted hash that we decrypt and
verify. This means we can't check for len(hash)==0 any more, but on the
other hand we do have a valid hash we can apply to the data we actually
read. If it matches then we don't need to worry about the read
supposedly being a bit short.
2021-02-05 16:07:21 +01:00
Jakob Borg
194501c958 lib/api: Give the config changes some more time? (#7335) 2021-02-05 15:33:37 +01:00
Simon Frei
27a34609a1 all: Failure reporting fixes (#7331) 2021-02-05 11:21:14 +01:00
Simon Frei
ffc14a77c6 all: Add configurable defaults (fixes #4224, fixes #6086) (#7131) 2021-02-04 21:10:41 +01:00
greatroar
31119ed61a lib/ignore: Store cache timestamps as Unix ns counts (#7326) 2021-02-04 18:39:06 +01:00
Simon Frei
070bf3b776 lib/db: Report number of repaired items from checkGlobal (#7329) 2021-02-04 14:42:46 +01:00
Quentin Hibon
ade8d79d42 gui: Do not touch .stignore when not needed (fixes #7284) (#7325) 2021-02-03 20:58:24 +01:00
greatroar
42917d707d lib/scanner: Remove unused field, move WaitGroup.Add out of loop (#7323) 2021-02-03 14:25:24 +01:00
Jakob Borg
1522cf74bc gui, man, authors: Update docs, translations, and contributors 2021-02-03 07:45:28 +01:00
Jakob Borg
3b7a57d108 lib/protocol: Hide repeated data blocks in a given file (#7319) 2021-02-02 20:15:14 +01:00
Audrius Butkevicius
a7d9268e4d lib/model: Make /browse endpoint return sane objects (#7306) 2021-02-01 09:27:34 +01:00
Simon Frei
052dc13487 lib/model: Correct pull progress for small files (fixes #7263) (#7316) 2021-01-31 23:40:15 +01:00
Simon Frei
249bcb3a01 lib/model: Optimize rename detection in scanner (#7315) 2021-01-31 21:02:42 +01:00
greatroar
fbe52faf49 lib/scanner: Allocate structure for final partial block (#7310)
Benchmark results on Linux/amd64, using updated benchmark for old and
new:

name        old time/op    new time/op    delta
HashFile-8    88.6ms ± 1%    88.3ms ± 1%   -0.33%  (p=0.046 n=19+19)

name        old speed      new speed      delta
HashFile-8   201MB/s ± 1%   202MB/s ± 1%   +0.33%  (p=0.044 n=19+19)

name        old alloc/op   new alloc/op   delta
HashFile-8    59.4kB ± 0%    46.1kB ± 0%  -22.47%  (p=0.000 n=14+20)

name        old allocs/op  new allocs/op  delta
HashFile-8      29.0 ± 0%      27.0 ± 0%   -6.90%  (p=0.000 n=20+20)

Co-authored-by: greatroar <@>
2021-01-28 14:23:24 +01:00
greatroar
8b86171642 lib/stun: Inline util.OnDone, comment on its purpose (#7308)
Co-authored-by: greatroar <@>
2021-01-27 19:27:00 +01:00
Simon Frei
e19d6e993d lib/fs: Cache all real-case results (fixes #7270) (#7286) 2021-01-27 19:25:34 +01:00
greatroar
ef0473c091 lib/util, lib/svcutil: Remove unused code (#7309)
Duplicates the definition in lib/svcutil.

Co-authored-by: greatroar <@>
2021-01-27 16:33:01 +01:00
Tomasz Wilczyński
3406a3ba95 gui: Reduce checkboxes size in Advanced Configuration (fixes #6949) (#7296) 2021-01-27 12:23:58 +01:00
Jakob Borg
7c1ed420a9 gui, man, authors: Update docs, translations, and contributors 2021-01-27 07:45:21 +01:00
André Colomb
d7e86af6c6 gui/untrusted: Mirror changes from #7205 and #7192 (#7302) 2021-01-25 20:19:55 +01:00
Tomasz Wilczyński
76cf326290 gui: Make label and input IDs in Advanced Configuration unique (fixes #7287) (#7290) 2021-01-25 19:54:42 +01:00
greatroar
6c3e187d1d lib/svcutil: Simplify doneService (#7303)
OnSupervisorDone no longer allocates.

Co-authored-by: greatroar <@>
2021-01-25 16:27:17 +01:00
André Colomb
e32a516b5f lib/model: Forget pending folders no longer announced in ClusterConfig (fixes #5187) (#7205)
* lib/db: Add ExpirePendingFolders().

Use-case is to drop any no-longer-pending folders for a specific
device when parsing its ClusterConfig message where previously offered
folders are not mentioned any more.

The timestamp in ObservedFolder is stored with only second precision,
so round to seconds here as well.  This allows calling the function
within the same second of adding or updating entries.

* lib/model: Weed out pending folders when receiving ClusterConfig.

Filter the entries by timestamp, which must be newer than or equal to
the reception time of the ClusterConfig.  For just mentioned ones,
this assumption will hold as AddOrUpdatePendingFolder() updates the
timestamp.

* lib/model, gui: Notify when one or more pending folders expired.

Introduce new event type FolderOfferCancelled and use it to trigger a
complete refreshCluster() cycle.  Listing individual entries would be
much more code and probably just as much work to answer the API
request.

* lib/model: Add comment and rename ExpirePendingFolders().

* lib/events: Rename FolderOfferCancelled to ClusterPendingChanged.

* lib/model: Reuse ClusterPendingChanged event for cleanPending()

Changing the config does not necessarily mean that the
/resut/cluster/pending endpoints need to be refreshed, but only if
something was actually removed.  Detect this and indicate it through
the ClusterPendingChanged event, which is already hooked up to requery
respective endpoints within the GUI.

No more need for a separate refreshCluster() in reaction to
ConfigSaved event or calling refreshConfig().

* lib/model: Gofmt.

* lib/db: Warn instead of info log for failed removal.

* gui: Fix pending notifications not loading on GUI start.

* lib/db: Use short device ID in log message.

* lib/db: Return list of expired folder IDs after deleting them.

* lib/model: Refactor Pending...Changed events.

* lib/model: Adjust format of removed pending folders enumeration.

Use an array of objects with device / folder ID properties, matching
the other places where it's used.

* lib/db: Drop invalid entries in RemovePendingFoldersBeforeTime().

* lib/model: Gofmt.

My local gofmt did not complain here, strangely...

* gui: Handle PendingDevicesChanged event.

Even though it currently only holds one device at a time, wrap the
contents in an array under the "added" property name.

* lib/model: Fix null values in PendingFoldersChanged removed member.

* gui: Handle PendingFoldersChanged event.

* lib/model: Simplify construction of expiredPendingList.

* lib/model: Reduce code duplication in cleanPending().

Use goto and a label for the common parts of calling the DB removal
function and building the event data part.

* lib/events, gui: Mark ...Rejected events deprecated.

Extend comments explaining the conditions when the replacement event
types are emitted.

* lib/model: Wrap removed devices in array of objects as well.

* lib/db: Use iter.Value() instead of needless db.Get(iter.Key())

* lib/db: Add comment explaining RemovePendingFoldersBeforeTime().

* lib/model: Rename fields folderID and deviceID in event data.

* lib/db: Only list actually expired IDs as removed.

Skip entries where Delete() failed as well as invalid entries that got
removed automatically.

* lib/model: Gofmt
2021-01-25 10:58:10 +00:00
greatroar
6da83ac9f5 lib/util: Remove duplicate error handling code (#7299)
This is also in lib/svcutil, and never used by clients.

Co-authored-by: greatroar <@>
2021-01-24 20:19:10 +01:00
Jakob Borg
adc07eddf6 gui, man, authors: Update docs, translations, and contributors 2021-01-20 07:45:29 +01:00
greatroar
9c88efd55f lib/util: Don't modify input in UniqueTrimmedStrings (#7288)
Also clarified the comment.
2021-01-16 17:39:15 +01:00
Jakob Borg
ffcb57580f cmd/syncthing: Provide early startup for config service (ref #7188) (#7285) 2021-01-16 12:58:02 +01:00
Quentin Hibon
abfbd13f17 gui: Allow device removal even if possibly reintroduced (fixes #5426) (#7216) 2021-01-15 20:46:04 +01:00
Simon Frei
f63cdbfcfa lib: Apply config changes sequentially (ref #5298) (#7188) 2021-01-15 15:43:34 +01:00
Simon Frei
b2d82da20d lib/model: Pull when folder leaves error state (fixes #7280) (#7281) 2021-01-14 13:29:01 +01:00
Choongkyu
70fddb6523 gui: Disable "Rescan All" when all folders are paused (fixes #7257) (#7278) 2021-01-14 09:15:47 +01:00
Choongkyu
83cfd308b4 gui: Fix log-tailing behavior when scrolled to top (fixes #7267) (#7272) 2021-01-13 20:08:39 +01:00
Jakob Borg
36acaf5e21 lib/fs: Avoid blocking new caseFs creation while waiting to drop cache (fixes #7273) (#7275) 2021-01-13 17:45:29 +01:00
Jakob Borg
572ccfe3e2 gui, man, authors: Update docs, translations, and contributors 2021-01-13 07:45:46 +01:00
Jakob Borg
253049a4cc lib/api, lib/model: Avoid contention on filesystem for DB status call (ref #7270) (#7271)
This splits the ignore getting to two methods, one that loads from disk
(the old one) and one that just returns whatever is already loaded (the
new one). The folder summary service which is just interested in stats
now uses the latter method. This means that it, and API calls that call
it, does not get blocked by folder I/O.
2021-01-12 16:25:21 +01:00
Jakob Borg
8f199e12b3 lib/fs, lib/model: Reduce lock contention on NewCaseFilesystem (fixes #7268) (#7269) 2021-01-12 16:22:21 +01:00
greatroar
f6fac3e949 lib/ur: Plug file descriptor leak in Linux memorySize (#7266) 2021-01-11 15:15:21 +01:00
Jakob Borg
0b193b76c2 lib/config, lib/connections: Add optional connection limits (fixes #7176) (#7223)
This adds two new configuration options:

    // The number of connections at which we stop trying to connect to more
    // devices, zero meaning no limit. Does not affect incoming connections.
    ConnectionLimitEnough int

    // The maximum number of connections which we will allow in total, zero
    // meaning no limit. Affects incoming connections and prevents
    // attempting outgoing connections.
    ConnectionLimitMax int

These can be used to limit the number of concurrent connections in
various ways.
2021-01-11 15:14:44 +01:00
Jakob Borg
e6f0ed65be gui, man, authors: Update docs, translations, and contributors 2021-01-06 07:45:28 +01:00
Jakob Borg
b13b15758d lib/connections, lib/model: Track last connection duration (ref #7223) (#7242)
This adds a statistic to track the last connection duration per device.
It isn't used for much in this PR, but it's available for #7223 to use
in deciding how to order device connection attempts (deprioritizing
devices that just dropped our connection the last time).
2021-01-05 17:45:07 +01:00
Simon Frei
c48eb4241a lib/model: Fix child-check when deleting dirs in pull (#7236) 2021-01-02 21:40:37 +01:00
Simon Frei
0f8290485e lib/model: Handle index sender terminating due to error (fixes #7231) (#7232) 2020-12-30 09:59:11 +01:00
André Colomb
3d1edd2492 lib/fs: Fix TestChmodDir depending on umask (fixes #6551) (#7241)
The test would fail if the umask on UNIX is greater than 0022, because
the OS transparently subtracts it from the mode passed to Mkdir(), as
the Go documentation confirms.

Our goal here is not to test os.Mkdir(), so just make sure the desired
mode is actually set by forcing it afterwards.
2020-12-30 09:56:10 +01:00
Jakob Borg
a73db6fd84 gui, man, authors: Update docs, translations, and contributors 2020-12-30 07:45:26 +01:00
Simon Frei
a05dc6cc47 lib/model: Cleanup redundant filesystem variables in folders (#7237) 2020-12-27 22:26:25 +01:00
Simon Frei
5440d1dc3b gui: Do not replace zero versioning cleanup interval (#7234) 2020-12-27 10:08:15 +01:00
Simon Frei
f13e6ca631 lib/model: Remove obsolete return val from ccHandleFolders (ref #6443) (#7229) 2020-12-23 13:10:08 +01:00
Jakob Borg
81553b4da7 gui, man, authors: Update docs, translations, and contributors 2020-12-23 07:45:28 +01:00
André Colomb
07618f8674 gui: Fix missing sharing device when adding pending folder (#7227) 2020-12-22 22:37:29 +01:00
André Colomb
1555a4da7f cmd/stevents: Add command line argument for event type filtering. (#7226)
Add a -types flag which can be set to a comma-separated list of event
types.  The contents will be included verbatim in the URL parameter
"events".
2020-12-22 22:10:26 +01:00
Simon Frei
a20a5f61f0 lib/ur: Send unreported failures on shutdown (#7164) 2020-12-22 20:17:14 +01:00
André Colomb
4bcc38cf63 gui: Fix nonfunctional ignore button on pending folder notification (#7224)
The merge of #6443 apparently introduced a wrong argument name in
$scope.ignoreFolder().
2020-12-22 07:28:10 +01:00
Jakob Borg
05f25e600e lib/connections: Refactor connection loop (#7177)
This breaks out some methods from the connection loop to make it simpler
to manage and understand.

Some slight simplifications to remove the `seen` variable (we can filter
`nextDial` based on times are in the future or not, so we don't need to
track `seen`) and adding a minimum loop interval (5s) in case some
dialer goes haywire and requests a 0s redial interval or such.

Otherwise no significant behavioral changes.
2020-12-21 16:40:13 +01:00
Simon Frei
a744dee94c lib/fs: Correct wrapping order for meaningful log-caller (#7209) 2020-12-21 13:01:34 +01:00
Simon Frei
78bd0341a8 all: Handle errors opening db/creating file-set (ref #5907) (#7150) 2020-12-21 12:59:22 +01:00
Roberto Santalla
b5de49917c cmd/relaypoolsrv: Allow validation of relay join requests by certificate (fixes #7196) (#7217) 2020-12-21 11:55:16 +01:00
Simon Frei
c845e245a1 lib: Close underlying conn in protocol (fixes #7165) (#7212) 2020-12-21 11:40:51 +01:00
Simon Frei
4a787986cd lib/db: Prevent IndexID creation race (#7211) 2020-12-21 11:32:59 +01:00
Simon Frei
78a41828fc gui: Reflect change in untrusted in sharing tab (#7201) 2020-12-21 11:11:44 +01:00
Simon Frei
bd0c9913cf lib/db: Remove index ids when dropping folder (#7200) 2020-12-21 11:10:59 +01:00
Simon Frei
d904dfa191 lib/model: Fix flaky test and add some scanning debug (#7214) 2020-12-20 18:13:35 +01:00
Simon Frei
fa40ccece1 lib: Consistently set suture logging (#7202) 2020-12-18 19:44:00 +01:00
Simon Frei
7919310dc6 lib/model: Unflake TestIgnoreDeleteUnignore (#7208) 2020-12-18 18:42:09 +01:00
Simon Frei
7669af578a gui: Apply changes to untrusted (ref #6443) (#7206) 2020-12-17 23:13:28 +01:00
Simon Frei
739e99c4d9 lib/config: Remove deprecated pending entries from config (ref #6443) (#7204) 2020-12-17 22:49:29 +01:00
André Colomb
7502997e7e all: Store pending devices and folders in database (fixes #7178) (#6443) 2020-12-17 19:54:31 +01:00
Jakob Borg
4470cd5aaa gui, man, authors: Update docs, translations, and contributors 2020-12-16 07:45:23 +01:00
André Colomb
466e8a5cd0 gui: Sort folders and devices in advanced config modal (#7192) 2020-12-14 16:45:38 +01:00
Jakob Borg
4142a431b5 model: Actually print folder description in "Overriding" log message 2020-12-12 12:32:24 +01:00
Jakob Borg
5565afdd9f gui: version.tags is an array, which is truthy when empty 2020-12-12 10:34:26 +01:00
Simon Frei
0db3b7a530 build: Switch to gopsutil's v3 module (#7191) 2020-12-10 16:43:15 +01:00
Simon Frei
b37ecc3cf4 build: Update notify (fixes #7076) (#7189) 2020-12-10 15:43:05 +01:00
Jakob Borg
ec5a5d5218 lib/api: Returns tags in version as list (#7190) 2020-12-10 12:22:09 +01:00
Jakob Borg
7980c8cea2 gui: Harmonize architecture names 2020-12-10 11:23:47 +01:00
Jakob Borg
e9b68a224c lib/connections: Handle QUIC not being available (#7186)
This does two things:

- Exclude QUIC from go1.16 builds, automatically, for now, since it
  doesn't work and just panics.

- Provide some fake listeners and dialers when QUIC is disabled.

These fake listeners and dialers indicate that they are disabled and
unsupported, which silences "Dialing $address: unknown address scheme:
quic" type of stuff which is not super helpful to the user.
2020-12-09 19:23:50 +01:00
Simon Frei
8fd6b1d428 lib/protocol: Handle slashified paths in IsEncryptedParent (fixes #7184) (#7187) 2020-12-09 18:16:14 +01:00
André Colomb
4198b5061f gui: Split folders into two categories on the sharing tab for devices (#7162) 2020-12-09 14:54:51 +01:00
Jakob Borg
b0a525a504 gui, man, authors: Update docs, translations, and contributors 2020-12-09 07:45:25 +01:00
Eric Lesiuta
25d904dc37 gui: Fix blank device name under "Recent Changes" (#7185)
fixes the device showing up as blank if the friendly name is known
2020-12-07 22:19:28 +01:00
Simon Frei
c1b452df93 build: Upgrade quic-go to v0.19.3 (ref #7146) (#7180) 2020-12-06 13:46:27 +01:00
Jakob Borg
28bc8b6153 gui, man, authors: Update docs, translations, and contributors 2020-12-02 07:45:24 +01:00
Simon Frei
cccbb0bd5e lib/ur: Reset timer when there's nothing to report (#7169) 2020-11-28 20:09:22 +01:00
Simon Frei
240ae0c14f lib/model: Unflake TestRequestReceiveEncryptedLocalNoSend (#7167) 2020-11-27 20:53:03 +01:00
Jakob Borg
9a9b7002cd Merge branch 'release' into main
* release:
  gui: Restore Select / Deselect All buttons in device sharing tab. (#7161)
2020-11-27 16:41:16 +01:00
André Colomb
b16cc72fc7 gui: Restore Select / Deselect All buttons in device sharing tab. (#7161)
This fixes a regression by restoring two functions removed in commit
a20d85d451, but still used from the HTML
template.  Adjust the restored versions to access the new flag storage
structure.

The replacement functions selectAllSharedFolders() and
selectAllUnrelatedFolders() are not functional, so this is just a
quick fix to restore a working state before making the new functions
actually work sensibly.

Just like the respective functions for sharing device selections, give
it a boolean argument instead of writing two almost identical
functions.

In line with the other selectAll...() functions, avoid calling
angular.forEach() and iterate over the folders object directly.
2020-11-27 14:33:58 +01:00
André Colomb
ab53687c38 gui: Restore Select / Deselect All buttons in device sharing tab. (#7161)
This fixes a regression by restoring two functions removed in commit
a20d85d451, but still used from the HTML
template.  Adjust the restored versions to access the new flag storage
structure.

The replacement functions selectAllSharedFolders() and
selectAllUnrelatedFolders() are not functional, so this is just a
quick fix to restore a working state before making the new functions
actually work sensibly.

Just like the respective functions for sharing device selections, give
it a boolean argument instead of writing two almost identical
functions.

In line with the other selectAll...() functions, avoid calling
angular.forEach() and iterate over the folders object directly.
2020-11-27 11:48:48 +01:00
Simon Frei
bbb22c8c80 lib/protocol: Send Close message on read error (#7141) 2020-11-27 11:31:20 +01:00
Simon Frei
a9764fc16c lib: Skip deleted, locally changed on recv-enc folders (fixes #7153) (#7154) 2020-11-27 11:26:36 +01:00
Audrius Butkevicius
af13f0cd35 lib/stun: Don't notify about address changes if it's not useful (fixes #7144) (#7159) 2020-11-27 07:34:30 +01:00
Simon Frei
e1b958284e lib/api: Shut the api down gracefully (fixes #7138) (#7157) 2020-11-26 15:49:39 +01:00
Simon Frei
bf7d03d029 lib/model: Fix enc file size when pulling (fixes #7152) (#7155) 2020-11-25 22:57:25 +01:00
Simon Frei
3169212046 lib/db: Do not reset index-id when dropping device (ref #7135) (#7156)
This reverts commit 641b7aee38.
2020-11-25 22:54:05 +01:00
Simon Frei
54b50e3d52 lib/fs, lib/model: Cover more windowsyness sanitizing paths (fixes #7075) (#7158) 2020-11-25 22:52:46 +01:00
Jakob Borg
c6f2ec9400 gui, man, authors: Update docs, translations, and contributors 2020-11-25 07:45:27 +01:00
André Colomb
e6595c1ab9 lib/model: Simplify access to Folder and Device configuration. (#7151)
Use the accessor methods with a device argument instead of looking up
in a temporary map of the same data.
2020-11-24 22:20:50 +01:00
Simon Frei
6c7e8c08db build: Ignore noscript in translation-script (#7149) 2020-11-24 22:17:52 +01:00
Jakob Borg
6864f7c9d0 gui: Remove probing for remote GUI address (ref #7017) (#7136) 2020-11-24 22:07:22 +01:00
Simon Frei
e5c1948b94 gui: Fix & improve sharing with untrusted device (#7148) 2020-11-24 22:02:16 +01:00
Simon Frei
100ef10d84 lib/model: Don't send locally changed on recv-enc (fixes #7137) (#7147) 2020-11-24 21:49:45 +01:00
Simon Frei
5d2c83a7e9 lib/protocol: Fix OOR panic on recv-only folders (#7143) 2020-11-23 18:37:27 +01:00
Simon Frei
8e5c844370 gui: Incorrect recv-enc folder status after revert (#7142) 2020-11-23 18:35:36 +01:00
Simon Frei
8ebd893349 lib/db: Store versions for last successful db migration (#7140) 2020-11-23 18:31:32 +01:00
dependabot-preview[bot]
cc4071d0ba build(deps): bump github.com/lucas-clemente/quic-go (#7139)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.18.1 to 0.19.2.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.18.1...v0.19.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-11-23 09:04:58 +01:00
Jakob Borg
b253022a96 build: Take extra tags in account for tar, zip 2020-11-20 17:45:07 +01:00
Simon Frei
db1f20603a lib/model: Retain index info for new folders/devs (ref #7100) (#7133) 2020-11-20 15:53:13 +01:00
Simon Frei
24af89c8e2 all: Refactor preparing configuration (#7127) 2020-11-20 14:21:54 +01:00
Simon Frei
641b7aee38 lib/db: Reset index-id when dropping device (#7135) 2020-11-20 14:17:09 +01:00
Simon Frei
b43eccf2fe lib/model: Never send unpaused folder without index info (#7134) 2020-11-20 14:13:50 +01:00
Jakob Borg
7f63afcb99 Merge branch 'release' into main
* release:
  gui: Remove erronous $ from scope in directive (fixes #7124) (#7125)
2020-11-18 14:27:00 +01:00
Simon Frei
dcddd9c1e4 gui: Remove erronous $ from scope in directive (fixes #7124) (#7125) 2020-11-18 14:22:38 +01:00
Simon Frei
e11b309379 lib/model, lib/util: Replace IsComplete with NoRestartErr (ref #6947) (#7126) 2020-11-18 13:43:57 +01:00
Simon Frei
53fd54e308 gui: Remove erronous $ from scope in directive (fixes #7124) (#7125) 2020-11-18 13:33:19 +01:00
Simon Frei
2d3a535ced lib/model: Handle cluster-config before folder start (fixes #7122) (#7123) 2020-11-17 15:30:21 +01:00
Simon Frei
9524b51708 all: Implement suture v4-api (#6947) 2020-11-17 13:19:04 +01:00
Simon Frei
e8fc465ea8 lib/config: Use correct var in MaxConcurrentIncomingRequestKiB() (#7121) 2020-11-16 16:51:51 +01:00
Phani Rithvij
1491898fd4 build: Update delve issue link (#7119) 2020-11-16 09:54:31 +01:00
Jakob Borg
cca73de6a1 lib/osutil: Consider sync() best effort (fixes #7117) 2020-11-14 09:23:27 +01:00
Jakob Borg
5e669e0ae1 Merge branch 'release' into main
* release:
  gui: Initialise sharing when accepting new device (fixes #7113) (#7114)
2020-11-11 18:19:44 +01:00
Simon Frei
35c813f56f gui: Initialise sharing when accepting new device (fixes #7113) (#7114) 2020-11-11 18:18:52 +01:00
Simon Frei
1f81940a1f gui: Initialise sharing when accepting new device (fixes #7113) (#7114) 2020-11-11 18:18:34 +01:00
Simon Frei
b8051fb37e lib/model: Prevent test deadlock (#7110) 2020-11-10 12:32:07 +01:00
Simon Frei
1d3b9876f6 lib/api, lib/db: Add file debug endpoint (#7095) 2020-11-10 09:24:45 +01:00
Rahmi Pruitt
2f6a25a56f gui: Add advance config port mapping to gui (fixes #4824) (#7017) 2020-11-10 09:24:11 +01:00
Jakob Borg
846b265430 lib/tlsutil: Add O and OU to generated certificates (fixes #7108) (#7109) 2020-11-09 17:02:56 +01:00
Simon Frei
31559e908b all: Add untrusted folders behind feature flag (ref #62) (#7055) 2020-11-09 15:33:32 +01:00
Simon Frei
4db5ea5893 build: Update notify (fixes #5360) (#7106) 2020-11-09 14:25:19 +01:00
Simon Frei
54643e86b5 lib/model: Fix locking when resending cluster-configs (#7107) 2020-11-09 14:05:21 +01:00
Jakob Borg
326111d10f gui: Remove superfluous translate in previous (ref #7102) 2020-11-09 09:46:45 +01:00
Tomasz Wilczyński
0fb7cc186c gui: Add warning when JavaScript is disabled in Web browser (fixes #7099) (#7102)
When using a Web browser with JavaScript either disabled or unavailable,
show a warning to let the user know that the Web GUI requires JS in
order to operate.

To achieve this, add a <div> that wraps both the navbar and the main
content, and then move the CSS class ng-cloak from the <html> element to
that <div>. This way, only the JavaScript-dependent part is hidden when
JS is unavailable, and not the whole website, as it is the case right
now. Then, add a <noscript> element right at the start of the <body>
element, so that the warning is also shown right away in text-based Web
browsers. The <noscript> element includes a stripped down version of the
navbar showing only the Syncthing logo, and then a container with the
warning itself. Lastly, leave the footer untouched and always visible,
because it does not rely on JavaScript at all.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2020-11-09 09:15:22 +01:00
Simon Frei
1f1729ba43 lib/model: Add done chan to track folder-lifetime (fixes #6664) (#7094) 2020-11-09 09:05:48 +01:00
Simon Frei
d4ce0dfd84 lib/model: Send indexes for newly shared folder (fixes #7098) (#7100) 2020-11-09 08:58:46 +01:00
Simon Frei
cc9ea9db89 lib/folder: Clear pull errors when nothing is needed anymore (#7093) 2020-11-06 14:22:20 +01:00
Simon Frei
a08a1b6998 lib/api: Fix debug endpoints (ref #7001) (#7092) 2020-11-06 14:21:37 +01:00
Jakob Borg
33185fdeb5 gui, man, authors: Update docs, translations, and contributors 2020-11-04 07:45:27 +01:00
Simon Frei
d0ccea0404 lib/config: Sanity checks on MaxConcurrentWrites (ref #7064) (#7069) 2020-11-03 19:09:32 +01:00
Jakob Borg
c206fbdc58 Merge branch 'release' into main
* release:
  lib/ur: Fix panics in failure-reporting (fixes #7090) (#7091)
2020-11-03 12:34:23 +01:00
Simon Frei
2b9cef3ae5 lib/ur: Fix panics in failure-reporting (fixes #7090) (#7091) 2020-11-03 12:29:54 +01:00
Simon Frei
a38b370c8d lib/ur: Fix panics in failure-reporting (fixes #7090) (#7091) 2020-11-03 12:29:33 +01:00
Jakob Borg
942b8ebb27 build: Update dependencies (#7088) 2020-11-03 09:11:00 +01:00
Jakob Borg
7892547873 lib: Remove USE_BADGER experiment (#7089)
This removes the switch for using a Badger database, because it has bugs
that it seems there is no interest in fixing, and no actual bug tracker
to track them in.

It retains the actual implementation for the sole purpose of being able
to do the conversion back to LevelDB if anyone is actually running with
USE_BADGER. At some point in a couple of versions we can remove the
implementation as well.
2020-11-03 09:10:35 +01:00
Simon Frei
5b9280c50f build: Update notify (fixes #7063) (#7080) 2020-11-01 21:37:31 +01:00
Simon Frei
4d1bcd718c lib/api: Fix /rest/config path and add methods to cors (ref #7001) (#7081) 2020-11-01 21:36:54 +01:00
André Colomb
7dc0c6ab43 lib/api: Allow OPTIONS method in CORS preflight request handling (ref #7017) (#7079)
This allows for checking GUI / API availability without actually doing
a GET or POST request.
2020-11-01 14:29:55 +01:00
André Colomb
9d1ee2f7e0 gui: Fix another undefined variable access (fixes #7077) (#7078) 2020-11-01 13:15:20 +01:00
Tomasz Wilczyński
4a616f3cb2 lib/config: Check for "msdos" when detecting FAT FS in Android (#7072) 2020-10-30 15:13:56 +01:00
Jakob Borg
deafe4ca53 gui, man, authors: Update docs, translations, and contributors 2020-10-28 07:45:27 +01:00
Simon Frei
bc012d750d gui: Readd check if device exists (ref #7059) (#7061)
This reverts commit c7d40ccbae.
2020-10-27 16:40:16 +01:00
André Colomb
c7d40ccbae gui: Remove needless looping in ignoreFolder() (#7059) 2020-10-26 11:27:03 +01:00
André Colomb
0d90ae26ac gui: Fix undefined variables fallout from #7049 (#7056) 2020-10-26 09:09:32 +01:00
Simon Frei
9189c79d74 lib/api: Add missing config mod. locks (ref #7001) (#7053) 2020-10-23 10:34:20 +02:00
Simon Frei
a20d85d451 gui: Refactor to make encryption diff smaller (#7049) 2020-10-23 08:27:02 +02:00
Simon Frei
f0f60ba2e7 lib/api: Add /rest/config endpoint (fixes #6540) (#7001) 2020-10-22 19:54:35 +02:00
Simon Frei
1c2be84e4e lib/model: Pass device infos as struct (fixes #7051) (#7052) 2020-10-22 13:05:31 +02:00
Simon Frei
2ba3be5e4d lib/db: Add mechanism to repair db without schema update (ref #7044) (#7047) 2020-10-21 14:21:09 +02:00
Simon Frei
5c91723ef2 lib/model: Handle index sender lifetime (fixes #7034) (#7038) 2020-10-21 11:51:53 +02:00
Audrius Butkevicius
a17a8cd48b lib/connections: Fix LAN addresses begin advertised even when disabled (fixes #7035) (#7045) 2020-10-21 09:16:44 +02:00
Simon Frei
27c91c57d5 lib/db: Remove need for the right dev removing globals (fixes #7036) (#7044) 2020-10-21 08:26:10 +02:00
Jakob Borg
86b040f595 gui, man, authors: Update docs, translations, and contributors 2020-10-21 07:45:23 +02:00
Simon Frei
1a8c10a8d0 lib/model: Use winning version instead of merge on conflict (#6995) 2020-10-19 08:53:19 +02:00
Simon Frei
01a7ef3b0f lib/db: Undo adding user info to panic msgs (ref #7029) (#7040) 2020-10-19 08:40:37 +02:00
Simon Frei
23c935b05a lib/db: Ignore not found on delete in recalcGlobal (ref #7026) (#7041) 2020-10-19 08:28:53 +02:00
Jakob Borg
8e8e30dc7b gui, man, authors: Update docs, translations, and contributors 2020-10-14 07:45:25 +02:00
Simon Frei
d828adb648 cmd/stcrashreceiver, lib/db: Improve panic message handling (#7029) 2020-10-08 17:37:45 +02:00
Simon Frei
9d09fd6af3 all: Add failure reporting (fixes #7028) (#6925) 2020-10-07 10:05:13 +02:00
Jakob Borg
b1db328931 gui, man, authors: Update docs, translations, and contributors 2020-10-07 07:45:24 +02:00
Simon Frei
14ae330eff lib/db: Improve error handling checking db (ref #7026) (#7027) 2020-10-06 20:14:09 +02:00
Felix Lampe
977ee4f06b gui: Fix NaN percentage for zero byte files (fixes #7002) (#7025) 2020-10-06 17:17:34 +02:00
Simon Frei
42de53c6c9 lib/model: Fix race in GlobalDirectory tests (fixes #7021) (#7022) 2020-10-03 20:46:17 +02:00
Simon Frei
48da6f0f22 lib: Use uint64 for disk stats (ref #3930) (#7019) 2020-10-02 15:22:28 +02:00
Simon Frei
a20c6ca868 lib/model, lib/protocol: Send ClusterConfig on config change (fixes #7020) (#7018) 2020-10-02 11:49:51 +02:00
Audrius Butkevicius
e027175446 all: Move remaining protos to use the vanity plugin (#7009) 2020-10-02 08:07:05 +02:00
Jakob Borg
7774932302 lib/config, lib/syncthing: Only drop delta index on upgrade if so ordered (fixes #6982) (#6983) 2020-09-30 20:16:30 +02:00
Jakob Borg
3fe331c2d0 gui, man, authors: Update docs, translations, and contributors 2020-09-30 07:45:22 +02:00
Simon Frei
1b1d38183d lib: Remove HelloResult type, same as Hello (#7015) 2020-09-29 12:17:38 +01:00
Tomasz Wilczyński
fb3281b647 lib/fs: Add COM0 and LPT0 to invalid Windows file names (ref #7008) (#7013)
COM0 and LPT0 are not listed in the official Microsoft's documentation
at https://docs.microsoft.com/windows/win32/fileio/naming-a-file, but
in reality are also invalid in Windows Explorer.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2020-09-28 20:35:54 +02:00
Jakob Borg
e6b1f67ecf lib/fs: Be even more strict about Windows names (ref #7008) (#7012)
Things like nul.whatever.txt are also not allowed.
2020-09-28 10:42:37 +02:00
Jakob Borg
9e0b924d57 lib/fs: Be more clear about invalid file names (ref #7010) (#7011)
Add specific errors for the failures, resulting in this rather than just
the generic "invalid filename":

[MRIW7] 08:50:50 INFO: Puller (folder default, item "NUL"): syncing: filename is invalid: name is reserved
[MRIW7] 08:50:50 INFO: Puller (folder default, item "fail."): syncing: filename is invalid: name ends with space or period
[MRIW7] 08:50:50 INFO: Puller (folder default, item "sup:yo"): syncing: filename is invalid: name contains reserved character
[MRIW7] 08:50:50 INFO: default: Failed to sync 3 items
2020-09-28 10:22:50 +02:00
Jakob Borg
df99237a7f lib/model: Disallow reserved names, and names ending with period on Windows (fixes #7008) (#7010)
Like we already do with names ending in space or containing invalid
characters.
2020-09-28 08:25:43 +01:00
Simon Frei
8452fd2ab4 lib/model, lib/scanner: Prevent races aborting scans (fixes #6994) (#6997) 2020-09-25 11:27:44 +02:00
Tobias Klauser
c390565eef lib/fs: Use file clone ioctl wrappers and types from golang.org/x/sys/unix (#7000)
Use the IoctlFileClone and IoctlFileCloneRange ioctl wrappers and the
FileCloneRange type provided by golang.org/x/sys/unix instead of
locally implementing them. This also allows to re-enable the code for
ppc/ppc64/ppc64le again (see commit 758a1a6a37 ("lib/fs: Disable ioctl
on ppc (fixes #6898) (#6901)")) since golang.org/x/sys/unix internally
uses the correct FICLONE and FICLONERANGE values depending on $GOARCH.
2020-09-24 10:29:32 +02:00
Audrius Butkevicius
02744cd73f Update config.yml 2020-09-23 08:30:46 +01:00
Jakob Borg
bd622b8edd gui, man, authors: Update docs, translations, and contributors 2020-09-23 07:45:25 +02:00
Jakob Borg
67761d8795 cmd/ursrv: Properly sort versions (fixes #6991) 2020-09-18 08:11:48 +02:00
Jakob Borg
9f8b01b1b9 cmd/ursrv: Recognize new-style dev versions 2020-09-18 08:11:44 +02:00
Jakob Borg
d2e3295767 gui, man, authors: Update docs, translations, and contributors 2020-09-16 07:45:24 +02:00
Jakob Borg
aa65c6f249 build: Dockerfile that expects ready baked binaries 2020-09-15 19:38:23 +02:00
Simon Frei
8210466b03 lib/model: Consider case conflicts when checking to be deleted items (#6986) 2020-09-12 07:45:50 +02:00
greatroar
3e24d82513 lib/fs: Optimize UnicodeLowercase (#6979)
Most notably, it now detects all-lowercase files and returns these
as-is. The tests have been expanded with two cases and are now used
as a benchmark (admittedly a rather trivial one).

name                           old time/op    new time/op    delta
UnicodeLowercaseMaybeChange-8    4.59µs ± 2%    4.57µs ± 1%    ~     (p=0.197 n=10+10)
UnicodeLowercaseNoChange-8       3.26µs ± 1%    3.09µs ± 1%  -5.27%  (p=0.000 n=9+10)
2020-09-11 09:16:10 +02:00
Simon Frei
08bebbe59b lib/db, lib/syncthing: Don't repair DB on upgrade, but on error (fixes #6917) (#6971) 2020-09-10 10:54:41 +02:00
Simon Frei
c5c23ed10f lib/model: Consider existing file when handling symlink on windows (#6977) 2020-09-10 10:52:38 +02:00
Simon Frei
286698ccb1 lib/model: Handle symlink deletion on windows (fixes #6972) (#6976) 2020-09-10 08:25:44 +02:00
Simon Frei
56d48d341f lib/model: Fix case-only renames on pull (#6978) 2020-09-10 08:23:54 +02:00
Jakob Borg
780fb3bac1 lib/fs: More efficient casefs cache (#6974)
This changes the cache to cache less things, yet retain the required
efficiency for our walk usecase. This uses less memory.

Specifically, instead of keeping result and child caches for each path
level, only keep a single cached child. In practice our operations are
depth-first, or almost depth-first, and then we retain the same hit
ratio for a smaller cache size.

I improved the benchmark so that it counts the Lstat and DirNames
operations performed, and they do not change significantly. The amount
of allocated memory is reduced by 20% and the walk itself is actually
slightly faster.

This also removes the clear based on number of cached names (as that is
not a thing any more) and the timer based clear (which was unused). This
means we'll retain the last cache state forever until it's cleared by a
write operation, but we did that before too and that state is now a lot
smaller...

The overhead compared to not using a casefs, for our typical "double
walk" (walk the tree then stat everything again) is 2x the dirnames we
would otherwise call, and no overhead on the stats (unchanged from old
implementation)

```
name                         old time/op         new time/op         delta
WalkCaseFakeFS100k/rawfs-8           306ms ± 1%          305ms ± 2%     ~     (p=0.182 n=9+10)
WalkCaseFakeFS100k/casefs-8          579ms ± 5%          557ms ± 1%   -3.77%  (p=0.000 n=10+10)

name                         old B/entry         new B/entry         delta
WalkCaseFakeFS100k/rawfs-8             590 ± 0%            590 ± 0%     ~     (all equal)
WalkCaseFakeFS100k/casefs-8          1.09k ± 0%          0.87k ± 0%  -19.98%  (p=0.000 n=10+10)

name                         old DirNames/entry  new DirNames/entry  delta
WalkCaseFakeFS100k/rawfs-8            0.51 ± 0%           0.51 ± 0%     ~     (all equal)
WalkCaseFakeFS100k/casefs-8           1.02 ± 0%           1.02 ± 0%     ~     (all equal)

name                         old DirNames/op     new DirNames/op     delta
WalkCaseFakeFS100k/rawfs-8           51.2k ± 0%          51.2k ± 0%     ~     (all equal)
WalkCaseFakeFS100k/casefs-8           102k ± 0%           102k ± 0%     ~     (all equal)

name                         old Lstat/entry     new Lstat/entry     delta
WalkCaseFakeFS100k/rawfs-8            3.02 ± 0%           3.02 ± 0%     ~     (all equal)
WalkCaseFakeFS100k/casefs-8           3.02 ± 0%           3.02 ± 0%     ~     (all equal)

name                         old Lstat/op        new Lstat/op        delta
WalkCaseFakeFS100k/rawfs-8            302k ± 0%           302k ± 0%     ~     (all equal)
WalkCaseFakeFS100k/casefs-8           302k ± 0%           302k ± 0%     ~     (all equal)

name                         old allocs/entry    new allocs/entry    delta
WalkCaseFakeFS100k/rawfs-8            15.7 ± 0%           15.7 ± 0%     ~     (all equal)
WalkCaseFakeFS100k/casefs-8           27.5 ± 0%           26.1 ± 0%   -5.09%  (p=0.000 n=10+10)

name                         old ns/entry        new ns/entry        delta
WalkCaseFakeFS100k/rawfs-8           2.02k ± 1%          2.02k ± 2%     ~     (p=0.163 n=9+10)
WalkCaseFakeFS100k/casefs-8          3.83k ± 5%          3.68k ± 1%   -3.77%  (p=0.000 n=10+10)

name                         old alloc/op        new alloc/op        delta
WalkCaseFakeFS100k/rawfs-8          89.2MB ± 0%         89.2MB ± 0%     ~     (p=0.364 n=9+10)
WalkCaseFakeFS100k/casefs-8          164MB ± 0%          131MB ± 0%  -19.97%  (p=0.000 n=10+10)

name                         old allocs/op       new allocs/op       delta
WalkCaseFakeFS100k/rawfs-8           2.38M ± 0%          2.38M ± 0%     ~     (all equal)
WalkCaseFakeFS100k/casefs-8          4.16M ± 0%          3.95M ± 0%   -5.05%  (p=0.000 n=10+10)
```
2020-09-09 14:38:39 +02:00
Simon Frei
e3cd9219b8 lib/model: Don't fail over case-conflict on tempfile (fixes #6973) (#6975) 2020-09-09 11:47:14 +02:00
Jakob Borg
44658258d2 gui, man, authors: Update docs, translations, and contributors 2020-09-09 07:45:21 +02:00
Simon Frei
b628ec5054 lib/fs: Use generic case resolver on windows (fixes #6968) (#6969) 2020-09-08 13:10:26 +02:00
Simon Frei
ecc24428ac lib/model: Prevent duplicate need count on recalculating metadata (#6964) 2020-09-07 20:19:03 +02:00
Jakob Borg
674fca3868 lib/db, lib/protocol: Never need empty-version entries (fixes #6961) (#6962)
Avoid havoc when discovering locally-deleted-upgraded files during repair / need calculation...

Co-authored-by: Simon Frei <freisim93@gmail.com>
2020-09-07 20:18:25 +02:00
Simon Frei
e19728d8cc lib/model: Correct completion perc. when globalBytes is 0 (#6963) 2020-09-07 20:03:18 +02:00
Jakob Borg
415adfbae6 lib/db: Don't hang on double iterator release with Badger (#6960)
Since iterators must be released before committing or discarding a
transaction we have the pattern of both deferring a release plus doing
it manually. But we can't release twice because we track this with a
WaitGroup that will panic when there are more Done()s than Add()s. This
just adds a boolean to let an iterator keep track.
2020-09-07 10:31:33 +02:00
Simon Frei
3dd13c3994 test, lib/model: Various integration test updates & improvements (#6956) 2020-09-07 09:35:37 +02:00
Simon Frei
52d1681fe6 lib/db: Copy returned, old FileVersion (#6952) 2020-09-04 14:13:38 +02:00
Simon Frei
7b821d2550 lib/db: Add local need check&repair (#6950) 2020-09-04 14:01:46 +02:00
Simon Frei
0e3e0a7c9e cmd/stindex, lib/db: Use same condition to check for needed files (#6954) 2020-09-04 13:59:04 +02:00
Jakob Borg
71bfad0bc6 cmd/stindex: Add dumping folder meta 2020-09-04 11:39:21 +02:00
Jakob Borg
b7986801cd cmd/stindex: Print more hashes and versions 2020-09-04 09:10:33 +02:00
Jakob Borg
7e738118df github: Create FUNDING.yml via GitHub settings GUI 2020-09-04 07:47:09 +02:00
Simon Frei
6365e6108f lib/model: Don't acquire I/O token for send-only pull (#6951) 2020-09-03 13:59:45 +02:00
Jaroslav Lichtblau
e3e46ec1de cmd/ursrv: BUILDHOST name changed for Arch (#6948)
Recognize both old and new.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2020-09-02 08:20:25 +02:00
Jakob Borg
0d3db38b2f gui, man, authors: Update docs, translations, and contributors 2020-09-02 07:45:21 +02:00
Simon Frei
540518a7b7 lib/model: Add missing lock on download-state (fixes #6880) (#6945) 2020-08-30 08:03:10 +02:00
Simon Frei
44bf8cfd27 build: Improve translation script (fixes #6943) (#6944) 2020-08-30 08:01:46 +02:00
Tomasz Wilczyński
563cea0dbe gui: Use indexOf instead of startsWith for IE11 compatibility (fixes #6940) (#6942)
Use indexOf() == 0 instead of startsWith() to maintain compatibility
and prevent JavaScript error console spam in the Web GUI when used in
Internet Explorer 11 under Windows 7.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2020-08-29 12:26:31 +02:00
Jakob Borg
55fddacdc2 Merge branch 'release' into main
* release:
  lib/db, lib/model: Avoid accounting mishap on folder restart (fixes #6938) (#6939)
  lib/model: Save config after auto accepting folders (fixes #6922) (#6937)
2020-08-28 07:48:40 +02:00
Jakob Borg
3943873626 lib/db, lib/model: Avoid accounting mishap on folder restart (fixes #6938) (#6939)
We created a new fileset before stopping the folder during restart. When
we create that fileset it loads the current metadata and sequence
numbers from the database. But the folder may have time to update those
before stopping, leaving the new fileset with bad data.

This would cause wrong accounting (forgotten files) and potentially
sequence reuse causing files not sent to other devices.

This change reuses the fileset on restart, skipping the issue entirely.
It also moves the creation of the fileset back under the lock so there
should be no chance of concurrency issues here.
2020-08-28 07:48:25 +02:00
Jakob Borg
15ce96f704 lib/model: Save config after auto accepting folders (fixes #6922) (#6937) 2020-08-28 07:48:25 +02:00
Jakob Borg
3ffbe45a6d lib/db, lib/model: Avoid accounting mishap on folder restart (fixes #6938) (#6939)
We created a new fileset before stopping the folder during restart. When
we create that fileset it loads the current metadata and sequence
numbers from the database. But the folder may have time to update those
before stopping, leaving the new fileset with bad data.

This would cause wrong accounting (forgotten files) and potentially
sequence reuse causing files not sent to other devices.

This change reuses the fileset on restart, skipping the issue entirely.
It also moves the creation of the fileset back under the lock so there
should be no chance of concurrency issues here.
2020-08-27 18:33:27 +02:00
Jakob Borg
3393db1f69 lib/model: Save config after auto accepting folders (fixes #6922) (#6937) 2020-08-27 16:28:19 +02:00
Jakob Borg
145d87ce70 lib/model: Fixup spelling of protocol.FileIntf in test (ref #6463) 2020-08-27 16:21:04 +02:00
Simon Frei
06ac631351 lib/model: Reduce fmut locking in ClusterConfig (#6913)
The FileSet.Drop operation in there needs to potentially update a whole lot of global lists, which can take a while (longer than the deadlock interval apparently)
2020-08-27 16:01:46 +02:00
Simon Frei
1fc2dbdeeb lib/model: Add test for recv-only changes undone by remote (#6463)
Co-authored-by: Audrius Butkevicius <audrius.butkevicius@gmail.com>
2020-08-27 15:54:00 +02:00
Simon Frei
3f0eba388c lib/syncthing: Also cleanup on startup error (#6926) 2020-08-27 15:52:51 +02:00
greatroar
0941ce76b7 cmd/strelaypoolsrv: Fix relay shuffling (fixes #6936) (#6935)
When cap(permanentRelays) >= len(permanentRelays) + len(knownRelays),

	append(permanentRelays, knownRelays...)

returns a slice of the array underlying permanentRelays. The subsequent
rand.Shuffle then mixes the permanent and known relays. Sequential
requests may cause strelaypoolsrv to forget its permanent relays. Worse,
concurrent requests may cause shuffling of the same slice on multiple
processors concurrently.

Co-authored-by: greatroar <@>
2020-08-27 15:51:58 +02:00
Rahmi Pruitt
c74df2d588 gui: Fix add folder bug (fixes #6930) (#6931) 2020-08-27 08:59:37 +02:00
Jakob Borg
0ca737b528 gui, man, authors: Update docs, translations, and contributors 2020-08-26 07:45:25 +02:00
Audrius Butkevicius
b19b5c95d3 lib/connections: Announce LAN addresses by default (fixes #6928) (#6896) 2020-08-25 11:48:14 +02:00
Audrius Butkevicius
d507d932b8 all: Use protobuf to generate config structs (fixes #6734) (#6900) 2020-08-25 08:11:14 +02:00
Rahmi Pruitt
5b953033c7 Created cleanup functionality for syncthing (#6884)
* Add clean up for Simple File Versioning pt.1

created test

* Add clean up for Simple File Versioning pt.2

Passing the test

* stuck on how javascript communicates with backend

* Add trash clean up for Simple File Versioning

Add trash clean up functionality of to allow the user to delete backups
after specified amount of days.

* Fixed html and js style

* Refactored cleanup test cases

Refactored cleanup test cases to one file and deleted duplicated code.

* Added copyright to test file

* Refactor folder cleanout to utility function

* change utility function to package private

* refactored utility function; fixed build errors

* Updated copyright year.

* refactor test and logging

* refactor html and js

* revert style change in html

* reverted changes in html and some js

* checkout origin head version edit...html

* checkout upstream master and correct file
2020-08-24 12:14:30 +01:00
dependabot-preview[bot]
dfc3525cf7 build(deps): bump github.com/maruel/panicparse from 1.3.0 to 1.5.1 (#6924)
Bumps [github.com/maruel/panicparse](https://github.com/maruel/panicparse) from 1.3.0 to 1.5.1.
- [Release notes](https://github.com/maruel/panicparse/releases)
- [Commits](https://github.com/maruel/panicparse/compare/v1.3.0...v1.5.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-24 10:18:44 +02:00
Simon Frei
675b535ead build: Bump goleveldb to latest commit (#6895) 2020-08-21 12:35:05 +02:00
Simon Frei
a65b46debd lib/model: Don't mark globally deleted items as recv-only (fixes #6910) (#6911) 2020-08-21 12:34:22 +02:00
Simon Frei
b628460930 lib/model: Prevent localflag flipflopping on del. item (ref #6865) (#6919) 2020-08-21 10:09:48 +02:00
Simon Frei
cc1f6e4d4a lib/db, lib/model: Cover exec-paths with debug logging (#6918) 2020-08-20 16:11:20 +02:00
Jakob Borg
f79e980fdf build: Update QUIC and gopsutil (fixes #6889) (#6915) 2020-08-20 11:57:20 +02:00
Simon Frei
88599bc154 lib/model: Handle del. dir with locally changed items on pull (fixes #6873) (#6914) 2020-08-20 10:56:29 +02:00
Simon Frei
fc2c46e82f lib/config, lib/fs: Make junction behaviour configurable (ref #6606) (#6907) 2020-08-19 19:58:51 +02:00
Simon Frei
ce4d149bf5 lib/nat: Don't hang on draining timer chan (fixes #6908) (#6912) 2020-08-19 15:58:44 +01:00
Audrius Butkevicius
cbbc262161 lib/db: Dont recurse on flush (fixes #6905) (#6906)
Or else we crash.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
Co-authored-by: Simon Frei <freisim93@gmail.com>
2020-08-19 13:13:44 +02:00
Jakob Borg
96e35aa7f5 build: Add -trimpath compiler option (#6904)
Quoting the manual:

    -trimpath
      remove all file system paths from the resulting executable.
      Instead of absolute file system paths, the recorded file names
      will begin with either "go" (for the standard library),
      or a module path@version (when using modules),
      or a plain import path (when using GOPATH).

That is, when we panic, instead of:

    goroutine 1 [running]:
    main.main()
        /Users/jb/dev/syncthing/syncthing/cmd/syncthing/main.go:272 +0x116

we get:

    goroutine 1 [running]:
    main.main()
        github.com/syncthing/syncthing@/cmd/syncthing/main.go:272 +0x116

(Module path and file path within module.)
2020-08-19 09:40:21 +02:00
Jakob Borg
086d1f8f6a build: We now target Go 1.14 2020-08-19 08:49:42 +02:00
Audrius Butkevicius
758a1a6a37 lib/fs: Disable ioctl on ppc (fixes #6898) (#6901) 2020-08-19 07:56:35 +02:00
Jakob Borg
b1bfa9aece gui, man, authors: Update docs, translations, and contributors 2020-08-19 07:45:23 +02:00
Audrius Butkevicius
d0c6c18b4f lib/dialer: Try dialing without reuse in parallel (fixes #6892) (#6893) 2020-08-18 13:11:12 +02:00
Jakob Borg
2286a6ebef cmd/stcrashreceiver: Don't crash on nil err 2020-08-18 12:54:20 +02:00
Audrius Butkevicius
bf9ff17267 all: Remove need to restart syncthing (#6883) 2020-08-18 09:26:33 +02:00
Simon Frei
8f5215878b lib/db: Don't put truncated files (ref #6855, ref #6501) (#6888) 2020-08-18 09:20:12 +02:00
Simon Frei
9c2117f08e lib/osutil: Check returned error instead of info (ref #6885) (#6887) 2020-08-12 11:33:56 +02:00
Jakob Borg
fa9bc08afb gui, man, authors: Update docs, translations, and contributors 2020-08-12 07:45:23 +02:00
Simon Frei
fd8bea6179 lib/osutil: Preserve perms in AtomicWriter (fixes #tbd) (#6885) 2020-08-10 18:48:37 +02:00
Jakob Borg
f2f1a28206 Merge branch 'release' into main
* release:
  lib/fs: Fix WatchRename test for FreeBSD (fixes #6613)
2020-08-07 09:10:50 +02:00
Jakob Borg
89946b21be lib/fs: Fix WatchRename test for FreeBSD (fixes #6613) 2020-08-07 08:09:12 +02:00
Jakob Borg
872fbf6e32 Merge branch 'release' into main
* release:
  lib/fs: Unwrap mtimeFile, get fd the "correct" way (ref #6875) (#6877)
  lib/model: Don't close file early (fixes #6875) (#6876)
2020-08-07 07:50:38 +02:00
Audrius Butkevicius
b2e7ecdbf0 lib/fs: Unwrap mtimeFile, get fd the "correct" way (ref #6875) (#6877) 2020-08-07 07:49:32 +02:00
Audrius Butkevicius
00008994e4 lib/model: Don't close file early (fixes #6875) (#6876) 2020-08-07 07:49:28 +02:00
Audrius Butkevicius
e9bb17307d lib/fs: Unwrap mtimeFile, get fd the "correct" way (ref #6875) (#6877) 2020-08-07 07:47:48 +02:00
Jakob Borg
ff84f075d5 gui, man, authors: Update docs, translations, and contributors 2020-08-05 07:45:24 +02:00
Jakob Borg
5e1f39b6f6 lib/fs: Fix WatchRename test for FreeBSD (fixes #6613) 2020-08-03 23:24:01 +02:00
Audrius Butkevicius
96e197e502 lib/model: Don't close file early (fixes #6875) (#6876) 2020-08-03 21:54:42 +02:00
Simon Frei
bbf25e2d02 lib/db: Log context on panic (#6872) 2020-08-01 17:32:36 +02:00
Simon Frei
5c9df60699 gui: Don't show pull order on SO folders (ref #6807) (#6871) 2020-08-01 11:19:54 +02:00
Simon Frei
a85bc1c3a6 lib/model: Check folder error before sync-waiting (fixes #6793) (#6847) 2020-07-31 19:26:09 +02:00
Simon Frei
850dd4cd25 lib/db: Don't count invalid items to global state (ref #6850) (#6863) 2020-07-30 13:49:14 +02:00
Simon Frei
e46c8ab9ee lib/model: Detect deleted RO items scanning on non-RO (fixes #6864) (#6865) 2020-07-30 13:41:45 +02:00
Jakob Borg
2dc2aa5d21 lib/connections, lib/tlsutil: Handle certName in Go 1.15 (fixes #6867) (#6868)
Our authentication is based on device ID (certificate fingerprint) but
we also check the certificate name for ... historical extra security
reasons. (I don't think this adds anything but it is what it is.) Since
that check breaks in Go 1.15 this change does two things:

- Adds a manual check for the peer certificate CommonName, and if they
  are equal we are happy and don't call the more advanced
  VerifyHostname() function. This allows our old style certificates to
  still pass the check.

- Adds the cert name "syncthing" as a DNS SAN when generating the
  certificate. This is the correct way nowadays and makes VerifyHostname()
  happy in Go 1.15 as well, even without the above patch.
2020-07-30 13:36:11 +02:00
Jakob Borg
d53a2567a4 build: Actually set build tags (#6866)
Apparently our Tags field depended on having specific files react to
tags and add themselves there. This, instead, works for all tags.

Also, pass tags to the test command line.
2020-07-30 10:58:43 +02:00
Jakob Borg
6f4671ed27 lib/connections: Add noquic tag
The QUIC package is notorious for being incompatible with either too
old or too new Go releases. Currently it doesn't build with Go 1.15 RC
and I want to test the rest with Go 1.15. With this I can do `go run
build.go --tags noquic` to do that.
2020-07-30 09:42:02 +02:00
Jakob Borg
b70dbfa0f7 gui, man, authors: Update docs, translations, and contributors 2020-07-29 07:45:25 +02:00
Simon Frei
424d1b1608 lib/db: Commit meta when dropping device (#6862) 2020-07-28 16:46:42 +02:00
Simon Frei
1b9e5c0937 lib/db: Include blocks in db check (ref #6855) (#6861) 2020-07-28 16:25:07 +02:00
Jakob Borg
26b188dc0e Merge branch 'release' into main
* release:
  lib/config: Repair versioning XML serialization (fixes #6859, ref #6693)
2020-07-28 12:09:48 +02:00
Jakob Borg
4faa5882f2 lib/config: Repair versioning XML serialization (fixes #6859, ref #6693) 2020-07-28 12:09:00 +02:00
Jakob Borg
62cff26edf lib/config: Repair versioning XML serialization (fixes #6859, ref #6693) 2020-07-28 12:08:37 +02:00
Simon Frei
932d8c69de lib/fs: Properly handle case insensitive systems (fixes #1787, fixes #2739, fixes #5708)
With this change we emulate a case sensitive filesystem on top of
insensitive filesystems. This means we correctly pick up case-only renames
and throw a case conflict error when there would be multiple files differing
only in case.

This safety check has a small performance hit (about 20% more filesystem
operations when scanning for changes). The new advanced folder option
`caseSensitiveFS` can be used to disable the safety checks, retaining the
previous behavior on systems known to be fully case sensitive.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2020-07-28 11:15:11 +02:00
Simon Frei
21dd9d6b43 build: Replace hypen in -dirty for version (ref #6758) (#6858) 2020-07-28 10:58:01 +02:00
Simon Frei
08e0f938a9 lib/db: Update global meta even if unchanged (fixes #6850) (#6852) 2020-07-24 12:36:16 +02:00
Simon Frei
ebead944b5 lib/fs: Pass infinite recursion error on instead of warning (#6846)
Prompted by https://forum.syncthing.net/t/infinite-filesystem-recursion-detected/15285. In my opinion the filesystem shouldn't throw warnings but pass on errors for the caller to decide what's to be happening with it. Right now in this PR an infinite recursion is a normal scan error, i.e. folder is in failed state and displays failed items, but no warning. I think that's appropriate but if deemed appropriate an additional warning can be thrown in the scanner.
2020-07-22 22:10:24 +02:00
Jakob Borg
d91d77a2b2 gui, man, authors: Update docs, translations, and contributors 2020-07-22 07:45:19 +02:00
Audrius Butkevicius
55147f5901 lib/db: Rework flush hooks (#6838) 2020-07-19 08:55:27 +02:00
Alex Lindeman
851ee51c1b gui: Sharpen device icons (fixes #5579) (#6837)
Add [shape-rendering: crispEdges](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) to `.identicon` class to remove blurry grid lines within device icons
2020-07-16 19:49:48 +02:00
Jakob Borg
29cd156e71 gui, man, authors: Update docs, translations, and contributors 2020-07-15 07:46:14 +02:00
Jakob Borg
aaecf813e2 gui: Add GUI control for versioning cleanup interval (ref #6693) (#6834) 2020-07-14 17:35:09 +02:00
HansK-p
cd8e1ec738 docker: Support starting as a non-root user (fixes #6832) (#6835) 2020-07-14 11:38:59 +02:00
Jakob Borg
aedc2d788f lib/model, lib/versioner: Drive version cleanup from scanner (fixes #6313) (#6693)
This change adds a separate config for the cleanup interval, and runs that cleanup from the main folder loop.
2020-07-14 10:48:50 +02:00
dependabot-preview[bot]
245b4b98c4 build(deps): bump github.com/greatroar/blobloom from 0.2.1 to 0.3.0 (#6830)
Bumps [github.com/greatroar/blobloom](https://github.com/greatroar/blobloom) from 0.2.1 to 0.3.0.
- [Release notes](https://github.com/greatroar/blobloom/releases)
- [Commits](https://github.com/greatroar/blobloom/compare/v0.2.1...v0.3.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-07-14 08:40:46 +02:00
dependabot-preview[bot]
74ee83cc86 build(deps): bump github.com/lucas-clemente/quic-go (#6829)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.17.2 to 0.17.3.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.17.2...v0.17.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-07-14 08:29:20 +02:00
Simon Frei
16f4921c50 lib/nat: Make sure nat keeps being disabled (fixes #6823) (#6824) 2020-07-14 08:16:08 +02:00
Jakob Borg
91922b6dc8 Merge branch 'release' into main
* release:
  lib/scanner: Less strict validation (fixes #6827) (#6828)
2020-07-14 08:05:30 +02:00
Jakob Borg
d57694dc04 lib/scanner: Less strict validation (fixes #6827) (#6828)
This fixes the change in #6674 where the weak hash became a deciding
factor. Now we again just use it to accept a block, but don't take a
negative as meaning the block is bad.
2020-07-11 20:17:41 +02:00
Jakob Borg
fc1dac5196 lib/scanner: Less strict validation (fixes #6827) (#6828)
This fixes the change in #6674 where the weak hash became a deciding
factor. Now we again just use it to accept a block, but don't take a
negative as meaning the block is bad.
2020-07-11 14:48:45 +02:00
greatroar
9f92f8c609 lib/db: Use SipHash to deal with hash collision in GC (#6826)
If the GC finds a key k that it wants to keep, it records that in a
Bloom filter. If a key k' can be removed but its hash collides with k,
it will be kept. Since the old Bloom filter code was completely
deterministic, the next run would encounter the same collision, assuming
k must still be kept.

A randomized hash function that uses all the SHA-256 bits solves this
problem: the second run has a non-zero probability of removing k', as
long as the Bloom filter is not completely full.
2020-07-11 09:36:09 +02:00
Jakob Borg
bbda58a29f lib/db: Add test for GC run 2020-07-11 09:22:15 +02:00
Simon Frei
3d339cc8d3 gui: Improve advanced tab in folder edit modal (#6822) 2020-07-09 14:28:45 +01:00
Jack Croft
8cbdf1e1de gui: Disable file pull order when for send-only (fixes #6807) #6821 2020-07-09 11:57:04 +02:00
Jakob Borg
ff7873fcc1 gui, man, authors: Update docs, translations, and contributors 2020-07-08 07:45:21 +02:00
Simon Frei
8d67235a75 lib/config: Don't cache device map (fixes #6816) (#6817) 2020-07-07 23:44:49 +02:00
dependabot-preview[bot]
493de9392a build(deps): bump github.com/lucas-clemente/quic-go (#6813)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.17.1 to 0.17.2.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.17.1...v0.17.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-07-06 12:18:10 +01:00
Jakob Borg
0c61c66511 lib/api, lib/model: Improve folder completion API (fixes #6075) (#6808) 2020-07-03 08:48:37 +02:00
Jakob Borg
baf21a8fa2 gui, man, authors: Update docs, translations, and contributors 2020-07-01 07:45:21 +02:00
Simon Frei
ebbe1abe28 lib/protocol: Include WeakHash in BlocksHash (#6799) 2020-06-29 09:33:07 +02:00
Audrius Butkevicius
9d4a700829 lib/ur: Track new folder feature usage (#6803) 2020-06-28 20:35:22 +02:00
Simon Frei
d7fc7008af lib/protocol: Add BlocksHash to FileInfo string (#6802) 2020-06-27 07:44:33 +02:00
Simon Frei
9c45ac381c lib/model: Consider weak hash on recheckFile (#6797) 2020-06-26 16:47:03 +02:00
Jakob Borg
e0c8865a45 build: Consistently use 8 hash digits in git describe
This might otherwise differ between builds depending on branches present
in the repository and the Git version in use (?).
2020-06-26 09:02:35 +02:00
Simon Frei
4f06708330 lib/api, lib/model: Fixes around event request tracking (#6774) 2020-06-25 21:48:48 +02:00
Simon Frei
80ada1bb6c lib/protocol: Don't warn when dropping deleted invalid item (fixes #6795) (#6796) 2020-06-25 20:24:31 +02:00
Simon Frei
0648fb0626 lib/model: Don't force rescan already changed items (#6798) 2020-06-25 20:23:59 +02:00
Simon Frei
90e248615f lib/scanner: Test weak hash consistency (ref #5556) (#6794)
Relevant much earlier changes:
  9b1c592fb7
  bd1c29ee32

Make sure vanilla and rolling adler are consistent. And that they match
with scanner.Validate.
2020-06-25 14:47:35 +02:00
Jakob Borg
57f47bcf83 gui, man, authors: Update docs, translations, and contributors 2020-06-24 07:45:25 +02:00
Audrius Butkevicius
bb76311ec6 lib/ur: Zero our the value before unmarshal (#6790)
* lib/ur: Zero our the value before unmarshal

* Comment

* Complete rewrite
2020-06-23 21:23:32 +01:00
Jakob Borg
78d294f78c cmd/ursrv: Skip the duplicate complaints with new index name 2020-06-23 14:18:52 +02:00
Audrius Butkevicius
689cf2a5ee lib/ur: Normalise contract between syncthing and ursrv (#6770)
* Fix ui, hide report date

* Undo Goland madness

* UR now web scale

* Fix migration

* Fix marshaling, force tick on start

* Fix tests

* Darwin build

* Split "all" build target, add package name as a tag

* Remove pq and sql dep from syncthing, split build targets

* Empty line

* Revert "Empty line"

This reverts commit f74af2b067.

* Revert "Remove pq and sql dep from syncthing, split build targets"

This reverts commit 8fc295ad00.

* Revert "Split "all" build target, add package name as a tag"

This reverts commit f4dc889951.

* Normalise contract types

* Fix build add more logging
2020-06-23 09:47:15 +01:00
Simon Mwepu
72f954dcab lib/versioner: Create versioning directory recursively (fixes #6565) (#6678)
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2020-06-23 08:37:29 +02:00
dependabot-preview[bot]
adace320a0 build(deps): bump github.com/go-ldap/ldap/v3 from 3.1.10 to 3.2.0 (#6783)
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.1.10 to 3.2.0.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.1.10...v3.2.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-23 07:34:51 +02:00
dependabot-preview[bot]
96d3117759 build(deps): bump golang.org/x/text from 0.3.2 to 0.3.3 (#6782)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.2 to 0.3.3.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.2...v0.3.3)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-23 07:34:22 +02:00
Simon Frei
85794933d3 lib/model: Remove double error handling in performFinish (#6780) 2020-06-23 07:30:16 +02:00
Simon Frei
4881a6336f lib/db: Correct need accounting on reset (fixes #6784) (#6785) 2020-06-23 07:29:27 +02:00
Audrius Butkevicius
5fb3992275 lib/model: More connection closing (#6778)
* lib/model: More connection closing

* Revert "lib/model: More connection closing"

This reverts commit 5397c3a55c.

* Add tests, fix one broken-ness

* Update lib/model/model.go

Co-authored-by: Simon Frei <freisim93@gmail.com>

* Update model.go

* Update model.go

Co-authored-by: Simon Frei <freisim93@gmail.com>
2020-06-22 21:26:26 +01:00
Jakob Borg
b62b7d269e lib/connections: Correctly fixup port in IPv6 listen URLs (#6786)
Previously tcp://[fe80::1] would get "fixed" to tcp://[[fe80::1]]:22000
which is not great.
2020-06-22 16:47:15 +01:00
Audrius Butkevicius
cbaef624cf lib/nat: Make service termination faster (#6777)
* lib/nat: Make service termination faster

* Newline
2020-06-22 09:01:57 +01:00
Jakob Borg
aee4b10d3a gui, man, authors: Update docs, translations, and contributors 2020-06-22 06:15:24 +02:00
greatroar
dc145bfad7 lib/protocol: Use sha256.Sum256 in NewDeviceID (#6775)
This is shorter, skips two allocations, makes the function inlineable
and is safer, since the compiler now check whether
DeviceIDLength == sha256.Size.
2020-06-21 20:38:06 +02:00
greatroar
d985aa9e4b lib/scanner: Fix Validate docs (#6776)
Co-authored-by: greatroar <@>
2020-06-21 19:23:06 +01:00
Simon Frei
3d75819cdb build: Set CGO_ENABLED=0 by default, except on specific platforms (#6768) 2020-06-21 17:32:55 +02:00
Jakob Borg
705710b1a1 gui, lib/api: Add more version info to about dialog (#6773) 2020-06-21 12:20:19 +02:00
Simon Frei
f66e57947b lib/model: Use right db snap when scanning recvonly folder (#6769) 2020-06-21 09:28:29 +02:00
Jakob Borg
3fcf22ed5d build: Change version strings to not have plus in them (ref #6758) (#6760)
Currently a random dev version has a version string like this:

	v1.7.0-rc.1+23-gef3441bd6

That is, the tag name followed by a plus sign and the git describe
metadata (number of commits and hash) plus -dirty or -branchname in some
cases.

We introduced the plus sign in #473, where a dev version would
previously be called v0.9.0-42-gwhatever which is considered older than
v0.9.0 and hence caused a downgrade. The problem with the plus is that
per semver everything after the plus is ignored as build metadata, which
means we won't upgrade from v1.7.0-rc.1 to v1.7.0-rc.1+22-g946170f3f.

With this change the we instead either just add a dev suffix (if we're
already on a prerelease version) or we wind the patch version and add a
dev suffix.

	v1.7.0-rc.1+23-gef3441bd6 => v1.7.0-rc.1.dev.23.gef3441bd6
	v1.6.1+80-gef3441bd6      => v1.6.2-dev.80.gef3441bd6

This should preserve the ordering and keep versions semver-ish.
2020-06-20 08:42:06 +02:00
Simon Frei
2716898cb9 lib/model: Don't ignore stat failure in performFinish (#6766) 2020-06-19 23:47:29 +02:00
Audrius Butkevicius
deaccc7f8d lib/fs: Add support for Windows duplicate extents (#6764) 2020-06-18 22:32:26 +01:00
Simon Frei
22f0077262 lib/model: Don't stay scanning forever on fail (#6761) 2020-06-18 14:13:46 +01:00
Jakob Borg
946170f3fc gui, lib/ignore: Handle editing ignores with error (fixes #5425) (#6757)
This changes the error handling in loading ignores slightly:

- There is a new ParseError type that is returned as the error
  (somewhere in the chain) when the problem was not an I/O error loading
  the file, but some issue with the contents.

- If the file was read successfully but not parsed successfully we still
  return the lines read (in addition to nil patterns and a ParseError).

- In the API, if the error IsParseError then we return a successful
  HTTP response with the lines and the actual error included in the JSON
  object.

- In the GUI, as long as the HTTP call to load the ignores was
  successful we can edit the ignores. If there was an error we show this
  as a validation error on the dialog.

Also some cleanup on the Javascript side as it for some reason used
jQuery instead of Angular for this editor...
2020-06-18 11:04:00 +02:00
Simon Frei
8cf9d91ed4 lib: Print nicely rounded durations (#6756) 2020-06-18 10:55:41 +02:00
Audrius Butkevicius
4812fd3ec1 all: Add copy-on-write filesystem support (fixes #4271) (#6746) 2020-06-18 08:15:47 +02:00
greatroar
273cc9cef8 lib/rand: Various minor fixes (#6752)
crypto/rand output is cryptographically secure by the Go library
documentation's promise. That, rather than strength (= passes randomness
tests) is the property that Syncthing needs).
2020-06-17 10:43:58 +02:00
Simon Frei
cbe0d2fffc lib/db: Improve error message on meta inconsistency (#6751) 2020-06-17 10:03:39 +02:00
Jakob Borg
a218a69530 lib/db: Use explicit byte type for type prefixes (#6754)
This makes Go 1.15 test/vet happy, avoiding "conversion from untyped int
to string yields a string of one rune" warning where we do
string(KeyTypeWhatever) in namespaced.go.

It also clarifies and enforces the currently allowed range of these
numbers so I think it's fine.
2020-06-17 09:37:07 +02:00
Jakob Borg
3be9f68b51 gui, man, authors: Update docs, translations, and contributors 2020-06-17 07:45:21 +02:00
Simon Frei
6976219d6d lib/model: Check dir before deletion when pulling (#6741) 2020-06-16 15:20:08 +02:00
Simon Frei
dbacef35c4 build: Update integration tests and add to build.go (#6744) 2020-06-16 14:33:17 +02:00
Audrius Butkevicius
f310bbaaac cmd/stdiscosrv: Don't abuse wrong header (#6749) 2020-06-16 10:58:25 +02:00
greatroar
df83b84aa1 all: Make all error implementations pointer types (#6726)
This matches the convention of the stdlib and avoids ambiguity: when
customErr{} and &customErr{} both implement error, client code needs to
check for both.

Memory use should remain the same, since storing a non-pointer type in
an interface value still copies the value to the heap.
2020-06-16 09:27:34 +02:00
Simon Frei
a47546a1f1 lib/scanner, lib/model: Improve error handling when scanning (#6736) 2020-06-16 09:25:41 +02:00
Audrius Butkevicius
f619a7f4cc lib/connections: Try TCP punchthrough (fixes #4259) (#5753) 2020-06-16 09:17:07 +02:00
dependabot-preview[bot]
d09c8f0d0a build(deps): bump github.com/lucas-clemente/quic-go (#6742)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.16.1 to 0.17.1.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.16.1...v0.17.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-16 08:36:31 +02:00
Jakob Borg
ec718e729e various: Master is now main
Also cleans out various old strings from the translation strings.
2020-06-16 07:08:09 +02:00
Jakob Borg
5be13f62a2 lib/model: Fix minor flakiness in TestModTimeWindow 2020-06-16 06:32:37 +02:00
Audrius Butkevicius
36e6f8b082 cmd/ursrv: Attempt to fix js failure to load (#6747)
Following what was said in:

https://support.google.com/maps/thread/44057943?hl=en
2020-06-15 22:08:56 +01:00
Simon Frei
fdf5a5c0d7 lib/osutil: Use filepath.Join in tests (#6740) 2020-06-14 19:09:37 +01:00
Gleb Sinyavskiy
091cb5e611 cmd/strelaysrv: Fix JSON unmarshalling when joining a relay pool (fixes #6733) (#6729) 2020-06-10 11:26:09 +02:00
Jakob Borg
b6b6caeab5 gui, man, authors: Update docs, translations, and contributors 2020-06-10 07:45:27 +02:00
dependabot-preview[bot]
53af64a2a4 build(deps): bump github.com/lucas-clemente/quic-go (#6722)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.16.0 to 0.16.1.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.16.0...v0.16.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-09 08:43:34 +02:00
greatroar
b6a84ecb0c lib/db: Remove unused keyer methods (#6723)
Co-authored-by: greatroar <@>
2020-06-08 19:19:18 +01:00
Jakob Borg
5f40879a75 gui: Fix auto dismissing auth notification (ref #6536) 2020-06-08 08:29:55 +02:00
Simon Frei
0b65a616ba lib/scanner: Save one stat call per file (#6715) 2020-06-08 08:14:50 +02:00
Simon Frei
6b4fe5c063 gui: Ignore permissions isn't just about FAT (#6713)
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2020-06-08 08:12:06 +02:00
Simon Frei
3065b127b5 lib/connections, lib/nat: Correctly dis-/enable nat (fixes #6552) (#6719) 2020-06-07 20:29:53 +02:00
Simon Frei
74ea9c5f67 gui: Fix string and update translations (ref #6536) (#6716) 2020-06-07 10:46:06 +02:00
André Colomb
46536509d7 lib/protocol: Avoid panic in DeviceIDFromBytes (#6714) 2020-06-07 10:31:12 +02:00
Jakob Borg
607bcc0b0e build: Fix rebuild of strelaypoolsrv assets 2020-06-06 08:43:56 +02:00
Jakob Borg
1950efb790 cmd/strelaysrv: Add note about relay operators 2020-06-06 08:35:01 +02:00
Jakob Borg
1b77ab2b52 cmd/stcrashreceiver: Pick up extra build tags and send to Sentry (#6710)
This extracts the extra tags from any `[foo]` stuff at the end of the
version and sends them to Sentry for indexing.

If I need to modify that regexp again I'll probably write a from scratch
tokenizer and parser for our version string instead...
2020-06-03 15:00:46 +02:00
Jakob Borg
4f367e4376 lib/build: Add some env vars as synthetic build tags (#6709)
This adds some env vars to the long version string as if they were build
tags. The purpose is to better understand what code was running or not
in the version output, usage reporting and crash reports. In order to
prevent possible privacy issues the actual value of the variable is not
reported, just the fact that it was set to something non-empty.

Example:

	% ./bin/syncthing --version
	syncthing v1.6.1+47-g1eb104f3-buildtags "Fermium Flea" (go1.14.3 darwin-amd64) jb@kvin.kastelo.net 2020-06-03 07:25:46 UTC [stnoupgrade, use_badger]
2020-06-03 15:00:28 +02:00
dependabot-preview[bot]
98418c9b5c build(deps): bump github.com/lucas-clemente/quic-go (#6695)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.15.7 to 0.16.0.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.15.7...v0.16.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-03 10:03:08 +02:00
Jakob Borg
3e4a90a2ba gui, man, authors: Update docs, translations, and contributors 2020-06-03 07:45:41 +02:00
Simon Frei
fac4dec840 lib/db: New VersionList migration fixes (ref #6638) (#6705) 2020-06-02 23:05:41 +02:00
Simon Frei
79bf1f1056 gui: Preserve folder-device info on folder edit (fixes #6706) (#6707) 2020-06-02 23:05:19 +02:00
Jonathan
9ef17322be lib/config: Add missing quic address in case of non-default port (fixes #6679) (#6703)
* Add quic listener on instance of port blockage

* Update lib/config/config.go

Co-authored-by: Audrius Butkevicius <audrius.butkevicius@gmail.com>
2020-06-02 15:06:02 +01:00
Jakob Borg
c80e0bfc28 Merge branch 'release'
* release:
  cmd/syncthing: Correct auto upgrade criteria (fixes #6701) (#6702)
2020-06-02 12:09:14 +02:00
Jędrzej Kula
28d5c84599 gui, lib/config: Add GUI user and password notification (fixes #4703) (#6536) 2020-06-02 12:08:22 +02:00
Jakob Borg
d7c3d81dfb cmd/syncthing: Correct auto upgrade criteria (fixes #6701) (#6702) 2020-06-02 11:49:22 +02:00
Jakob Borg
b033c36b31 build: Add "changelog" command (#6700) 2020-06-02 11:40:45 +02:00
Jakob Borg
bfc9478965 cmd/syncthing: Correct auto upgrade criteria (fixes #6701) (#6702) 2020-06-02 11:38:39 +02:00
Jakob Borg
d9cb7e2739 lib/connections: Skip and warn on malformed URLs (fixes #6697) (#6699) 2020-06-02 11:19:51 +02:00
Simon Frei
1f8e6c55f6 lib/db: Refactor to use global list by version (fixes #6372) (#6638)
Group the global list of files by version, instead of having one flat list for all devices. This removes lots of duplicate protocol.Vectors.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2020-05-30 09:50:23 +02:00
Jakob Borg
1eea076f5c cmd/stindex: Detect and open Badger databases 2020-05-30 09:47:11 +02:00
Jakob Borg
94beed5c10 lib/db: Add Badger backend (fixes #5910) (#6250) 2020-05-29 13:43:02 +02:00
Simon Frei
ed6bfc5417 lib/model: Don't increase pull pause on triggered pull (#6690) 2020-05-29 09:52:28 +02:00
Jakob Borg
04ff890263 build: Clean up build.sh, add build.ps1 (#6689) 2020-05-28 12:42:15 +02:00
greatroar
9c0825c0d9 lib/scanner: Simplify, optimize and document Validate (#6674) (#6688) 2020-05-27 22:23:12 +02:00
Jakob Borg
f78133b8e9 lib/db: Adjust transaction flush sizes downwards (#6686)
This reduces the size of our write batches before we flush them. This
has two effects: reducing the amount of data lost if we crash when
updating the database, and reducing the amount of memory used when we do
large updates without checkpoint (e.g., deleting a folder).

I ran our SyncManyFiles benchmark as it is the one doing most
transactions, however there was no relevant change in any metric (it's
limited by our fsync I expect). This is good as any visible change would
just be a decrease in performance.

I don't have a benchmark on deleting a large folder, taking that part on
trust for now...
2020-05-27 12:15:00 +02:00
Simon Frei
b784f5b9e3 lib/config, lib/model: Commit auto-accepted folders all at once (#6684) 2020-05-27 08:05:26 +02:00
Jakob Borg
1c089a4d11 gui, man, authors: Update docs, translations, and contributors 2020-05-27 07:45:24 +02:00
greatroar
baa38eea7a lib/assets: Allow assets to remain uncompressed (#6661) 2020-05-25 08:51:27 +02:00
Simon Frei
c3b5eba205 lib/model: Fix checking children when trying to delete a dir (fixes #6646) (#6647) 2020-05-25 08:46:24 +02:00
Simon Frei
cf75329067 lib/model: Handle concurrently removed device in ClusterConfig (#6666) 2020-05-20 11:13:55 +02:00
Jakob Borg
8343db6766 Merge branch 'release'
* release:
  lib/db: Initialize need meta on first dev occurrence (fixes #6668) (#6669)
  lib/db: Don't panic on seq. coruption when debugging (#6662)
2020-05-20 11:05:53 +02:00
Simon Frei
8c74177699 lib/db: Initialize need meta on first dev occurrence (fixes #6668) (#6669) 2020-05-20 11:04:45 +02:00
Simon Frei
9a5f7fbadf lib/db: Don't panic on seq. coruption when debugging (#6662) 2020-05-20 11:04:38 +02:00
Simon Frei
8f344d0915 lib/db: Initialize need meta on first dev occurrence (fixes #6668) (#6669) 2020-05-20 11:01:27 +02:00
Jakob Borg
77dd874383 gui, man, authors: Update docs, translations, and contributors 2020-05-20 07:45:28 +02:00
Simon Frei
5b34c31cb3 lib/db: Don't panic on seq. coruption when debugging (#6662) 2020-05-18 10:42:51 +02:00
André Colomb
668979605b cmd/stindex: Add missing KeyType values in stindex dump code (#6659)
* cmd/stindex: Unify access to key from cached variable.

Avoid calling the Key() method from the iterator each time the value
is needed.  Just reuse the cache variable already assigned before the
switch block.

* cmd/stindex: Display the prefix byte value for unknown key types.

Make it easier to diagnose corrupt / unknown key type entries by
showing their decimal value, correlating with the definitions in
keyer.go.

* cmd/stindex: Add missing KeyType values in stindex dump code.

Recently added DB key prefixes KeyTypeBlockListMap and KeyTypeVersion
were unknown to the stindex dumping tool.  Add basic parsing to dump
their key structure.
2020-05-17 11:06:14 +02:00
Jakob Borg
5ffa012410 lib/model: Don't crash when taking rename shortcut (fixes #6654) (#6657)
If we fail to take the rename shortcut we may crash on a later loop,
because we do trickiness with the indexes but the original buckets[key]
in "range buckets[key]" isn't re-evaluated so i exceeds the max index.
2020-05-17 08:48:35 +01:00
Jakob Borg
5c54d879a1 cmd/syncthing: Don't crash when failing to create default config (fixes #6655) (#6658)
This is not an ignorable error, because it can happen if we fail to
allocate a free port for the GUI or sync port on first startup.
2020-05-17 07:56:24 +02:00
Jakob Borg
1c5af3a4bd Merge branch 'release'
* release:
  lib/model: Partial revert of rename fix (fixes #6653) (#6656)
2020-05-16 23:08:43 +02:00
Jakob Borg
22c222bf75 lib/model: Partial revert of rename fix (fixes #6653) (#6656)
We can't just drop the snap because it's in use elsewhere. This should
be equally functional.
2020-05-16 23:06:25 +02:00
Jakob Borg
651ee2ce74 lib/model: Partial revert of rename fix (fixes #6653) (#6656)
We can't just drop the snap because it's in use elsewhere. This should
be equally functional.
2020-05-16 23:05:33 +02:00
Jakob Borg
5c9dc4c883 Merge branch 'release'
* release:
  lib/model: Fix rename handling (ref #6650) (#6652)
  lib/db: Filter repeat files in one update (ref #6650) (#6651)
2020-05-16 14:42:11 +02:00
Audrius Butkevicius
258341f8bf lib/model: Fix rename handling (ref #6650) (#6652) 2020-05-16 14:40:20 +02:00
Simon Frei
f5ca213682 lib/db: Filter repeat files in one update (ref #6650) (#6651) 2020-05-16 14:40:20 +02:00
Audrius Butkevicius
a1c5b44c74 lib/model: Fix rename handling (ref #6650) (#6652) 2020-05-16 14:39:27 +02:00
Simon Frei
de9489585f lib/db: Filter repeat files in one update (ref #6650) (#6651) 2020-05-16 14:34:53 +02:00
Jakob Borg
438f687591 docker: Add tzdata for local time log entries 2020-05-16 11:34:46 +02:00
Shaarad Dalvi
7a8cc5fc99 docker: Improved health check for host networks (#6649) 2020-05-15 12:59:22 +02:00
xarx00
f05ccd775a lib/fs: Set execute bits on junctions converted to dirs (ref #6606) (#6645) 2020-05-14 08:09:58 +02:00
Simon Frei
e5cc55ce09 lib/model: Close conns when devices are removed (fixes #6564) (#6641) 2020-05-14 07:50:53 +02:00
Simon Frei
299b9d8883 lib/model: Adjust remote-rename-test to timer-based versions (fixes #6625) (#6644) 2020-05-14 00:31:05 +02:00
Simon Frei
074097a8e7 lib/fs: Prevent race-detector triggering in tests (fixes #6608) (#6642) 2020-05-14 00:30:09 +02:00
xarx00
ee445e35a0 lib/fs: Treat Windows junctions as normal directories (#6606)
Fixes #1830, presumably.
2020-05-13 21:46:24 +02:00
Jakob Borg
3ad049184e Merge branch 'release'
* release:
  lib/db: Dont add symlinks to blocks map (fixes #6637) (#6639)
2020-05-13 20:48:34 +02:00
Simon Frei
6768daec07 lib/db: Dont add symlinks to blocks map (fixes #6637) (#6639) 2020-05-13 20:47:05 +02:00
Simon Frei
974551375e lib/db: Dont add symlinks to blocks map (fixes #6637) (#6639) 2020-05-13 20:38:21 +02:00
Jakob Borg
531ceb2b0f Add indirection for large version vectors. (#6376)
This adds indirection of large version vectors in the same manner as we
already to block lists. The effect is the same: less duplicated data in
some situations.

To mitigate the impact for when this indirection
wouldn't be needed I've added an indirection cutoff for both blocks and
the new version vector stuff: we don't do the indirection at all for
small block lists or small version vectors, instead storing it directly
like we used to do. This is faster for small files and small setups.
2020-05-13 14:28:42 +02:00
Simon Frei
ba4462a70b lib/db: Fix updating/removing from global (ref #6413) (#6635) 2020-05-13 12:56:49 +02:00
Jakob Borg
8419c05794 gui, man, authors: Update docs, translations, and contributors 2020-05-13 07:45:31 +02:00
NinoM4ster
c84f60f949 etc: Add RestartSec=5 to linux-systemd units
Might help avoiding the 'Start request repeated too quickly.' error.

Fixes #6633, fixes #6634
2020-05-12 10:02:32 +02:00
Audrius Butkevicius
6201eebc98 lib/model: Add support for different puller block ordering (#6587)
* WIP

* Tests

* Header and format

* WIP

* Fix tests

* Goland you disappoint me

* Remove CC storage

* Update blockpullreorderer.go
2020-05-11 22:44:04 +01:00
Audrius Butkevicius
decb967969 all: Reorder sequences for better rename detection (#6574) 2020-05-11 20:15:11 +02:00
Jakob Borg
aac3750298 build: Enable hardened runtime in Mac codesigning
syncthing/syncthing-macos#111
2020-05-11 18:19:39 +02:00
Simon Frei
a94951becd lib/db, lib/model: Keep need stats in metadata (ref #5899) (#6413) 2020-05-11 15:07:06 +02:00
Audrius Butkevicius
7dc290c3ed lib/connections: React to listeners going up and down faster (#6590) 2020-05-11 15:02:22 +02:00
Jakob Borg
50faa8f7ef build: Check new assets location for rebuild 2020-05-11 12:20:21 +02:00
Simon Frei
5c87ceb392 build: Update .gitignores for new asset locs (ref #6624) (#6631) 2020-05-11 11:04:47 +01:00
dependabot-preview[bot]
6ffc8255b6 build(deps): bump github.com/lucas-clemente/quic-go (#6630)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.15.6 to 0.15.7.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.15.6...v0.15.7)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-11 11:04:23 +01:00
dependabot-preview[bot]
3354e60461 build(deps): bump github.com/go-ldap/ldap/v3 from 3.1.7 to 3.1.10 (#6629)
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.1.7 to 3.1.10.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.1.7...v3.1.10)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-11 10:14:31 +01:00
greatroar
06365e5635 cmd/strelaypoolsrv, lib/api: Factor out static asset serving (#6624) 2020-05-10 11:44:34 +02:00
Audrius Butkevicius
da99203dcd lib/db: Fix non-truncated fileinfo loading (#6621) 2020-05-08 20:31:43 +01:00
Simon Frei
57ea8a1bf5 lib/model: Prevent panic on test failure (ref #6618) (#6620) 2020-05-08 17:56:49 +02:00
Jakob Borg
f72832d591 build: go.mod tidy 2020-05-08 16:50:17 +02:00
Jakob Borg
c0c18a568c lib/db: Hold the bloom filter the right way (fixes #6614) (#6617) 2020-05-08 14:18:00 +02:00
Shaarad Dalvi
b0b3abf76b docker: Remove health check (fixes #6604) (#6616)
Co-authored-by: Shaarad Dalvi <shdalv@microsoft.com>
2020-05-08 12:03:37 +02:00
Jakob Borg
c20ed80dc4 github: Update issue templates (#6610)
* github: Update issue templates

* wip

* wip
2020-05-07 12:23:00 +01:00
greatroar
e2febf246e all: Store assets as strings (#6611)
Storing assets as []byte requires every compiled-in asset to be copied
into writable memory at program startup. That currently takes up 1.6MB
per syncthing process. Strings stay in the RODATA section and should be
shared between processes running the same binary.
2020-05-07 11:47:23 +02:00
Simon Frei
2cdeb1bf70 lib/model: Spurious tmp file (ref #6607) (#6609) 2020-05-07 08:49:59 +02:00
Jakob Borg
876609a0f0 lib/model: Fix test after version vector changes (#6607) 2020-05-06 21:19:33 +02:00
Jakob Borg
744ef0d8ac lib/protocol: Avoid data loss on database wipe by higher version numbers (fixes #3876) (#6605)
This makes version vector values clock based instead of just incremented
from zero. The effect is that a vector that is created from scratch
(after database reset) will have a higher value for the local device
than what it could have been previously, causing a conflict. That is, if
we are A and we had

    {A: 42, B: 12}

in the old scheme, a reset and rescan would give us

    {A: 1}

which is a strict ancestor of the older file (this might be wrong). With
the new scheme we would instead have

    {A: someClockTime, b: otherClockTime}

and the new version after reset would become

    {A: someClockTime+delta}

which is in conflict with the previous entry (better).
In case the clocks are wrong (current time is less than the value in the
vector) we fall back to just simple increment like today.

This scheme is ineffective if we suffer a database reset while at the
same time setting the clock back far into the past. It's however no
worse than what we already do.

This loses the ability to emit the "added" event, as we can't look for
the magic 1 entry any more. That event was however already broken
(#5541).

Another place where we infer meaning from the vector itself is in
receive only folders, but there the only criteria is that the vector is
one item long and includes just ourselves, which remains the case with
this change.

* wip
2020-05-06 08:47:02 +02:00
dependabot-preview[bot]
8d6fb86ee0 build(deps): bump github.com/greatroar/blobloom from 0.2.0 to 0.2.1 (#6600)
Bumps [github.com/greatroar/blobloom](https://github.com/greatroar/blobloom) from 0.2.0 to 0.2.1.
- [Release notes](https://github.com/greatroar/blobloom/releases)
- [Commits](https://github.com/greatroar/blobloom/compare/v0.2.0...v0.2.1)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-06 08:35:37 +02:00
dependabot-preview[bot]
13c3dac89c build(deps): bump github.com/lucas-clemente/quic-go (#6599)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.15.5 to 0.15.6.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.15.5...v0.15.6)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-06 08:35:20 +02:00
Simon Frei
b5fc332782 lib/model: Merge add and start folder funcs and related refactor (#6594) 2020-05-06 08:34:54 +02:00
Jakob Borg
4a8a8b294d gui, man, authors: Update docs, translations, and contributors 2020-05-06 07:46:12 +02:00
Jakob Borg
92905d30e8 docker: Accept Go version as --build-arg 2020-05-04 12:45:36 +02:00
Simon Frei
914eb77ca4 lib/model: Don't include iolimiter wait into sync duration (#6593) 2020-05-04 08:43:35 +02:00
Tomasz Wilczyński
f560e8c850 gui: Prevent text overflow in file lists (fixes #6268) (#6292) 2020-05-02 19:34:28 +02:00
Simon Frei
2e3975e956 lib/model: Improve errors when deleting dirs (fixes #6575) (#6586) 2020-05-01 11:11:38 +02:00
Audrius Butkevicius
bd0c2bf237 lib/model: Do file recheck in folder loop (fixes #6583) (#6585) 2020-05-01 11:08:59 +02:00
Audrius Butkevicius
f86deedd9c lib/model: Progress emitter network operations dont need to be blocking (#6589)
* lib/model: Progress emitter network operations dont need to be blocking

* Do sends outside of the lock
2020-05-01 08:54:15 +01:00
Audrius Butkevicius
782bd08aad lib/model: Add option to disable fsync (#6588)
* lib/model: Add option to disable fsync

* Fix test

* Dont open stuff for no reason
2020-05-01 08:36:46 +01:00
Simon Frei
22242d51be lib/db: Refactor getting global lists (#6529)
* lib/db: Refactor getting global lists

* VL -> Versions

* keyBuf

* don't touch db migration
2020-05-01 08:30:20 +01:00
Audrius Butkevicius
ac7338f1f2 lib/connections: Update quic (#6591)
* lib/connections: Update quic

* Fix freebsd builds?

* Undo x/sys and gopsutil update

* Update quic_dial.go

* Update quic_listen.go
2020-05-01 08:14:28 +01:00
Jakob Borg
bdb25f9ba5 gui, man, authors: Update docs, translations, and contributors 2020-04-29 07:45:31 +02:00
Jakob Borg
0e2a07d71a lib/fs: Avoid dirty offset read in fakefs (fixes #6584) 2020-04-28 09:58:31 +02:00
dependabot-preview[bot]
5e1cd0e71a build(deps): bump github.com/greatroar/blobloom from 0.1.1 to 0.2.0 (#6580)
Bumps [github.com/greatroar/blobloom](https://github.com/greatroar/blobloom) from 0.1.1 to 0.2.0.
- [Release notes](https://github.com/greatroar/blobloom/releases)
- [Commits](https://github.com/greatroar/blobloom/compare/v0.1.1...v0.2.0)
2020-04-27 14:38:20 +02:00
MikolajTwarog
5224f07ac8 gui: Add "Pause All"/"Resume All" button for devices (fixes #6530) (#6549) 2020-04-27 00:18:05 +02:00
Jakob Borg
d9664a946d gui: Allow rescan on local additions (fixes #6578) (#6579) 2020-04-27 00:13:53 +02:00
Jakob Borg
8c61e0d6ab lib/config: Sort versioning options on marshal (fixes #6576) (#6577) 2020-04-27 00:13:35 +02:00
Jakob Borg
6c73617974 lib/model: Use semaphore to limit concurrent folder writes (fixes #6541) (#6573) 2020-04-27 00:13:18 +02:00
Jakob Borg
037934ec74 Merge branch 'release'
* release:
  gui: Fix regression on refreshNeed (fixes #6560, ref #6452) (#6561)
2020-04-22 20:41:03 +02:00
Jakob Borg
78a741d0be gui, man, authors: Update docs, translations, and contributors 2020-04-22 07:45:34 +02:00
Simon Frei
ebad9e2073 gui: Fix regression on refreshNeed (fixes #6560, ref #6452) (#6561) 2020-04-21 22:45:03 +02:00
Simon Frei
d68fa84055 gui: Fix regression on refreshNeed (fixes #6560, ref #6452) (#6561) 2020-04-21 22:42:59 +02:00
Simon Frei
d3ed4de4ed lib/model: Don't exit pullerRoutine on cancelled ctx (fixes #6559) (#6562)
* lib/model: Don't exit pullerRoutine on cancelled ctx (fixes #6559)

* actual fix
2020-04-21 18:55:14 +01:00
Simon Frei
6bbd24de12 lib/model: Refactor folder health/error handling (fixes #6557) (#6558) 2020-04-21 10:15:59 +02:00
Boqin Qin
c63ca4f563 lib/protocol, rc, utils: Add mutex Unlock before panic (#6556) 2020-04-20 14:52:16 +02:00
greatroar
0e5ba3ca05 lib/db: Upgrade to Blobloom v0.1.1 (#6553)
Now faster and Apache-licensed.
2020-04-20 14:23:36 +02:00
greatroar
44b0f0b456 lib/db: Switch to faster blobloom Bloom filter pkg (#6537) 2020-04-20 09:02:33 +02:00
MikolajTwarog
4aa2199d5b lib/connections: Accept new connections in place of old ones (fixes #5224) (#6548) 2020-04-20 08:23:38 +02:00
Simon Frei
49798552f2 lib/model: Delay watch setup on errors (fixes #5731) (#6544) 2020-04-17 17:43:42 +02:00
Jakob Borg
777a30e870 Add usage notes and screenshot 2020-04-17 09:34:31 +02:00
Jakob Borg
aea66ff25a v1.0.0 2020-04-17 09:11:01 +02:00
Jakob Borg
171b8139ab lib/model: Fix logging placeholder 2020-04-16 15:42:45 +02:00
Jakob Borg
7fa699e159 build, lib/build: Build faster (#6538)
This changes the build script to build all the things in one go
invocation, instead of one invocation per cmd. This is a lot faster
because it means more things get compiled concurrently. It's especially
a lot faster when things *don't* need to be rebuilt, possibly because it
only needs to build the dependency map and such once instead of once per
binary.

In order for this to work we need to be able to pass the same ldflags to
all the binaries. This means we can't set the program name with an
ldflag.

When it needs to rebuild everything (go clean -cache):

    ( ./old-build -gocmd go1.14.2 build all 2> /dev/null; )  65.82s user 11.28s system 574% cpu 13.409 total
    ( ./new-build -gocmd go1.14.2 build all 2> /dev/null; )  63.26s user 7.12s system 1220% cpu 5.766 total

On a subsequent run (nothing to build, just link the binaries):

    ( ./old-build -gocmd go1.14.2 build all 2> /dev/null; )  26.58s user 7.53s system 582% cpu 5.853 total
    ( ./new-build -gocmd go1.14.2 build all 2> /dev/null; )  18.66s user 2.45s system 1090% cpu 1.935 total
2020-04-16 10:09:33 +02:00
Jakob Borg
5373e38ac8 cmd/ursrv: Filter out ancient versions from chart 2020-04-16 09:13:01 +02:00
Jakob Borg
41ef945b2b gui, man, authors: Update docs, translations, and contributors 2020-04-15 07:45:24 +02:00
Jesse Lucas
9dd319f4da status-list: update styling, adding selected and hover states 2020-04-14 21:00:48 -04:00
Jesse Lucas
8b4a1f52d0 update folder devices array for the "shared with" section in the folder list #CTR-2 2020-04-14 21:00:48 -04:00
Jesse Lucas
7a9f317ee1 enable expandable rows for devices list 2020-04-14 21:00:48 -04:00
Jesse Lucas
48efea99e5 add trim pipe 2020-04-14 21:00:48 -04:00
Jesse Lucas
fbef856a97 Remove unused columns 2020-04-14 21:00:48 -04:00
Jesse Lucas
3b7c760ffd start of expandable rows for folder list 2020-04-14 21:00:48 -04:00
Jesse Lucas
ae776ff8df Rework device and folder service to have public obseravble
to accomaccommodatemodate many subscribers without re-requesting data
from the API
2020-04-14 21:00:48 -04:00
Jesse Lucas
24a637e9e6 Change device/folder getAll to getEach 2020-04-14 21:00:48 -04:00
Jesse Lucas
f53475a204 use replay subject in place of timer 2020-04-14 21:00:48 -04:00
greatroar
81ff31b8fc lib/model: Harden sanitizePath (#6533)
In particular, non-printable runes and non-UTF8 sequences are no longer
allowed. Linux systems will happily creates filenames containing these.
2020-04-14 20:26:26 +02:00
greatroar
82fbcb96f8 lib/db: Remove unused blockFinder global (#6534) 2020-04-14 17:09:59 +02:00
Jakob Borg
3fbc51cd38 Skip animations on donut charts 2020-04-14 16:29:52 +02:00
Jakob Borg
37ede49077 build: Remove snap build machinery (#6532) 2020-04-14 14:20:44 +02:00
Simon Frei
0ba3abdee4 lib/db: Handle missed error variable in old schema upgrade (#6528) 2020-04-13 22:58:04 +02:00
Simon Frei
ab92f8520c cmd/syncthing, lib/db: Store upgrade info to throttle queries (fixes #6513) (#6514) 2020-04-13 10:21:07 +02:00
Jakob Borg
0e67c036bb lib/db: Make database GC a service, stop on Stop() (#6518)
This makes the GC runner a service that will stop fairly quickly when
told to.

As a bonus, STTRACE=app will print the service tree on the way out,
including any errors they've flagged.
2020-04-12 10:26:57 +02:00
Jesse Lucas
5f1aba9a37 adjusting styles 2020-04-09 13:01:06 -04:00
Jesse Lucas
95f7a26bce style dialog component and close button 2020-04-09 13:01:06 -04:00
Jesse Lucas
6e1828ff63 support dark mode and add custom card component 2020-04-09 13:01:06 -04:00
Jesse Lucas
89c53c508b consolidate retry logic in error interceptor
remove retry operator from services
2020-04-09 13:01:06 -04:00
Jesse Lucas
9918cb4ffc Add MatDialog and use messageService to display errors 2020-04-09 13:01:06 -04:00
Jesse Lucas
7b61f800c3 add missing semicolon 2020-04-09 13:01:06 -04:00
Jesse Lucas
33d47063e8 remove unused data binding 2020-04-09 13:01:06 -04:00
Jesse Lucas
e67b91977d remove console logs 2020-04-09 13:01:06 -04:00
Jesse Lucas
ac603e9228 start of message service 2020-04-09 13:01:06 -04:00
Jesse Lucas
632b6f8fbd start of dialog component 2020-04-09 13:01:06 -04:00
Jesse Lucas
b247ef2632 start of error interceptor 2020-04-09 13:01:06 -04:00
Jakob Borg
046bbdfbd4 Merge branch 'release'
* release:
  lib/db: Don't get blocklists on drop and missing continue (ref #6457) (#6502)
  Revert "cmd/syncthing: Do auto-upgrade before startup (fixes #6384) (#6385)"
  lib/ur: Correct freaky error handling (fixes #6499) (#6500)
2020-04-08 10:49:59 +02:00
Jakob Borg
c6c74e8291 gui, man, authors: Update docs, translations, and contributors 2020-04-08 07:45:32 +02:00
Jakob Borg
59b1b0e1dc lib/osutil: Fix "atomic" rename on Windows (ref #6495, ref #6493) (#6510)
So, in a funny plot twist, it turns out that WriteFile in Go 1.13
doesn't actually set the read only bit on Windows when called with
permissions 0444 so my test was broken. With an improved test it turns
out that Rename does not, in fact, overwrite a read-only file on
Windows. This adds a fix for that.

(Rename might get improved in Go 1.15...)
2020-04-07 15:38:55 +02:00
Jakob Borg
4b17c511f9 cmd/stcrashreceiver: Enable (rough) affected users count (#6511)
Seeing thousands of reports is no use when we don't know if they
represent one poor user or thousands.
2020-04-07 13:19:49 +02:00
Simon Frei
df318ed370 lib/db: Don't get blocklists on drop and missing continue (ref #6457) (#6502) 2020-04-07 13:13:18 +02:00
Simon Frei
07ce3572a0 lib/ignore: Only skip for toplevel includes (fixes #6487) (#6508) 2020-04-07 10:23:38 +02:00
Jakob Borg
b64052bc26 Revert "build: Go 1.14 for the Debian etc builds"
This reverts commit d400e51422.
2020-04-07 09:37:39 +02:00
Jakob Borg
7956e7d0ef lib/{fs,scanner}: gofmt from Go 1.14 (#6509) 2020-04-07 09:31:29 +02:00
Jakob Borg
d400e51422 build: Go 1.14 for the Debian etc builds 2020-04-07 08:22:53 +02:00
Jesse Lucas
5a6d79a66e Recalculate completion for devices and update total properties 2020-04-06 14:30:44 -04:00
greatroar
674a99e9ae cmd/strelaypoolsrv: Simplify LRU usage (#6507) 2020-04-06 12:43:56 +02:00
Jakob Borg
88cabb9e0a lib/ur: Correct freaky error handling (fixes #6499) (#6500) 2020-04-06 09:53:37 +02:00
Jesse Lucas
1e33cc9720 update progress service with device/folders loaded and add animation 2020-04-05 11:50:05 -04:00
Jesse Lucas
ee465c0890 update progress service with get percentValue and table tests 2020-04-05 11:50:05 -04:00
Jesse Lucas
236816cb93 Add imports and providers to enable basic testing 2020-04-05 11:50:05 -04:00
Jesse Lucas
3ee9bc097f Update tech-ui-blue style to have contrast 2020-04-05 11:50:05 -04:00
Jesse Lucas
f205ce14c1 start of progress indicator and animation 2020-04-05 11:50:05 -04:00
Jesse Lucas
8199e0a7a9 update angular dependencies 2020-04-05 11:50:05 -04:00
greatroar
b7ba401c0b cmd/strelaypoolsrv: Fix race condition in caching (#6496)
Successful LRU cache lookups modify the cache's recency list, so
RWMutex.RLock isn't enough protection.

Secondarily, multiple concurrent lookups with the same key should not
create separate rate limiters, so release the lock only when presence
of the key in the cache has been ascertained.

Co-authored-by: greatroar <@>
2020-04-04 20:20:25 +01:00
Jakob Borg
7505ea79a0 lib/osutil: Don't remove before rename on Windows (ref #6493) (#6495)
This was needed in ancient times but not currently.
2020-04-04 14:17:16 +02:00
Kevin Bushiri
e1324a0e23 cmd/strelaypoolsrv: Use OpenStreetMap (fixes #6150) (#6459) 2020-04-04 13:48:20 +02:00
Jakob Borg
b7b9476e5a cmd/strelaysrv: Harmonize and improve log output (ref #6492) 2020-04-04 13:31:42 +02:00
Jakob Borg
d1db7e3dd2 cmd/strelaypoolsrv: Configurable request processors & queue len 2020-04-04 13:31:42 +02:00
Jakob Borg
362da59396 cmd/strelaypoolsrv: Expose check error to client, fix incorrect response code handling 2020-04-04 13:31:42 +02:00
Jakob Borg
66262392c3 cmd/strelaypoolsrv: Correctly account status codes, tweak status codes 2020-04-04 13:31:42 +02:00
Jakob Borg
48f9d323fa lib/api: Add LDAP search filters (fixes #5376) (#6488)
This adds the functionality to run a user search with a filter for LDAP
authentication. The search is done after successful bind, as the binding
user. The typical use case is to limit authentication to users who are
member of a group or under a certain OU. For example, to only match
users in the "Syncthing" group in otherwise default Active Directory
set up for example.com:

    <searchBaseDN>CN=Users,DC=example,DC=com</searchBaseDN>
    <searchFilter>(&amp;(sAMAccountName=%s)(memberOf=CN=Syncthing,CN=Users,DC=example,DC=com))</searchFilter>

The search filter is an "and" of two criteria (with the ampersand being
XML quoted),

- "(sAMAccountName=%s)" matches the user logging in
- "(memberOf=CN=Syncthing,CN=Users,DC=example,DC=com)" matches members
  of the group in question.

Authentication will only proceed if the search filter matches precisely
one user.
2020-04-04 11:33:43 +02:00
Jakob Borg
f18fc40436 Harmonize license with Syncthing proper 2020-04-03 22:28:36 +02:00
Jesse Lucas
f509c65509 increase chart item padding 2020-04-03 10:25:19 -04:00
Jesse Lucas
bf062db83f create chart item state to toggle filter selection 2020-04-03 09:20:27 -05:00
Jesse Lucas
9907523321 switch filter to Subject from BehaviorSubject 2020-04-03 09:20:27 -05:00
Jesse Lucas
915faabe25 Filter lists when donut chart items are clicked 2020-04-03 09:20:27 -05:00
Jesse Lucas
a9b6801b22 Store last filtered value between toggling of lists 2020-04-03 09:20:27 -05:00
Jesse Lucas
d76f1fe356 Style chart item 2020-04-03 09:20:27 -05:00
Jesse Lucas
3bdceb1d6b add filter service and enable chart states to filter lists 2020-04-03 09:20:27 -05:00
Simon Frei
f69c0b550c gui: Refactor out-of-sync modal (#6452) 2020-04-02 16:18:41 +02:00
Simon Frei
32245435e2 lib/model: Handle deleted items on RO for remote removes (fixes #6432) (#6464) 2020-04-02 16:14:25 +02:00
Jakob Borg
2658369051 gui: Expose LDAP config in advanced config editor (#6489)
One tiny step friendlier than vi on config.xml
2020-04-02 12:07:17 +02:00
Simon Mwepu
d50adb225b gui: Avoid validation error on closing folder editor (fixes #3808) (#6478) 2020-04-02 08:20:03 +02:00
Jakob Borg
7da898f2d6 go.mod: Use github.com/twmb/murmur3 for murmur3 (#6486)
Let's try this again shall we
2020-04-01 23:51:31 +02:00
Jakob Borg
0d919bd79c Revert "go.mod: Use github.com/twmb/murmur3 for murmur3"
"I shall not commit to master without testing all architectures on the
builder" * 100 on the black board
2020-04-01 21:16:15 +02:00
Jakob Borg
f91e90a94f go.mod: Use github.com/twmb/murmur3 for murmur3
It seems, like, maintained and stuff.
2020-04-01 21:04:43 +02:00
Jakob Borg
7ce20f197b gui, man, authors: Update docs, translations, and contributors 2020-04-01 07:45:33 +02:00
Jesse Lucas
cce8b60515 adjust filter style and add filter to device list 2020-03-31 20:40:36 -04:00
Jesse Lucas
06eacb87d8 Add additional columns, styling and data to lists 2020-03-31 20:40:36 -04:00
Jesse Lucas
865f1f2ea6 reduce mock data delay for testing 2020-03-31 20:40:36 -04:00
Jesse Lucas
f59a26cb80 relative path apiURL 2020-03-31 11:41:59 -04:00
Jesse Lucas
d384ac52a1 use relative path for base-href and meta.js 2020-03-31 11:41:59 -04:00
Jesse Lucas
42fa03aa4a start of list filtering 2020-03-31 11:41:59 -04:00
Jesse Lucas
dae1f990a5 Combine types 2020-03-31 11:41:59 -04:00
Jakob Borg
33398b0b6b Also mention STGUIASSETS 2020-03-31 16:14:09 +02:00
Jakob Borg
192e843989 README/LICENSE 2020-03-31 15:55:39 +02:00
greatroar
2f26a95973 lib/db, lib/model: Code simplifications (#6484)
NamespacedKV.prefixedKey is still small enough to be inlined.
2020-03-31 14:32:24 +02:00
Simon Frei
123941cf62 lib/fs: Basic with empty root shouldn't point at / (#6483) 2020-03-31 13:56:07 +02:00
Jakob Borg
9c67d57c28 lib/api: Update ldap package (fixes #6479) (#6481) 2020-03-31 09:56:04 +02:00
mv1005
5b3466dc6e lib/versioner: Extended tests of intervals (#6462) 2020-03-31 00:14:05 +02:00
Michael Rienstra
bca6854c03 lib/versioner: Fix "30 days" interval (fixes #6410) (#6461) 2020-03-30 23:28:53 +02:00
greatroar
c930b2e9e2 lib/rand: Various fixes (#6474) 2020-03-30 23:26:28 +02:00
Jesse Lucas
8851f4571c Add header and logo 2020-03-30 14:48:53 -04:00
Jesse Lucas
7fed8334b9 Use a smaller font when device or folder counts are above 4 digits 2020-03-30 14:48:53 -04:00
Jesse Lucas
6af2657d7e Combine folder and device chart component into chart component 2020-03-30 14:48:53 -04:00
Jesse Lucas
933a57af7a Add title to donut chart and media queries 2020-03-30 11:54:54 -04:00
Jesse Lucas
e5b85ff1a0 update angular cli, devkit and node 2020-03-30 11:54:24 -04:00
greatroar
d7a257b391 lib/util: Fix potential data race (#6477)
Co-authored-by: greatroar <@>
2020-03-30 14:10:08 +01:00
Alberto Donato
7709ac33a7 go.mod: Update jackpal/gateway dependency (fixes #5288) (#6469) 2020-03-30 11:11:55 +02:00
Jesse Lucas
c382aa04e4 right justify chart items 2020-03-29 17:45:08 -04:00
Jesse Lucas
86141c1eef enable chart canvas responsiveness 2020-03-29 16:51:12 -04:00
Jesse Lucas
d67c9b66d3 determine chart color based on state type 2020-03-29 16:51:12 -04:00
Jesse Lucas
6158b20a8c Style donut chart and add total count 2020-03-29 16:51:12 -04:00
Jesse Lucas
485a234263 Use flexbox for dashboard layout 2020-03-29 16:51:12 -04:00
Jesse Lucas
7226a87c6d Create tech ui card css to replace material cards 2020-03-29 16:51:12 -04:00
Jesse Lucas
7aca2bcbc0 add custom chartjs tooltip 2020-03-29 16:51:12 -04:00
Jesse Lucas
3840d57f8d temporarily handle current device in device list 2020-03-29 16:51:12 -04:00
Jesse Lucas
b7f3425f36 add system status service and mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
9fe0c30299 update mock names 2020-03-29 16:51:12 -04:00
Jesse Lucas
9d126760fa Synchronously get the status of each device 2020-03-29 16:51:12 -04:00
Jesse Lucas
09673ba0c6 create db completion service and mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
bc7d71ee3d Create system connections service, mocks, and work on updating devices chart 2020-03-29 16:51:12 -04:00
Jesse Lucas
78a31449aa create Device namespace and getStateType function 2020-03-29 16:51:12 -04:00
Jesse Lucas
0361d303f2 organize services into services folder 2020-03-29 16:51:12 -04:00
Jesse Lucas
2fe94736e6 update device chart to use donut chart updateData 2020-03-29 16:51:12 -04:00
Jesse Lucas
9589f25e57 refactor to use caching interceptor 2020-03-29 16:51:12 -04:00
Jesse Lucas
15c2556e06 fix conditional logic 2020-03-29 16:51:12 -04:00
Jesse Lucas
f342a2a54b refactor to use array of objects to map state data to chart update 2020-03-29 16:51:12 -04:00
Jesse Lucas
598dc991e8 complete observers 2020-03-29 16:51:12 -04:00
Jesse Lucas
7d59dc6c18 add updateData and removeAllData methods to donut chart 2020-03-29 16:51:12 -04:00
Jesse Lucas
05f01a5d94 start of caching, csrf interceptor, and device service 2020-03-29 16:51:12 -04:00
Jesse Lucas
03c6fb2f82 Rename folders 2020-03-29 16:51:12 -04:00
Jesse Lucas
7a657bf3c7 Create states map and set chart-items based on map 2020-03-29 16:51:12 -04:00
Jesse Lucas
02d14c7e9b Add chart item component, StateType and getStateType to determine state from Folder 2020-03-29 16:51:12 -04:00
Jesse Lucas
32c849e18c Refactor Folder interface to use Folder namespace 2020-03-29 16:51:12 -04:00
Jesse Lucas
c27fe5694d Update mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
b0ebf56283 Add new component chart-item 2020-03-29 16:51:12 -04:00
Jesse Lucas
fb33a8ad6b Remove unused tags in index.html 2020-03-29 16:51:12 -04:00
Jesse Lucas
9207562545 refactor status toggle to list toggle 2020-03-29 16:51:12 -04:00
Jesse Lucas
230eb20a34 update font styles 2020-03-29 16:51:12 -04:00
Jesse Lucas
e0d9542bfe update status list template and add flex box 2020-03-29 16:51:12 -04:00
Jesse Lucas
063951cffa Synchronously get the status of each folder 2020-03-29 16:51:12 -04:00
Jesse Lucas
dae0872379 Remove Folder object from array in development only 2020-03-29 16:51:12 -04:00
Jesse Lucas
123f4a6d9d Update mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
65679892b0 Don't encapsulate data for in memory services for development 2020-03-29 16:51:12 -04:00
Jesse Lucas
c4979cf6d6 update readme to disable syncthing upgrade 2020-03-29 16:51:12 -04:00
Jesse Lucas
09d498bb80 Refactor charts to use @ViewChild instead of @Input 2020-03-29 16:51:12 -04:00
Jesse Lucas
90ed7aa121 add apiRetry to api-utils 2020-03-29 16:51:12 -04:00
Jesse Lucas
206c0d0933 Work on db status service 2020-03-29 16:51:12 -04:00
Jesse Lucas
81c539c516 new folder service 2020-03-29 16:51:12 -04:00
Jesse Lucas
75b3b31d11 create folder status interface 2020-03-29 16:51:12 -04:00
Jesse Lucas
90c39de0cc add system config service retry 2020-03-29 16:51:12 -04:00
Jesse Lucas
241864b43c create mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
b2d839d4e7 fix race condition with Observables in list components 2020-03-29 16:51:12 -04:00
Jesse Lucas
8bdf409d07 start of db status service 2020-03-29 16:51:12 -04:00
Jesse Lucas
08da982de5 pass and add data to donut chart 2020-03-29 16:51:12 -04:00
Jesse Lucas
f250425ef1 clean up mock data and update device interface 2020-03-29 16:51:12 -04:00
Jesse Lucas
aebcc495f9 create style.ts to set elevation for all dashboard components 2020-03-29 16:51:12 -04:00
Jesse Lucas
eaffbc0f92 refactor chart and list component structure 2020-03-29 16:51:12 -04:00
Jesse Lucas
37f2f2cdf6 add delay to in memory service and update check interval 2020-03-29 16:51:12 -04:00
Jesse Lucas
82f5706350 start of chart component 2020-03-29 16:51:12 -04:00
greatroar
1e2379df1b lib/protocol: faster Luhn algorithm and better testing (#6475)
The previous implementation was very generic; its tests didn't cover the
actual alphabet for device IDs.

Benchmark results on amd64:

name         old time/op    new time/op     delta
Luhnify-8      1.00µs ± 1%     0.28µs ± 4%   -72.38%  (p=0.000 n=9+10)
Unluhnify-8     992ns ± 2%      274ns ± 1%   -72.39%  (p=0.000 n=10+9)
2020-03-29 22:28:04 +02:00
greatroar
ea5c9176e1 lib/protocol: Remove unused channel Connection.preventSends (#6473)
Co-authored-by: greatroar <@>
2020-03-29 17:09:53 +01:00
greatroar
cc1b003f21 lib/weakhash: Fix speed reporting in benchmark (#6470) 2020-03-29 17:07:25 +02:00
Jakob Borg
38bd90e6f2 build: Simplify/correct Windows version tagging (fixes #6471) (#6472) 2020-03-29 16:51:50 +02:00
greatroar
1c47fae206 lib/ur: Use sysctl syscall to get RAM size on Mac (#6468) 2020-03-29 14:28:46 +02:00
Simon Frei
79a758be3c lib/model: Do Revert/Override synchronously (#6460) 2020-03-27 13:05:09 +01:00
Simon Frei
c7cf3ef899 lib/syncthing: Save version to db after upgrade ops are done (ref #6457) (#6458) 2020-03-26 16:58:21 +01:00
Jakob Borg
2c2e6cd0d5 cmd/ursrv: Minor heatmap tweaks 2020-03-26 15:19:05 +01:00
Simon Frei
b7dffc051e lib/model: Remove unused func (#6456) 2020-03-26 14:19:26 +01:00
Kevin Bushiri
963e9a4071 cmd/ursrv: Use OpenStreetMap and Leaflet for heat map (ref #6150) (#6454) 2020-03-26 12:32:14 +01:00
Jakob Borg
b28899ac07 cmd/ursrv: Provide cached locations.json 2020-03-25 14:19:35 +01:00
Jakob Borg
83f6da8dca authors: Fixup keevBush 2020-03-25 10:03:23 +01:00
Jakob Borg
1a29296d9d gui, man, authors: Update docs, translations, and contributors 2020-03-25 07:45:35 +01:00
Simon Frei
a7de4c68e3 go.mod: Update quic-go to 0.14.4 (#6453) 2020-03-24 21:12:57 +01:00
Simon Frei
7f23de4f03 all: Pass db intervals as args not env vars (#6448) 2020-03-24 13:53:20 +01:00
Jakob Borg
ca89f12be6 lib/api: Set ServerName on LDAPS connections (fixes #6450) (#6451)
tls.Dial needs it for certificate verification.
2020-03-24 12:56:43 +01:00
Simon Frei
ddfa82e990 lib/model: Unset local flag on deleted files (fixes #6436) (#6449) 2020-03-24 12:51:17 +01:00
Nicolas Perraut
61302c467c gui: Improve unused device status (fixes #6416) (#6445) 2020-03-22 19:30:18 +01:00
Simon Frei
d6b4873eed gui, lib/model: Fix for folder stats with r-o and ignoreDel (fixes #6430) (#6431) 2020-03-22 11:46:42 +01:00
Jakob Borg
1ea98a16b1 cmd/syncthing: Don't open browser on upgrade restarts (fixes #6437) (#6442)
We set the STRESTART environment when starting the inner process after
the first time, but this didn't persist when restarting the monitor
process. Now it does.
2020-03-22 11:39:09 +01:00
Jakob Borg
e2f3500df9 cmd/syncthing: Properly handle STNORESTART=1 (fixes #6440) (#6441)
Makes it truly equivalent to -no-restart, and also updates the option
descriptions to be more truthful.
2020-03-22 11:38:53 +01:00
Jakob Borg
8b025af1e5 Merge branch 'release'
* release:
  lib/db: Don't whack blocks when putting truncated file (#6434)
2020-03-20 12:08:16 +01:00
Jakob Borg
c4abe6f815 lib/db: Don't whack blocks when putting truncated file (#6434)
As of the latest database checker we are again putting files without
blocks. I'm not 100% convinced that's a great idea, but we also do it
for ignored files apparently so it looks like we probably should support
it. This adds an escape hatch that must be manually enabled...
2020-03-20 12:07:14 +01:00
Jakob Borg
4c5e9cf921 Merge branch 'release'
* release:
  lib/db, lib/syncthing: Repair db once on upgrade (ref #6425, #6427) (#6429)
  lib/db: Fix removeFromGlobal and no filenames in error (fixes #6427) (#6428)
  lib/db: Remove emptied global list in checkGlobals (fixes #6425) (#6426)
2020-03-19 16:05:39 +01:00
Simon Frei
74706bb02b lib/db, lib/syncthing: Repair db once on upgrade (ref #6425, #6427) (#6429) 2020-03-19 15:58:32 +01:00
Kevin Bushiri
5975772ed8 cmd/stdiscosrv: Only generate keypair if it doesn't exist (fixes #5809) (#6419) 2020-03-19 14:50:24 +01:00
Simon Frei
cf11fa4327 lib/db: Fix removeFromGlobal and no filenames in error (fixes #6427) (#6428) 2020-03-19 14:32:22 +01:00
Simon Frei
40580d8b9b lib/db: Remove emptied global list in checkGlobals (fixes #6425) (#6426) 2020-03-19 14:30:20 +01:00
Simon Frei
e25e71cdde cmd/syncthing, lib/locations: Separate data and config dirs (fixes #4924) (#6309) 2020-03-18 20:58:11 +01:00
Jesse Lucas
ad2902b3ee start of dashboard component with flexbox 2020-03-15 17:19:57 -04:00
Jesse Lucas
ce2c6c01da update mock config data and service 2020-03-15 17:19:57 -04:00
Jesse Lucas
fb4c7d288c update system config url and http options 2020-03-15 12:47:24 -04:00
Jesse Lucas
838b2a6a34 add mock in-memory data service 2020-03-15 12:47:24 -04:00
Jesse Lucas
fd0de9eb6c update readme to indicate build and syncthing tech-ui branch 2020-03-14 22:38:41 -04:00
Jesse Lucas
6b89991ba8 create cookie service to find CSRF header data 2020-03-14 20:11:05 -04:00
Jesse Lucas
4727570870 create api-utils to hold convenience convenience data structures 2020-03-14 20:11:05 -04:00
Jesse Lucas
ebf0541385 start of CSRF 2020-03-14 20:11:05 -04:00
Jesse Lucas
af3d380b6a update SystemConfigService to load config and set folders and devices
update getFolders and getDevices to send respective array as soon as it has data
2020-03-14 20:11:05 -04:00
Jesse Lucas
cf3de8cf35 toggle status lists 2020-03-11 21:24:02 -04:00
Jesse Lucas
61b4de581d create folder and device list components
refactor status-list to contain device and folder list
2020-03-11 21:24:02 -04:00
Jesse Lucas
031fd72dfd start of toggle to switch between devices and folders data table 2020-03-11 21:24:02 -04:00
Jesse Lucas
1d249a877e start of StatusList component 2020-03-10 22:51:50 -04:00
Jesse Lucas
3eb6045dee initial commit 2020-03-10 10:57:02 -04:00
642 changed files with 103651 additions and 16883 deletions

View File

@@ -1,5 +1,20 @@
comment: false
coverage:
range: "40...100"
precision: 1
status:
patch:
default:
informational: true
project:
default:
informational: true
github_checks:
annotations: false
ignore:
- "**.pb.go"
- "**_mocked.go"
- "**/mocks/*"

12
.deepsource.toml Normal file
View File

@@ -0,0 +1,12 @@
version = 1
exclude_patterns = ["*.pb.go"]
test_patterns = ["*_test.go"]
[[analyzers]]
name = "go"
enabled = true
[analyzers.meta]
import_paths = ["github.com/syncthing/syncthing"]
build_tags = ["noassets"]

11
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
github: syncthing
custom: "https://syncthing.net/donations/"
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username

View File

@@ -1,42 +0,0 @@
### DO NOT REPORT SECURITY ISSUES IN THIS ISSUE TRACKER
Instead, contact security@syncthing.net directly - see
https://syncthing.net/security.html for more information.
### DO NOT POST SUPPORT REQUESTS OR GENERAL QUESTIONS IN THIS ISSUE TRACKER
Please use the forum at https://forum.syncthing.net/ where a large number of
helpful people hang out. This issue tracker is for reporting bugs or feature
requests directly to the developers. Worst case you might get a short
"that's a bug, please report it on GitHub" response on the forum, in which
case we thank you for your patience and following our advice. :)
### Please use the correct issue tracker
If your problem relates to a Syncthing wrapper or [sub-project](https://github.com/syncthing) such as [Syncthing for Android](https://github.com/syncthing/syncthing-android/issues), [SyncTrayzor](https://github.com/canton7/synctrayzor) or the [documentation](https://github.com/syncthing/docs/issues), please use their respective issue trackers.
### Does your log mention database corruption?
If your Syncthing log reports panics because of database corruption it is most likely a fault with your system's storage or memory. Affected log entries will contain lines starting with `panic: leveldb`. You will need to delete the index database to clear this, by running `syncthing -reset-database`.
### Please do post actual bug reports and feature requests.
If your issue is a bug report, replace this boilerplate with a description
of the problem, being sure to include at least:
- what happened,
- what you expected to happen instead, and
- any steps to reproduce the problem.
Also fill out the version information below and add log output or
screenshots as appropriate.
If your issue is a feature request, simply replace this template text in
its entirety.
### Version Information
Syncthing Version: v1.x.y
OS Version: Windows 7 / Ubuntu 14.04 / ...
Browser Version: (if applicable, for GUI issues)

13
.github/ISSUE_TEMPLATE/01-feature.md vendored Normal file
View File

@@ -0,0 +1,13 @@
---
name: Feature request
about: If you're just not sure how to do something, see "ask a question".
labels: enhancement, needs-triage
---
### Include required information
Please be sure to include at least:
- what problem your new feature would solve
- how or why you think it is generally useful (i.e., not just for you)
- what alternatives or workarounds you considered

23
.github/ISSUE_TEMPLATE/02-bug.md vendored Normal file
View File

@@ -0,0 +1,23 @@
---
name: Bug report
about: If you're actually looking for support, see "ask a question".
labels: bug, needs-triage
---
### Does your log mention database corruption?
If your Syncthing log reports panics because of database corruption it is
most likely a fault with your system's storage or memory. Affected log
entries will contain lines starting with `panic: leveldb`. You will need to
delete the index database to clear this, by running `syncthing
-reset-database`.
### Include required information
Please be sure to include at least:
- which version of Syncthing and what operating system you are using
- browser and version, if applicable
- what happened,
- what you expected to happen instead, and
- any steps to reproduce the problem.

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: I need help / I have a question
url: https://forum.syncthing.net/
about: Ask questions, get support, and discuss with other community members.
- name: Android issues
url: https://github.com/syncthing/syncthing-android/issues/
about: The Android app has its own issue tracker.

52
.github/SECURITY.md vendored
View File

@@ -1,48 +1,10 @@
## Reporting a Vulnerability
If you believe that you've found a Syncthing-related security vulnerability, please report it by sending email to the address security@syncthing.net. The PGP key for security@syncthing.net (B683AD7B76CAB013) below can be used to send encrypted mail or to verify responses received from that address.
If you believe that you've found a Syncthing-related security vulnerability,
please report it by sending email to the address security@syncthing.net. The
[PGP key for security@syncthing.net
(B683AD7B76CAB013)](https://syncthing.net/security-key.txt) can be used to
send encrypted mail or to verify responses received from that address.
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFShFlIBCACsW346HYskhKhxrdZMjyU5Ntsjvg6/ogqINDPoL10/oaIP0G+t
7zzC0K5Cq29ix43kNNLKTJNyPkdTeaJEcqslMUt6tovjHwoKJ073GP0W3KsNvBRg
ffCZOAexGfOsBSL9KHaYGK67Py3TFgtN1H/EmboU1arrLfAMrmqOip++EGqOxjse
gH0qk7Mk1TqEC5Xh3NGE7r1UobAlqdUv5E3v7U11NhAdP1zu/XZ/zvP5mwVQJMLv
iZyeWGliNI8nEeRjYw+S85f4gq7H2mgoeNBN4WwwK1hhz9qpvCsgPW3XqlExTPI4
1vM4PxpiFIuF0zuy2OwsmjrpTCZeBscr4Tj5ABEBAAG0K1N5bmN0aGluZyBTZWN1
cml0eSA8c2VjdXJpdHlAc3luY3RoaW5nLm5ldD6JATgEEwECACIFAlShFlICGwMG
CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJELaDrXt2yrATB1UH/jnnIa6DekCA
2V36N/2+pFSNLVWeoZQxZ9ne9S7WSubaoK4oCWiuChPSAy5hagnKnNA3a9wrz5iN
0hgCA88NnTU18biZW6HX8xWEd3dnY3fX1sG0XdHuKlFria8ByfcrbShf/CttXkEd
Y5qPHH9aLIMtksBS1MIsRYrOCHiLNYFCKlbjDDCGT3tuk/yaU7aBAFVPIag54afC
zZAIvTIgRruLWkNT/sSEJx9ekhJzO/+pXNbSSHwhoj5OJh7sQjZWwPzNazelk48R
+ku8VpB5Wxgk2MnJPf1RxF+7saBAaeAVZsJcPN+Jp7u9LCFelIRn1ISsHbhLhyqL
cPXqllltLCKJAhwEEAECAAYFAlShFlsACgkQSfWuwLzlJMcEpA//VvZYHGZgZMM0
bBkYnjManYnJkHSQ2pHsjquSFH+fbfq2FxxTk/nQ/IAvBzt8NDTT3ylPOmsl4A8q
r8BxsRNENhU7zDQrKC5NtYUrzXhPGo8qfDwkeLyqd2msUvHn7EH3PNgiN2QaFWxE
21FqoXIpERKJRgRtv1SYZoMyNGjmT2hta1ZbwEfrPJnzjYhneoUGsRApG7p+uPqe
4LRpbG3Fa2vBm/UWUrOe+6jPzvMokjIJbdK0IjXamFAzwYW5fSZaFa94mR6L5f5m
X8Dhp66mBRTx7qk6ldEqptvaYGqihaWP1xbDaApQsGHQujtcBYGp+edlkabuW5h7
stl/7QTFkEPqHT4ybxEX0rLoFUGq56WUlKp27z40keStaXMgfrsxJtkz66Xs8vU4
7qZcLAcPsin+y0toqavtwtM/L7uCMu1yhbFRGJ+JL6saJAqzwS8l7r6E2R7OnVj1
BdASgxx1TgzW6ZFW5p1Iy6mtpkBypsnp8s3UcP3GFRnQe9gi1EXHjzuZAUGafe4Q
juvJ8t8xIcQMFuAylNIVyXvIWJoehqsVY9EBgVtE4y1SRh8XTT3Tddn8ab5fl7uh
HWAY8cRlv6WIOhK8w8oroiYx0SID8jMeEwJBS4DL7qWtJMkDo8ZEJiB+Pkd963MX
05QXt33AvJJ9PmbGCHkcH7198tCmA+e5AQ0EVKEWUgEIAPGczHpa6NdxY0pm+tIp
btiA6gdPE70pJYgJTKX7siCQ2w770H3CBSKmqEXadr7WnfIgUYIDaSxadeGzB/Mn
3SHCYRCqbA7mwu2k4wNNvCEM0xZqFAvaDJ4avlZ5oiMT8IFHKsjC77nkhmfXaIGt
hn10H2MFADjvJYul7vR+Ghg1wGhTGWo2u7VVj9BI+AfvnWaouFI0cx2KNWEI/Ocj
z6jk8nmC3yOEFQECM/hF4lkAOv9CQUa8UcvAr31trzawmV1iSsKjmVZgqd0N4T8f
hUikqUPZGNCRcqEUffTzggIyGPbedFnZw9Di7o1xByxyTrZycemAVqaVGF+9nFLG
pccAEQEAAYkBHwQYAQIACQUCVKEWUgIbDAAKCRC2g617dsqwEzrjB/9q0T8A4XUE
p0g6xq86jhmh4jlEedxrfXUL3R6ejFtuKMThulxEP0xiQ7xLzBhOnvyxLCsVbjp8
0JtJTVCq44UzUiIBuVNRoYG29uXuTUL2UtI27VhjFxMzLDwZL97tbGR6lzdM/+U5
9PC+PIvS0yz13z2t3/x3KUOnBgxZnpy9h4AdKwjrNVtnQdGDXSKlJBLb57TFcS94
f3roZ5Gpw3AWYSmSSiZWbhks2UNzYSQ84LAKlV1NkktO+qRc/pUqr6IxMjOKc7XP
e8u1Nst6fN3GNqZOV+jUYs/fqrJgp1TUWjNTuf22Rl0Idz7XLPJKYFh9W7T/4MbU
M7Q8GZuww1rk
=No/v
-----END PGP PUBLIC KEY BLOCK-----
```
You can read more about Syncthing security at
https://syncthing.net/security/.

7
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10

10
.gitignore vendored
View File

@@ -15,12 +15,8 @@ coverage.xml
syncthing.sig
RELEASE
deb
lib/auto/gui.files.go
snapcraft.yaml
prime/
snap/
parts/
stage/
*.snap
*.bz2
/repos
/proto/scripts/protoc-gen-gosyncthing
/gui/next-gen-gui
.idea

49
AUTHORS
View File

@@ -17,7 +17,9 @@ Aaron Bieber (qbit) <qbit@deftly.net>
Adam Piggott (ProactiveServices) <aD@simplypeachy.co.uk> <simplypeachy@users.noreply.github.com> <ProactiveServices@users.noreply.github.com> <adam@proactiveservices.co.uk>
Adel Qalieh (adelq) <aqalieh95@gmail.com> <adelq@users.noreply.github.com>
Alan Pope <alan@popey.com>
Alberto Donato <albertodonato@users.noreply.github.com>
Alessandro G. (alessandro.g89) <alessandro.g89@gmail.com>
Alex Lindeman <139387+aelindeman@users.noreply.github.com>
Alex Xu <alex.hello71@gmail.com>
Alexander Graf (alex2108) <register-github@alex-graf.de>
Alexandre Viau (aviau) <alexandre@alexandreviau.net> <aviau@debian.org>
@@ -32,6 +34,7 @@ andyleap <andyleap@gmail.com>
Anjan Momi <anjan@momi.ca>
Antoine Lamielle (0x010C) <antoine.lamielle@0x010c.fr> <gh@0x010c.fr>
Antony Male (canton7) <antony.male@gmail.com>
Anur <anurnomeru@163.com>
Aranjedeath <Aranjedeath@users.noreply.github.com>
Arkadiusz Tymiński <gevleeog@gmail.com>
Arthur Axel fREW Schmidt (frioux) <frew@afoolishmanifesto.com> <frioux@gmail.com>
@@ -49,18 +52,23 @@ Benedikt Morbach <benedikt.morbach@googlemail.com>
Benno Fünfstück <benno.fuenfstueck@gmail.com>
Benny Ng (tpng) <benny.tpng@gmail.com>
boomsquared <54829195+boomsquared@users.noreply.github.com>
Boqin Qin <bobbqqin@bupt.edu.cn>
Boris Rybalkin <ribalkin@gmail.com>
Brandon Philips (philips) <brandon@ifup.org>
Brendan Long (brendanlong) <self@brendanlong.com>
Brian R. Becker (brbecker) <brbecker@gmail.com>
bt90 <btom1990@googlemail.com>
Caleb Callaway (cqcallaw) <enlightened.despot@gmail.com>
Carsten Hagemann (carstenhag) <moter8@gmail.com> <carsten@chagemann.de>
Cathryne Linenweaver (Cathryne) <cathryne.linenweaver@gmail.com> <Cathryne@users.noreply.github.com> <katrinleinweber@MAC.local>
Cedric Staniewski (xduugu) <cedric@gmx.ca>
chenrui <rui@meetup.com>
Chih-Hsuan Yen <yan12125@gmail.com>
Choongkyu <choongkyu.kim+gh@gmail.com> <vapidlyrapid+gh@gmail.com>
Chris Howie (cdhowie) <me@chrishowie.com>
Chris Joel (cdata) <chris@scriptolo.gy>
Chris Tonkinson <chris@masterbran.ch>
Christian Prescott <me@christianprescott.com>
chucic <chucic@seznam.cz>
Colin Kennedy (moshen) <moshen.colin@gmail.com>
Cromefire_ <tim.l@nghorst.net> <26320625+cromefire@users.noreply.github.com>
@@ -72,10 +80,11 @@ Daniel Harte (norgeous) <daniel@harte.me> <daniel@danielharte.co.uk> <norgeous@u
Daniel Martí (mvdan) <mvdan@mvdan.cc>
Darshil Chanpura (dtchanpura) <dtchanpura@gmail.com> <dcprime314@gmail.com>
David Rimmer (dinosore) <dinosore@dbrsoftware.co.uk>
deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
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>
@@ -84,56 +93,72 @@ Dominik Heidler (asdil12) <dominik@heidler.eu>
Elias Jarlebring (jarlebring) <jarlebring@gmail.com>
Elliot Huffman <thelich2@gmail.com>
Emil Hessman (ceh) <emil@hessman.se>
Eric Lesiuta <elesiuta@gmail.com>
Erik Meitner (WSGCSysadmin) <e.meitner@willystreet.coop>
Evgeny Kuznetsov <evgeny@kuznetsov.md>
Federico Castagnini (facastagnini) <federico.castagnini@gmail.com>
Felix Ableitner (Nutomic) <me@nutomic.com>
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>
Gleb Sinyavskiy <zhulik.gleb@gmail.com>
Graham Miln (grahammiln) <graham.miln@dssw.co.uk> <graham.miln@miln.eu>
greatroar <61184462+greatroar@users.noreply.github.com>
Han Boetes <han@boetes.org>
HansK-p <42314815+HansK-p@users.noreply.github.com>
Harrison Jones (harrisonhjones) <harrisonhjones@users.noreply.github.com>
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>
Jacek Szafarkiewicz (hadogenes) <szafar@linux.pl>
Jack Croft <jccroft1@users.noreply.github.com>
Jacob <jyundt@gmail.com>
Jake Peterson (acogdev) <jake@acogdev.com>
Jakob Borg (calmh) <jakob@nym.se> <jakob@kastelo.net>
James Patterson (jpjp) <jamespatterson@operamail.com> <jpjp@users.noreply.github.com>
janost <janost@tuta.io>
Jaroslav Lichtblau <svetlemodry@users.noreply.github.com>
Jaroslav Malec (dzarda) <dzardacz@gmail.com>
jaseg <githubaccount@jaseg.net>
Jaya Chithra (jayachithra) <s.k.jayachithra@gmail.com>
jelle van der Waa <jelle@vdwaa.nl>
Jens Diemer (jedie) <github.com@jensdiemer.de> <git@jensdiemer.de>
Jerry Jacobs (xor-gate) <jerry.jacobs@xor-gate.org> <xor-gate@users.noreply.github.com>
Jesse Lucas <jesse@jesselucas.com>
Jochen Voss (seehuhn) <voss@seehuhn.de>
Johan Andersson <j@i19.se>
Johan Vromans (sciurius) <jvromans@squirrel.nl>
John Rinehart (fuzzybear3965) <johnrichardrinehart@gmail.com>
Jonas Thelemann <e-mail@jonas-thelemann.de>
Jonathan <artback@protonmail.com>
Jonathan Cross <jcross@gmail.com>
Jonta <359397+Jonta@users.noreply.github.com>
Jose Manuel Delicado (jmdaweb) <jmdaweb@hotmail.com> <jmdaweb@users.noreply.github.com>
jtagcat <git-514635f7@jtag.cat>
Jörg Thalheim <Mic92@users.noreply.github.com>
Jędrzej Kula <kula.jedrek@gmail.com>
Kalle Laine <pahakalle@protonmail.com>
Karol Różycki (krozycki) <rozycki.karol@gmail.com>
Keith Turner <kturner@apache.org>
Kelong Cong (kc1212) <kc04bc@gmx.com> <kc1212@users.noreply.github.com>
Ken'ichi Kamada (kamadak) <kamada@nanohz.org>
Kevin Allen (ironmig) <kma1660@gmail.com>
Kevin Bushiri (keevBush) <keevbush@gmail.com> <36192217+keevBush@users.noreply.github.com>
Kevin White, Jr. (kwhite17) <kevinwhite1710@gmail.com>
klemens <ka7@github.com>
Kurt Fitzner (Kudalufi) <kurt@va1der.ca> <kurt.fitzner@gmail.com>
Lars K.W. Gohlke (lkwg82) <lkwg82@gmx.de>
Lars Lehtonen <lars.lehtonen@gmail.com>
Laurent Arnoud <laurent@spkdev.net>
Laurent Etiemble (letiemble) <laurent.etiemble@gmail.com> <laurent.etiemble@monobjc.net>
Leo Arias (elopio) <yo@elopio.net>
@@ -147,6 +172,7 @@ Marc Pujol (kilburn) <kilburn@la3.org>
Marcin Dziadus (marcindziadus) <dziadus.marcin@gmail.com>
marco-m <marco.molteni@laposte.net>
Marcus Legendre <marcus.legendre@gmail.com>
Mario Majila <mariustshipichik@gmail.com>
Mark Pulford (mpx) <mark@kyne.com.au>
Mateusz Naściszewski (mateon1) <matin1111@wp.pl>
Mateusz Ż <thedead4fun@live.com>
@@ -158,23 +184,31 @@ Maurizio Tomasi <ziotom78@gmail.com>
Max Schulze (kralo) <max.schulze@online.de> <kralo@users.noreply.github.com>
MaximAL <almaximal@ya.ru>
Maxime Thirouin <m@moox.io>
mclang <1721600+mclang@users.noreply.github.com>
Michael Jephcote (Rewt0r) <rewt0r@gmx.com> <Rewt0r@users.noreply.github.com>
Michael Ploujnikov (plouj) <ploujj@gmail.com>
Michael Rienstra <mrienstra@gmail.com>
Michael Tilli (pyfisch) <pyfisch@gmail.com>
MichaIng <micha@dietpi.com>
Mike Boone <mike@boonedocks.net>
MikeLund <MikeLund@users.noreply.github.com>
MikolajTwarog <43782609+MikolajTwarog@users.noreply.github.com>
Mingxuan Lin <gdlmx@users.noreply.github.com>
mv1005 <49659413+mv1005@users.noreply.github.com>
Nate Morrison (nrm21) <natemorrison@gmail.com>
Nicholas Rishel (PrototypeNM1) <rishel.nick@gmail.com> <PrototypeNM1@users.noreply.github.com>
Nico Stapelbroek <3368018+nstapelbroek@users.noreply.github.com>
Nicolas Braud-Santoni <nicolas@braud-santoni.eu>
Nicolas Perraut <n.perraut@gmail.com>
Niels Peter Roest (Niller303) <nielsproest@hotmail.com> <seje.niels@hotmail.com>
Nils Jakobi (thunderstorm99) <jakobi.nils@gmail.com>
NinoM4ster <ninom4ster@gmail.com>
Nitroretro <43112364+Nitroretro@users.noreply.github.com>
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>
@@ -186,14 +220,18 @@ Peter Badida <KeyWeeUsr@users.noreply.github.com>
Peter Dave Hello <hsu@peterdavehello.org>
Peter Hoeg (peterhoeg) <peter@speartail.com>
Peter Marquardt (wwwutz) <wwwutz@gmail.com> <wwwutz@googlemail.com>
Phani Rithvij <phanirithvij2000@gmail.com>
Phil Davis <phil.davis@inf.org>
Philippe Schommers (filoozoom) <philippe@schommers.be>
Phill Luby (pluby) <phill.luby@newredo.com>
Pier Paolo Ramon <ramonpierre@gmail.com>
Piotr Bejda (piobpl) <piotrb10@gmail.com>
Pramodh KP (pramodhkp) <pramodh.p@directi.com> <1507241+pramodhkp@users.noreply.github.com>
Quentin Hibon <qh.public@yahoo.com>
Rahmi Pruitt <rjpruitt16@gmail.com>
Richard Hartmann <RichiH@users.noreply.github.com>
Robert Carosi (nov1n) <robert@carosi.nl>
Roberto Santalla <roobre@users.noreply.github.com>
Robin Schoonover <robin@cornhooves.org>
Roman Zaynetdinov (zaynetro) <romanznet@gmail.com>
Ross Smith II (rasa) <ross@smithii.com>
@@ -203,20 +241,23 @@ Ryan Sullivan (KayoticSully) <kayoticsully@gmail.com>
Sacheendra Talluri (sacheendra) <sacheendra.t@gmail.com>
Scott Klupfel (kluppy) <kluppy@going2blue.com>
Sergey Mishin (ralder) <ralder@yandex.ru>
Shaarad Dalvi <60266155+shaaraddalvi@users.noreply.github.com>
Simon Frei (imsodin) <freisim93@gmail.com>
Simon Mwepu <simonmwepu@gmail.com>
Sly_tom_cat <slytomcat@mail.ru>
Stefan Kuntz (Stefan-Code) <stefan.github@gmail.com> <Stefan.github@gmail.com>
Stefan Tatschner (rumpelsepp) <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org> <stefan@rumpelsepp.org>
Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
Suhas Gundimeda (snugghash) <suhas.gundimeda@gmail.com> <snugghash@gmail.com>
Taylor Khan (nelsonkhan) <nelsonkhan@gmail.com>
Thomas Hipp <thomashipp@gmail.com>
Tim Abell (timabell) <tim@timwise.co.uk>
Tim Howes (timhowes) <timhowes@berkeley.edu>
Tobias Klauser <tobias.klauser@gmail.com>
Tobias Nygren (tnn2) <tnn@nygren.pp.se>
Tobias Tom (tobiastom) <t.tom@succont.de>
Tom Jakubowski <tom@crystae.net>
Tomasz Wilczyński <5626656+tomasz1986@users.noreply.github.com>
Tomasz Wilczyński <5626656+tomasz1986@users.noreply.github.com> <twilczynski@naver.com>
Tommy Thorn <tommy-github-email@thorn.ws>
Tully Robinson (tojrobinson) <tully@tojr.org>
Tyler Brazier (tylerbrazier) <tyler@tylerbrazier.com>
@@ -225,10 +266,12 @@ Unrud (Unrud) <unrud@openaliasbox.org> <Unrud@users.noreply.github.com>
Veeti Paananen (veeti) <veeti.paananen@rojekti.fi>
Victor Buinsky (buinsky) <vix_booja@tut.by>
Vil Brekin (Vilbrekin) <vilbrekin@gmail.com>
Vladimir Rusinov <vrusinov@google.com>
Vladimir Rusinov <vrusinov@google.com> <vladimir.rusinov@gmail.com>
wangguoliang <liangcszzu@163.com>
William A. Kennington III (wkennington) <william@wkennington.com>
wouter bolsterlee <wouter@bolsterl.ee>
Wulf Weich (wweich) <wweich@users.noreply.github.com> <wweich@gmx.de> <wulf@weich-kr.de>
xarx00 <xarx00@users.noreply.github.com>
Xavier O. (damajor) <damajor@gmail.com>
xjtdy888 (xjtdy888) <xjtdy888@163.com>
Yannic A. (eipiminus1) <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>

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:

View File

@@ -1,4 +1,5 @@
FROM golang:1.13 AS builder
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
WORKDIR /src
COPY . .
@@ -10,11 +11,11 @@ RUN rm -f syncthing && go run build.go -no-upgrade build syncthing
FROM alpine
EXPOSE 8384 22000 21027/udp
EXPOSE 8384 22000/tcp 22000/udp 21027/udp
VOLUME ["/var/syncthing"]
RUN apk add --no-cache ca-certificates su-exec
RUN apk add --no-cache ca-certificates su-exec tzdata
COPY --from=builder /src/syncthing /bin/syncthing
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
@@ -22,7 +23,7 @@ COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/syncthing
HEALTHCHECK --interval=1m --timeout=10s \
CMD nc -z localhost 8384 || exit 1
CMD nc -z 127.0.0.1 8384 || exit 1
ENV STGUIADDRESS=0.0.0.0:8384
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/syncthing", "-home", "/var/syncthing/config"]

View File

@@ -1,13 +1,5 @@
# We will grab the Go compiler from the latest Go image.
FROM golang:1.13 as go
# Otherwise we base on the snapcraft container as that is by far the
# most complex and tricky thing to get installed and working...
FROM snapcore/snapcraft
# Go
COPY --from=go /usr/local/go /usr/local/go
ENV PATH="/usr/local/go/bin:$PATH"
ARG GOVERSION=latest
FROM golang:$GOVERSION
# FPM to build Debian packages
RUN apt-get update && apt-get install -y --no-install-recommends \

19
Dockerfile.buildx Normal file
View File

@@ -0,0 +1,19 @@
FROM alpine
ARG TARGETARCH
EXPOSE 8384 22000/tcp 22000/udp 21027/udp
VOLUME ["/var/syncthing"]
RUN apk add --no-cache ca-certificates su-exec tzdata
COPY ./syncthing-linux-$TARGETARCH /bin/syncthing
COPY ./script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/syncthing
HEALTHCHECK --interval=1m --timeout=10s \
CMD nc -z 127.0.0.1 8384 || exit 1
ENV STGUIADDRESS=0.0.0.0:8384
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/syncthing", "-home", "/var/syncthing/config"]

View File

@@ -1,4 +1,5 @@
FROM golang:1.13 AS builder
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
WORKDIR /src
COPY . .

View File

@@ -1,4 +1,5 @@
FROM golang:1.13 AS builder
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
WORKDIR /src
COPY . .

View File

@@ -7,17 +7,42 @@ Use the `/var/syncthing` volume to have the synchronized files available on the
host. You can add more folders and map them as you prefer.
Note that Syncthing runs as UID 1000 and GID 1000 by default. These may be
altered with the ``PUID`` and ``PGID`` environment variables.
altered with the ``PUID`` and ``PGID`` environment variables. In addition
the name of the Syncthing instance can be optionally defined by using
``--hostname=syncthing`` parameter.
## Example Usage
**Docker cli**
```
$ docker pull syncthing/syncthing
$ docker run -p 8384:8384 -p 22000:22000 \
$ 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
```
**Docker compose**
```
---
version: "3"
services:
syncthing:
image: syncthing/syncthing
container_name: syncthing
hostname: my-syncthing
environment:
- PUID=1000
- PGID=1000
volumes:
- /wherever/st-sync:/var/syncthing
ports:
- 8384:8384
- 22000:22000/tcp
- 22000:22000/udp
restart: unless-stopped
```
## Discovery
Note that local device discovery will not work with the above command,

View File

@@ -73,14 +73,13 @@ 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
Building Syncthing from source is easy, and there's a [guide][5]
Building Syncthing from source is easy, and there's [a guide][5]
that describes it for both Unix and Windows systems.
## Signed Releases
@@ -101,18 +100,16 @@ 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/master/etc
[4]: https://www.freenode.net/
[3]: https://github.com/syncthing/syncthing/blob/main/etc
[5]: https://docs.syncthing.net/dev/building.html
[6]: https://docs.syncthing.net/
[7]: https://github.com/syncthing/syncthing/blob/master/LICENSE
[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
[13]: https://github.com/syncthing/syncthing/blob/master/GOALS.md
[13]: https://github.com/syncthing/syncthing/blob/main/GOALS.md
[14]: assets/logo-text-128.png
[15]: https://syncthing.net/
[16]: https://github.com/syncthing/syncthing/blob/master/README-Docker.md
[16]: https://github.com/syncthing/syncthing/blob/main/README-Docker.md

568
build.go
View File

@@ -14,7 +14,6 @@ import (
"bytes"
"compress/flate"
"compress/gzip"
"crypto/sha256"
"encoding/json"
"errors"
"flag"
@@ -25,7 +24,6 @@ import (
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"regexp"
"runtime"
@@ -36,21 +34,26 @@ import (
)
var (
versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
goarch string
goos string
noupgrade bool
version string
goCmd string
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
debugBinary bool
coverage bool
timeout = "120s"
goarch string
goos string
noupgrade bool
version string
goCmd string
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
run string
benchRun string
debugBinary bool
coverage bool
long bool
timeout = "120s"
longTimeout = "600s"
numVersions = 5
withNextGenGUI = os.Getenv("BUILD_NEXT_GEN_GUI") != ""
)
type target struct {
@@ -58,12 +61,11 @@ type target struct {
debname string
debdeps []string
debpre string
debpost string
description string
buildPkgs []string
binaryName string
archiveFiles []archiveFile
systemdServices []string
systemdService string
installationFiles []archiveFile
tags []string
}
@@ -85,7 +87,6 @@ var targets = map[string]target{
name: "syncthing",
debname: "syncthing",
debdeps: []string{"libc6", "procps"},
debpost: "script/post-upgrade",
description: "Open Source Continuous File Synchronization",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/syncthing"},
binaryName: "syncthing", // .exe will be added automatically for Windows builds
@@ -96,6 +97,7 @@ var targets = map[string]target{
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
// All files from etc/ and extra/ added automatically in init().
},
systemdService: "syncthing@*.service",
installationFiles: []archiveFile{
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
{src: "README.md", dst: "deb/usr/share/doc/syncthing/README.txt", perm: 0644},
@@ -114,6 +116,7 @@ var targets = map[string]target{
{src: "etc/linux-systemd/system/syncthing@.service", dst: "deb/lib/systemd/system/syncthing@.service", perm: 0644},
{src: "etc/linux-systemd/system/syncthing-resume.service", dst: "deb/lib/systemd/system/syncthing-resume.service", perm: 0644},
{src: "etc/linux-systemd/user/syncthing.service", dst: "deb/usr/lib/systemd/user/syncthing.service", perm: 0644},
{src: "etc/linux-sysctl/30-syncthing.conf", dst: "deb/usr/lib/sysctl.d/30-syncthing.conf", perm: 0644},
{src: "etc/firewall-ufw/syncthing", dst: "deb/etc/ufw/applications.d/syncthing", perm: 0644},
{src: "etc/linux-desktop/syncthing-start.desktop", dst: "deb/usr/share/applications/syncthing-start.desktop", perm: 0644},
{src: "etc/linux-desktop/syncthing-ui.desktop", dst: "deb/usr/share/applications/syncthing-ui.desktop", perm: 0644},
@@ -139,9 +142,7 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdServices: []string{
"cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service",
},
systemdService: "cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service",
installationFiles: []archiveFile{
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
{src: "cmd/stdiscosrv/README.md", dst: "deb/usr/share/doc/syncthing-discosrv/README.txt", perm: 0644},
@@ -168,9 +169,7 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdServices: []string{
"cmd/strelaysrv/etc/linux-systemd/strelaysrv.service",
},
systemdService: "cmd/strelaysrv/etc/linux-systemd/strelaysrv.service",
installationFiles: []archiveFile{
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
{src: "cmd/strelaysrv/README.md", dst: "deb/usr/share/doc/syncthing-relaysrv/README.txt", perm: 0644},
@@ -204,19 +203,7 @@ 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 init() {
func initTargets() {
all := targets["all"]
pkgs, _ := filepath.Glob("cmd/*")
for _, pkg := range pkgs {
@@ -225,6 +212,9 @@ func init() {
// ignore dotfiles
continue
}
if noupgrade && pkg == "stupgrades" {
continue
}
all.buildPkgs = append(all.buildPkgs, fmt.Sprintf("github.com/syncthing/syncthing/cmd/%s", pkg))
}
targets["all"] = all
@@ -256,6 +246,8 @@ func main() {
}()
}
initTargets()
// Invoking build.go with no parameters at all builds everything (incrementally),
// which is what you want for maximum error checking during development.
if flag.NArg() == 0 {
@@ -278,29 +270,31 @@ func main() {
}
func runCommand(cmd string, target target) {
var tags []string
if noupgrade {
tags = []string{"noupgrade"}
}
tags = append(tags, strings.Fields(extraTags)...)
switch cmd {
case "install":
var tags []string
if noupgrade {
tags = []string{"noupgrade"}
}
tags = append(tags, strings.Fields(extraTags)...)
install(target, tags)
metalintShort()
case "build":
var tags []string
if noupgrade {
tags = []string{"noupgrade"}
}
tags = append(tags, strings.Fields(extraTags)...)
build(target, tags)
case "test":
test("github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
test(strings.Fields(extraTags), "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
case "bench":
bench("github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
bench(strings.Fields(extraTags), "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
case "integration":
integration(false)
case "integrationbench":
integration(true)
case "assets":
rebuildAssets()
@@ -308,6 +302,9 @@ func runCommand(cmd string, target target) {
case "proto":
proto()
case "testmocks":
testmocks()
case "translate":
translate()
@@ -315,17 +312,14 @@ func runCommand(cmd string, target target) {
transifex()
case "tar":
buildTar(target)
buildTar(target, tags)
case "zip":
buildZip(target)
buildZip(target, tags)
case "deb":
buildDeb(target)
case "snap":
buildSnap(target)
case "vet":
metalintShort()
@@ -338,6 +332,20 @@ func runCommand(cmd string, target target) {
case "version":
fmt.Println(getVersion())
case "changelog":
vers, err := currentAndLatestVersions(numVersions)
if err != nil {
log.Fatal(err)
}
for _, ver := range vers {
underline := strings.Repeat("=", len(ver))
msg, err := tagMessage(ver)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n%s\n\n%s\n\n", ver, underline, msg)
}
default:
log.Fatalf("Unknown command %q", cmd)
}
@@ -356,13 +364,25 @@ 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")
flag.BoolVar(&withNextGenGUI, "with-next-gen-gui", withNextGenGUI, "Also build 'newgui'")
flag.Parse()
}
func test(pkgs ...string) {
func test(tags []string, pkgs ...string) {
lazyRebuildAssets()
args := []string{"test", "-short", "-timeout", timeout, "-tags", "purego"}
tags = append(tags, "purego")
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 {
@@ -375,15 +395,56 @@ func test(pkgs ...string) {
args = append(args, "-covermode", "atomic", "-coverprofile", "coverage.txt", "-coverpkg", strings.Join(pkgs, ","))
}
args = append(args, runArgs()...)
runPrint(goCmd, append(args, pkgs...)...)
}
func bench(pkgs ...string) {
func bench(tags []string, pkgs ...string) {
lazyRebuildAssets()
runPrint(goCmd, append([]string{"test", "-run", "NONE", "-bench", "."}, pkgs...)...)
args := append([]string{"test", "-run", "NONE", "-tags", strings.Join(tags, " ")}, benchArgs()...)
runPrint(goCmd, append(args, pkgs...)...)
}
func integration(bench bool) {
lazyRebuildAssets()
args := []string{"test", "-v", "-timeout", "60m", "-tags"}
tags := "purego,integration"
if bench {
tags += ",benchmark"
}
args = append(args, tags)
args = append(args, runArgs()...)
if bench {
if run == "" {
args = append(args, "-run", "Benchmark")
}
args = append(args, benchArgs()...)
}
args = append(args, "./test")
fmt.Println(args)
runPrint(goCmd, args...)
}
func runArgs() []string {
if run == "" {
return nil
}
return []string{"-run", run}
}
func benchArgs() []string {
if benchRun == "" {
return []string{"-bench", "."}
}
return []string{"-bench", benchRun}
}
func install(target target, tags []string) {
if (target.name == "syncthing" || target.name == "") && !withNextGenGUI {
log.Println("Notice: Next generation GUI will not be built; see --with-next-gen-gui.")
}
lazyRebuildAssets()
tags = append(target.tags, tags...)
@@ -394,9 +455,7 @@ func install(target target, tags []string) {
}
os.Setenv("GOBIN", filepath.Join(cwd, "bin"))
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
os.Setenv("CC", cc)
setBuildEnvVars()
// On Windows generate a special file which the Go compiler will
// automatically use when generating Windows binaries to set things like
@@ -409,23 +468,22 @@ func install(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
for _, pkg := range target.buildPkgs {
args := []string{"install", "-v"}
args = appendParameters(args, tags, pkg)
runPrint(goCmd, args...)
}
args := []string{"install", "-v"}
args = appendParameters(args, tags, target.buildPkgs...)
runPrint(goCmd, args...)
}
func build(target target, tags []string) {
if (target.name == "syncthing" || target.name == "") && !withNextGenGUI {
log.Println("Notice: Next generation GUI will not be built; see --with-next-gen-gui.")
}
lazyRebuildAssets()
tags = append(target.tags, tags...)
rmr(target.BinaryName())
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
os.Setenv("CC", cc)
setBuildEnvVars()
// On Windows generate a special file which the Go compiler will
// automatically use when generating Windows binaries to set things like
@@ -442,15 +500,25 @@ func build(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
for _, pkg := range target.buildPkgs {
args := []string{"build", "-v"}
args = appendParameters(args, tags, pkg)
args := []string{"build", "-v"}
args = appendParameters(args, tags, target.buildPkgs...)
runPrint(goCmd, args...)
}
runPrint(goCmd, args...)
func setBuildEnvVars() {
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
os.Setenv("CC", cc)
if os.Getenv("CGO_ENABLED") == "" {
switch goos {
case "darwin", "solaris":
default:
os.Setenv("CGO_ENABLED", "0")
}
}
}
func appendParameters(args []string, tags []string, pkg string) []string {
func appendParameters(args []string, tags []string, pkgs ...string) []string {
if pkgdir != "" {
args = append(args, "-pkgdir", pkgdir)
}
@@ -466,26 +534,27 @@ func appendParameters(args []string, tags []string, pkg string) []string {
if !debugBinary {
// Regular binaries get version tagged and skip some debug symbols
args = append(args, "-ldflags", ldflags(path.Base(pkg)))
args = append(args, "-trimpath", "-ldflags", ldflags(tags))
} else {
// -gcflags to disable optimizations and inlining. Skip -ldflags
// because `Could not launch program: decoding dwarf section info at
// offset 0x0: too short` on 'dlv exec ...' see
// https://github.com/derekparker/delve/issues/79
args = append(args, "-gcflags", "-N -l")
// https://github.com/go-delve/delve/issues/79
args = append(args, "-gcflags", "all=-N -l")
}
return append(args, pkg)
return append(args, pkgs...)
}
func buildTar(target target) {
func buildTar(target target, tags []string) {
name := archiveName(target)
filename := name + ".tar.gz"
var tags []string
if noupgrade {
tags = []string{"noupgrade"}
name += "-noupgrade"
for _, tag := range tags {
if tag == "noupgrade" {
name += "-noupgrade"
break
}
}
build(target, tags)
@@ -501,14 +570,15 @@ func buildTar(target target) {
fmt.Println(filename)
}
func buildZip(target target) {
func buildZip(target target, tags []string) {
name := archiveName(target)
filename := name + ".zip"
var tags []string
if noupgrade {
tags = []string{"noupgrade"}
name += "-noupgrade"
for _, tag := range tags {
if tag == "noupgrade" {
name += "-noupgrade"
break
}
}
build(target, tags)
@@ -576,11 +646,13 @@ func buildDeb(target target) {
for _, dep := range target.debdeps {
args = append(args, "-d", dep)
}
for _, service := range target.systemdServices {
args = append(args, "--deb-systemd", service)
}
if target.debpost != "" {
args = append(args, "--after-upgrade", target.debpost)
if target.systemdService != "" {
debpost, err := createPostInstScript(target)
defer os.Remove(debpost)
if err != nil {
log.Fatal(err)
}
args = append(args, "--after-upgrade", debpost)
}
if target.debpre != "" {
args = append(args, "--before-install", target.debpre)
@@ -588,64 +660,55 @@ func buildDeb(target target) {
runPrint("fpm", args...)
}
func buildSnap(target target) {
os.RemoveAll("snap")
tmpl, err := template.ParseFiles("snapcraft.yaml.template")
func createPostInstScript(target target) (string, error) {
scriptname := filepath.Join("script", "deb-post-inst.template")
t, err := template.ParseFiles(scriptname)
if err != nil {
log.Fatal(err)
return "", err
}
f, err := os.Create("snapcraft.yaml")
defer f.Close()
scriptname = strings.TrimSuffix(scriptname, ".template")
w, err := os.Create(scriptname)
if err != nil {
log.Fatal(err)
return "", err
}
snaparch := goarch
if snaparch == "armhf" {
goarch = "arm"
} else if snaparch == "i386" {
goarch = "386"
defer w.Close()
if err = t.Execute(w, struct {
Service, Command string
}{
target.systemdService, target.binaryName,
}); err != nil {
return "", err
}
snapver := version
if strings.HasPrefix(snapver, "v") {
snapver = snapver[1:]
}
snapgrade := "devel"
if matched, _ := regexp.MatchString(`^\d+\.\d+\.\d+(-rc.\d+)?$`, snapver); matched {
snapgrade = "stable"
}
err = tmpl.Execute(f, map[string]string{
"Version": snapver,
"HostArchitecture": runtime.GOARCH,
"TargetArchitecture": snaparch,
"Grade": snapgrade,
})
if err != nil {
log.Fatal(err)
}
runPrint("snapcraft", "clean")
build(target, []string{"noupgrade"})
runPrint("snapcraft")
return scriptname, nil
}
func shouldBuildSyso(dir string) (string, error) {
type M map[string]interface{}
major, minor, patch, build := semanticVersion()
version := getVersion()
version = strings.TrimPrefix(version, "v")
major, minor, patch := semanticVersion()
bs, err := json.Marshal(M{
"FixedFileInfo": M{
"FileVersion": M{
"Major": major,
"Minor": minor,
"Patch": patch,
"Build": build,
},
"ProductVersion": M{
"Major": major,
"Minor": minor,
"Patch": patch,
},
},
"StringFileInfo": M{
"FileDescription": "Open Source Continuous File Synchronization",
"LegalCopyright": "The Syncthing Authors",
"ProductVersion": getVersion(),
"ProductName": "Syncthing",
"CompanyName": "The Syncthing Authors",
"FileDescription": "Syncthing - Open Source Continuous File Synchronization",
"FileVersion": version,
"InternalName": "syncthing",
"LegalCopyright": "The Syncthing Authors",
"OriginalFilename": "syncthing",
"ProductName": "Syncthing",
"ProductVersion": version,
},
"IconPath": "assets/logo.ico",
})
@@ -732,15 +795,50 @@ func listFiles(dir string) []string {
func rebuildAssets() {
os.Setenv("SOURCE_DATE_EPOCH", fmt.Sprint(buildStamp()))
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/lib/auto", "github.com/syncthing/syncthing/cmd/strelaypoolsrv/auto")
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/lib/api/auto", "github.com/syncthing/syncthing/cmd/strelaypoolsrv/auto")
}
func lazyRebuildAssets() {
if shouldRebuildAssets("lib/auto/gui.files.go", "gui") || shouldRebuildAssets("cmd/strelaypoolsrv/auto/gui.files.go", "cmd/strelaypoolsrv/auto/gui") {
shouldRebuild := shouldRebuildAssets("lib/api/auto/gui.files.go", "gui") ||
shouldRebuildAssets("cmd/strelaypoolsrv/auto/gui.files.go", "cmd/strelaypoolsrv/gui")
if withNextGenGUI {
shouldRebuild = buildNextGenGUI() || shouldRebuild
}
if shouldRebuild {
rebuildAssets()
}
}
func buildNextGenGUI() bool {
// Check if we need to run the npm process, and if so also set the flag
// to rebuild Go assets afterwards. The index.html is regenerated every
// time by the build process. This assumes the new GUI ends up in
// next-gen-gui/dist/next-gen-gui.
if !shouldRebuildAssets("gui/next-gen-gui/index.html", "next-gen-gui") {
// The GUI is up to date.
return false
}
runPrintInDir("next-gen-gui", "npm", "install")
runPrintInDir("next-gen-gui", "npm", "run", "build", "--", "--prod", "--subresource-integrity")
rmr("gui/tech-ui")
for _, src := range listFiles("next-gen-gui/dist") {
rel, _ := filepath.Rel("next-gen-gui/dist", src)
dst := filepath.Join("gui", rel)
if err := copyFile(src, dst, 0644); err != nil {
fmt.Println("copy:", err)
os.Exit(1)
}
}
return true
}
func shouldRebuildAssets(target, srcdir string) bool {
info, err := os.Stat(target)
if err != nil {
@@ -769,22 +867,35 @@ 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")
}
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/stdiscosrv")
runPrintInDir(path, "git", "checkout", pv)
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/cmd/stdiscosrv")
runPrint(goCmd, "generate", "proto/generate.go")
}
func testmocks() {
args := []string{
"generate",
"github.com/syncthing/syncthing/lib/config",
"github.com/syncthing/syncthing/lib/connections",
"github.com/syncthing/syncthing/lib/discover",
"github.com/syncthing/syncthing/lib/events",
"github.com/syncthing/syncthing/lib/logger",
"github.com/syncthing/syncthing/lib/model",
"github.com/syncthing/syncthing/lib/protocol",
}
runPrint(goCmd, args...)
}
func translate() {
@@ -803,14 +914,14 @@ func transifex() {
runPrint(goCmd, "run", "../../../../script/transifexdl.go")
}
func ldflags(program string) string {
func ldflags(tags []string) string {
b := new(strings.Builder)
b.WriteString("-w")
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Version=%s", version)
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Stamp=%d", buildStamp())
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.User=%s", buildUser())
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Host=%s", buildHost())
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Program=%s", program)
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Tags=%s", strings.Join(tags, ","))
if v := os.Getenv("EXTRA_LDFLAGS"); v != "" {
fmt.Fprintf(b, " %s", v)
}
@@ -835,15 +946,39 @@ func getReleaseVersion() (string, error) {
}
func getGitVersion() (string, error) {
v, err := runError("git", "describe", "--always", "--dirty")
// The current version as Git sees it
bs, err := runError("git", "describe", "--always", "--dirty", "--abbrev=8")
if err != nil {
return "", err
}
v = versionRe.ReplaceAllFunc(v, func(s []byte) []byte {
s[0] = '+'
return s
})
return string(v), nil
vcur := string(bs)
// The closest current tag name
bs, err = runError("git", "describe", "--always", "--abbrev=0")
if err != nil {
return "", err
}
v0 := string(bs)
// To be more semantic-versionish and ensure proper ordering in our
// upgrade process, we make sure there's only one hypen in the version.
versionRe := regexp.MustCompile(`-([0-9]{1,3}-g[0-9a-f]{5,10}(-dirty)?)`)
if m := versionRe.FindStringSubmatch(vcur); len(m) > 0 {
suffix := strings.ReplaceAll(m[1], "-", ".")
if strings.Contains(v0, "-") {
// We're based of a tag with a prerelease string. We can just
// add our dev stuff directly.
return fmt.Sprintf("%s.dev.%s", v0, suffix), nil
}
// We're based on a release version. We need to bump the patch
// version and then add a -dev prerelease string.
next := nextPatchVersion(v0)
return fmt.Sprintf("%s-dev.%s", next, suffix), nil
}
return vcur, nil
}
func getVersion() string {
@@ -864,22 +999,18 @@ func getVersion() string {
return "unknown-dev"
}
func semanticVersion() (major, minor, patch, build int) {
r := regexp.MustCompile(`v(?P<Major>\d+)\.(?P<Minor>\d+).(?P<Patch>\d+).*\+(?P<CommitsAhead>\d+)`)
func semanticVersion() (major, minor, patch int) {
r := regexp.MustCompile(`v(\d+)\.(\d+).(\d+)`)
matches := r.FindStringSubmatch(getVersion())
if len(matches) != 5 {
return 0, 0, 0, 0
if len(matches) != 4 {
return 0, 0, 0
}
var ints [4]int
for i := 1; i < 5; i++ {
value, err := strconv.Atoi(matches[i])
if err != nil {
return 0, 0, 0, 0
}
ints[i-1] = value
var ints [3]int
for i, s := range matches[1:] {
ints[i], _ = strconv.Atoi(s)
}
return ints[0], ints[1], ints[2], ints[3]
return ints[0], ints[1], ints[2]
}
func getBranchSuffix() string {
@@ -918,7 +1049,7 @@ func getBranchSuffix() string {
branch = parts[len(parts)-1]
switch branch {
case "master", "release":
case "master", "release", "main":
// these are not special
return ""
}
@@ -1194,7 +1325,7 @@ func macosCodesign(file string) {
}
if id := os.Getenv("CODESIGN_IDENTITY"); id != "" {
bs, err := runError("codesign", "-s", id, file)
bs, err := runError("codesign", "--options=runtime", "-s", id, file)
if err != nil {
log.Println("Codesign: signing failed:", string(bs))
return
@@ -1250,32 +1381,6 @@ func metalintShort() {
runPrint(goCmd, "test", "-short", "-run", "Metalint", "./meta")
}
func temporaryBuildDir() (string, error) {
// The base of our temp dir is "syncthing-xxxxxxxx" where the x:es
// are eight bytes from the sha256 of our working directory. We do
// this because we want a name in the global temp dir that doesn't
// conflict with someone else building syncthing on the same
// machine, yet is persistent between runs from the same source
// directory.
wd, err := os.Getwd()
if err != nil {
return "", err
}
hash := sha256.Sum256([]byte(wd))
base := fmt.Sprintf("syncthing-%x", hash[:4])
// The temp dir is taken from $STTMPDIR if set, otherwise the system
// default (potentially infrluenced by $TMPDIR on unixes).
var tmpDir string
if t := os.Getenv("STTMPDIR"); t != "" {
tmpDir = t
} else {
tmpDir = os.TempDir()
}
return filepath.Join(tmpDir, base), nil
}
func (t target) BinaryName() string {
if goos == "windows" {
return t.binaryName + ".exe"
@@ -1290,3 +1395,70 @@ func protobufVersion() string {
}
return string(bs)
}
func currentAndLatestVersions(n int) ([]string, error) {
bs, err := runError("git", "tag", "--sort", "taggerdate")
if err != nil {
return nil, err
}
lines := strings.Split(string(bs), "\n")
reverseStrings(lines)
// The one at the head is the latest version. We always keep that one.
// Then we filter out remaining ones with dashes (pre-releases etc).
latest := lines[:1]
nonPres := filterStrings(lines[1:], func(s string) bool { return !strings.Contains(s, "-") })
vers := append(latest, nonPres...)
return vers[:n], nil
}
func reverseStrings(ss []string) {
for i := 0; i < len(ss)/2; i++ {
ss[i], ss[len(ss)-1-i] = ss[len(ss)-1-i], ss[i]
}
}
func filterStrings(ss []string, op func(string) bool) []string {
n := ss[:0]
for _, s := range ss {
if op(s) {
n = append(n, s)
}
}
return n
}
func tagMessage(tag string) (string, error) {
hash, err := runError("git", "rev-parse", tag)
if err != nil {
return "", err
}
obj, err := runError("git", "cat-file", "-p", string(hash))
if err != nil {
return "", err
}
return trimTagMessage(string(obj), tag), nil
}
func trimTagMessage(msg, tag string) string {
firstBlank := strings.Index(msg, "\n\n")
if firstBlank > 0 {
msg = msg[firstBlank+2:]
}
msg = strings.TrimPrefix(msg, tag)
beginSig := strings.Index(msg, "-----BEGIN PGP")
if beginSig > 0 {
msg = msg[:beginSig]
}
return strings.TrimSpace(msg)
}
func nextPatchVersion(ver string) string {
parts := strings.SplitN(ver, "-", 2)
digits := strings.Split(parts[0], ".")
n, _ := strconv.Atoi(digits[len(digits)-1])
digits[len(digits)-1] = strconv.Itoa(n + 1)
return strings.Join(digits, ".")
}

20
build.ps1 Normal file
View File

@@ -0,0 +1,20 @@
function build {
go run build.go @args
}
$cmd, $rest = $args
switch ($cmd) {
"test" {
$env:LOGGER_DISCARD=1
build test
}
"bench" {
$env:LOGGER_DISCARD=1
build bench
}
default {
build @rest
}
}

View File

@@ -2,8 +2,6 @@
set -euo pipefail
IFS=$'\n\t'
STTRACE=${STTRACE:-}
script() {
name="$1"
shift
@@ -15,88 +13,23 @@ build() {
}
case "${1:-default}" in
default)
build
;;
clean)
build "$@"
;;
tar)
build "$@"
;;
assets)
build "$@"
;;
xdr)
build "$@"
;;
translate)
build "$@"
;;
deb)
build "$@"
;;
setup)
build "$@"
;;
test)
LOGGER_DISCARD=1 build test
;;
bench)
LOGGER_DISCARD=1 build bench | script benchfilter
LOGGER_DISCARD=1 build bench
;;
prerelease)
go run script/authors.go
script authors
build transifex
pushd man ; ./refresh.sh ; popd
git add -A gui man AUTHORS
git commit -m 'gui, man, authors: Update docs, translations, and contributors'
;;
noupgrade)
build -no-upgrade tar
;;
all)
platforms=(
darwin-amd64 dragonfly-amd64 freebsd-amd64 linux-amd64 netbsd-amd64 openbsd-amd64 solaris-amd64 windows-amd64
freebsd-386 linux-386 netbsd-386 openbsd-386 windows-386
linux-arm linux-arm64 linux-ppc64 linux-ppc64le
)
for plat in "${platforms[@]}"; do
echo Building "$plat"
goos="${plat%-*}"
goarch="${plat#*-}"
dist="tar"
if [[ $goos == "windows" ]]; then
dist="zip"
fi
build -goos "$goos" -goarch "$goarch" "$dist"
echo
done
;;
test-xunit)
(GOPATH="$(pwd)/Godeps/_workspace:$GOPATH" go test -v -race ./lib/... ./cmd/... || true) > tests.out
go2xunit -output tests.xml -fail < tests.out
;;
*)
echo "Unknown build command $1"
build "$@"
;;
esac

View File

@@ -1,96 +0,0 @@
// Copyright (C) 2019 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 main
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"strings"
"github.com/syncthing/syncthing/lib/config"
)
type APIClient struct {
http.Client
cfg config.GUIConfiguration
apikey string
}
func getClient(cfg config.GUIConfiguration) *APIClient {
httpClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(cfg.Network(), cfg.Address())
},
},
}
return &APIClient{
Client: httpClient,
cfg: cfg,
apikey: cfg.APIKey,
}
}
func (c *APIClient) Endpoint() string {
if c.cfg.Network() == "unix" {
return "http://unix/"
}
url := c.cfg.URL()
if !strings.HasSuffix(url, "/") {
url += "/"
}
return url
}
func (c *APIClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-API-Key", c.apikey)
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
}
return resp, checkResponse(resp)
}
func (c *APIClient) Get(url string) (*http.Response, error) {
request, err := http.NewRequest("GET", c.Endpoint()+"rest/"+url, nil)
if err != nil {
return nil, err
}
return c.Do(request)
}
func (c *APIClient) Post(url, body string) (*http.Response, error) {
request, err := http.NewRequest("POST", c.Endpoint()+"rest/"+url, bytes.NewBufferString(body))
if err != nil {
return nil, err
}
return c.Do(request)
}
func checkResponse(response *http.Response) error {
if response.StatusCode == 404 {
return errors.New("invalid endpoint or API call")
} else if response.StatusCode == 403 {
return errors.New("invalid API key")
} else if response.StatusCode != 200 {
data, err := responseToBArray(response)
if err != nil {
return err
}
body := strings.TrimSpace(string(data))
return fmt.Errorf("unexpected HTTP status returned: %s\n%s", response.Status, body)
}
return nil
}

View File

@@ -1,192 +0,0 @@
// Copyright (C) 2019 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 main
import (
"bufio"
"crypto/tls"
"encoding/json"
"flag"
"log"
"os"
"reflect"
"github.com/AudriusButkevicius/recli"
"github.com/flynn-archive/go-shlex"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/urfave/cli"
)
func main() {
// This is somewhat a hack around a chicken and egg problem.
// We need to set the home directory and potentially other flags to know where the syncthing instance is running
// in order to get it's config ... which we then use to construct the actual CLI ... at which point it's too late
// to add flags there...
homeBaseDir := locations.GetBaseDir(locations.ConfigBaseDir)
guiCfg := config.GUIConfiguration{}
flags := flag.NewFlagSet("", flag.ContinueOnError)
flags.StringVar(&guiCfg.RawAddress, "gui-address", guiCfg.RawAddress, "Override GUI address (e.g. \"http://192.0.2.42:8443\")")
flags.StringVar(&guiCfg.APIKey, "gui-apikey", guiCfg.APIKey, "Override GUI API key")
flags.StringVar(&homeBaseDir, "home", homeBaseDir, "Set configuration directory")
// Implement the same flags at the lower CLI, with the same default values (pre-parse), but do nothing with them.
// This is so that we could reuse os.Args
fakeFlags := []cli.Flag{
cli.StringFlag{
Name: "gui-address",
Value: guiCfg.RawAddress,
Usage: "Override GUI address (e.g. \"http://192.0.2.42:8443\")",
},
cli.StringFlag{
Name: "gui-apikey",
Value: guiCfg.APIKey,
Usage: "Override GUI API key",
},
cli.StringFlag{
Name: "home",
Value: homeBaseDir,
Usage: "Set configuration directory",
},
}
// Do not print usage of these flags, and ignore errors as this can't understand plenty of things
flags.Usage = func() {}
_ = flags.Parse(os.Args[1:])
// Now if the API key and address is not provided (we are not connecting to a remote instance),
// try to rip it out of the config.
if guiCfg.RawAddress == "" && guiCfg.APIKey == "" {
// Update the base directory
err := locations.SetBaseDir(locations.ConfigBaseDir, homeBaseDir)
if err != nil {
log.Fatal(errors.Wrap(err, "setting home"))
}
// Load the certs and get the ID
cert, err := tls.LoadX509KeyPair(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
)
if err != nil {
log.Fatal(errors.Wrap(err, "reading device ID"))
}
myID := protocol.NewDeviceID(cert.Certificate[0])
// Load the config
cfg, err := config.Load(locations.Get(locations.ConfigFile), myID, events.NoopLogger)
if err != nil {
log.Fatalln(errors.Wrap(err, "loading config"))
}
guiCfg = cfg.GUI()
} else if guiCfg.Address() == "" || guiCfg.APIKey == "" {
log.Fatalln("Both -gui-address and -gui-apikey should be specified")
}
if guiCfg.Address() == "" {
log.Fatalln("Could not find GUI Address")
}
if guiCfg.APIKey == "" {
log.Fatalln("Could not find GUI API key")
}
client := getClient(guiCfg)
cfg, err := getConfig(client)
original := cfg.Copy()
if err != nil {
log.Fatalln(errors.Wrap(err, "getting config"))
}
// Copy the config and set the default flags
recliCfg := recli.DefaultConfig
recliCfg.IDTag.Name = "xml"
recliCfg.SkipTag.Name = "json"
commands, err := recli.New(recliCfg).Construct(&cfg)
if err != nil {
log.Fatalln(errors.Wrap(err, "config reflect"))
}
// Construct the actual CLI
app := cli.NewApp()
app.Name = "stcli"
app.HelpName = app.Name
app.Author = "The Syncthing Authors"
app.Usage = "Syncthing command line interface"
app.Version = build.Version
app.Flags = fakeFlags
app.Metadata = map[string]interface{}{
"client": client,
}
app.Commands = []cli.Command{
{
Name: "config",
HideHelp: true,
Usage: "Configuration modification command group",
Subcommands: commands,
},
showCommand,
operationCommand,
errorsCommand,
}
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 {
log.Fatalln(errors.Wrap(err, "parsing input"))
}
if len(input) == 0 {
continue
}
err = app.Run(append(os.Args, input...))
if err != nil {
log.Fatalln(err)
}
}
err = scanner.Err()
if err != nil {
log.Fatalln(err)
}
} else {
err = app.Run(os.Args)
if err != nil {
log.Fatalln(err)
}
}
if !reflect.DeepEqual(cfg, original) {
body, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
log.Fatalln(err)
}
resp, err := client.Post("system/config", string(body))
if err != nil {
log.Fatalln(err)
}
if resp.StatusCode != 200 {
body, err := responseToBArray(resp)
if err != nil {
log.Fatalln(err)
}
log.Fatalln(string(body))
}
}
}

View File

@@ -7,7 +7,6 @@
package main
import (
"crypto/md5"
"errors"
"flag"
"fmt"
@@ -15,6 +14,8 @@ import (
"log"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/sha256"
)
func main() {
@@ -74,7 +75,7 @@ type fileInfo struct {
name string
mode os.FileMode
mod int64
hash [16]byte
hash [sha256.Size]byte
}
func (f fileInfo) String() string {
@@ -106,11 +107,7 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
if err != nil {
return err
}
h := md5.New()
h.Write([]byte(tgt))
hash := h.Sum(nil)
copy(f.hash[:], hash)
f.hash = sha256.Sum256([]byte(tgt))
} else if info.IsDir() {
f = fileInfo{
name: rn,
@@ -123,7 +120,7 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
mode: info.Mode(),
mod: info.ModTime().Unix(),
}
sum, err := md5file(path)
sum, err := sha256file(path)
if err != nil {
return err
}
@@ -150,14 +147,14 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
return errc
}
func md5file(fname string) (hash [16]byte, err error) {
func sha256file(fname string) (hash [sha256.Size]byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
h := md5.New()
h := sha256.New()
io.Copy(h, f)
hb := h.Sum(nil)
copy(hash[:], hb)

119
cmd/stcrashreceiver/main.go Normal file
View File

@@ -0,0 +1,119 @@
// Copyright (C) 2019 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/.
// Command stcrashreceiver is a trivial HTTP server that allows two things:
//
// - uploading files (crash reports) named like a SHA256 hash using a PUT request
// - checking whether such file exists using a HEAD request
//
// Typically this should be deployed behind something that manages HTTPS.
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"time"
"github.com/syncthing/syncthing/lib/sha256"
"github.com/syncthing/syncthing/lib/ur"
raven "github.com/getsentry/raven-go"
)
const maxRequestSize = 1 << 20 // 1 MiB
func main() {
dir := flag.String("dir", ".", "Directory to store reports in")
dsn := flag.String("dsn", "", "Sentry DSN")
listen := flag.String("listen", ":22039", "HTTP listen address")
flag.Parse()
mux := http.NewServeMux()
cr := &crashReceiver{
dir: *dir,
dsn: *dsn,
}
mux.Handle("/", cr)
if *dsn != "" {
mux.HandleFunc("/newcrash/failure", handleFailureFn(*dsn))
}
log.SetOutput(os.Stdout)
if err := http.ListenAndServe(*listen, mux); err != nil {
log.Fatalln("HTTP serve:", err)
}
}
func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request) {
return func(w http.ResponseWriter, req *http.Request) {
lr := io.LimitReader(req.Body, maxRequestSize)
bs, err := ioutil.ReadAll(lr)
req.Body.Close()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
var reports []ur.FailureReport
err = json.Unmarshal(bs, &reports)
if err != nil {
http.Error(w, err.Error(), 400)
return
}
if len(reports) == 0 {
// Shouldn't happen
log.Printf("Got zero failure reports")
return
}
version, err := parseVersion(reports[0].Version)
if err != nil {
http.Error(w, err.Error(), 400)
return
}
for _, r := range reports {
pkt := packet(version, "failure")
pkt.Message = r.Description
pkt.Extra = raven.Extra{
"count": r.Count,
}
message := sanitizeMessageLDB(r.Description)
pkt.Fingerprint = []string{message}
if err := sendReport(dsn, pkt, userIDFor(req)); err != nil {
log.Println("Failed to send failure report:", err)
} else {
log.Println("Sent failure report:", r.Description)
}
}
}
}
// userIDFor returns a string we can use as the user ID for the purpose of
// counting affected users. It's the truncated hash of a salt, the user
// remote IP, and the current month.
func userIDFor(req *http.Request) string {
addr := req.RemoteAddr
if fwd := req.Header.Get("x-forwarded-for"); fwd != "" {
addr = fwd
}
if host, _, err := net.SplitHostPort(addr); err == nil {
addr = host
}
now := time.Now().Format("200601")
salt := "stcrashreporter"
hash := sha256.Sum256([]byte(salt + addr + now))
return fmt.Sprintf("%x", hash[:8])
}

View File

@@ -31,17 +31,15 @@ var (
clientsMut sync.Mutex
)
func sendReport(dsn, path string, report []byte) error {
pkt, err := parseReport(path, report)
if err != nil {
return err
}
func sendReport(dsn string, pkt *raven.Packet, userID string) error {
pkt.Interfaces = append(pkt.Interfaces, &raven.User{ID: userID})
clientsMut.Lock()
defer clientsMut.Unlock()
cli, ok := clients[dsn]
if !ok {
var err error
cli, err = raven.New(dsn)
if err != nil {
return err
@@ -60,7 +58,7 @@ func sendReport(dsn, path string, report []byte) error {
return <-errC
}
func parseReport(path string, report []byte) (*raven.Packet, error) {
func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
parts := bytes.SplitN(report, []byte("\n"), 2)
if len(parts) != 2 {
return nil, errors.New("no first line")
@@ -109,7 +107,7 @@ func parseReport(path string, report []byte) (*raven.Packet, error) {
loader.LockWithVersion(version.tag)
} else {
// Last resort
loader.LockWithVersion("master")
loader.LockWithVersion("main")
}
defer loader.Unlock()
@@ -124,44 +122,68 @@ func parseReport(path string, report []byte) (*raven.Packet, error) {
}
}
pkt := &raven.Packet{
Message: string(subjectLine),
Platform: "go",
Release: version.tag,
Environment: version.environment(),
Tags: raven.Tags{
raven.Tag{Key: "version", Value: version.version},
raven.Tag{Key: "tag", Value: version.tag},
raven.Tag{Key: "codename", Value: version.codename},
raven.Tag{Key: "runtime", Value: version.runtime},
raven.Tag{Key: "goos", Value: version.goos},
raven.Tag{Key: "goarch", Value: version.goarch},
raven.Tag{Key: "builder", Value: version.builder},
},
Extra: raven.Extra{
"url": reportServer + path,
},
Interfaces: []raven.Interface{&trace},
}
if version.commit != "" {
pkt.Tags = append(pkt.Tags, raven.Tag{Key: "commit", Value: version.commit})
pkt := packet(version, "crash")
pkt.Message = string(subjectLine)
pkt.Extra = raven.Extra{
"url": reportServer + path,
}
pkt.Interfaces = []raven.Interface{&trace}
pkt.Fingerprint = crashReportFingerprint(pkt.Message)
return pkt, nil
}
// syncthing v1.1.4-rc.1+30-g6aaae618-dirty-crashrep "Erbium Earthworm" (go1.12.5 darwin-amd64) jb@kvin.kastelo.net 2019-05-23 16:08:14 UTC
var longVersionRE = regexp.MustCompile(`syncthing\s+(v[^\s]+)\s+"([^"]+)"\s\(([^\s]+)\s+([^-]+)-([^)]+)\)\s+([^\s]+)`)
var (
indexRe = regexp.MustCompile(`\[[-:0-9]+\]`)
sizeRe = regexp.MustCompile(`(length|capacity) [0-9]+`)
ldbPosRe = regexp.MustCompile(`(\(pos=)([0-9]+)\)`)
ldbChecksumRe = regexp.MustCompile(`(want=0x)([a-z0-9]+)( got=0x)([a-z0-9]+)`)
ldbFileRe = regexp.MustCompile(`(\[file=)([0-9]+)(\.ldb\])`)
ldbInternalKeyRe = regexp.MustCompile(`(internal key ")[^"]+(", len=)[0-9]+`)
ldbPathRe = regexp.MustCompile(`(open|write|read) .+[\\/].+[\\/]index[^\\/]+[\\/][^\\/]+: `)
)
func sanitizeMessageLDB(message string) string {
message = ldbPosRe.ReplaceAllString(message, "${1}x)")
message = ldbFileRe.ReplaceAllString(message, "${1}x${3}")
message = ldbChecksumRe.ReplaceAllString(message, "${1}X${3}X")
message = ldbInternalKeyRe.ReplaceAllString(message, "${1}x${2}x")
message = ldbPathRe.ReplaceAllString(message, "$1 x: ")
return message
}
func crashReportFingerprint(message string) []string {
// Do not fingerprint on the stack in case of db corruption or fatal
// db io error - where it occurs doesn't matter.
orig := message
message = sanitizeMessageLDB(message)
if message != orig {
return []string{message}
}
message = indexRe.ReplaceAllString(message, "[x]")
message = sizeRe.ReplaceAllString(message, "$1 x")
// {{ default }} is what sentry uses as a fingerprint by default. While
// never specified, the docs point at this being some hash derived from the
// stack trace. Here we include the filtered panic message on top of that.
// https://docs.sentry.io/platforms/go/data-management/event-grouping/sdk-fingerprinting/#basic-example
return []string{"{{ default }}", message}
}
// syncthing v1.1.4-rc.1+30-g6aaae618-dirty-crashrep "Erbium Earthworm" (go1.12.5 darwin-amd64) jb@kvin.kastelo.net 2019-05-23 16:08:14 UTC [foo, bar]
var longVersionRE = regexp.MustCompile(`syncthing\s+(v[^\s]+)\s+"([^"]+)"\s\(([^\s]+)\s+([^-]+)-([^)]+)\)\s+([^\s]+)[^\[]*(?:\[(.+)\])?$`)
type version struct {
version string // "v1.1.4-rc.1+30-g6aaae618-dirty-crashrep"
tag string // "v1.1.4-rc.1"
commit string // "6aaae618", blank when absent
codename string // "Erbium Earthworm"
runtime string // "go1.12.5"
goos string // "darwin"
goarch string // "amd64"
builder string // "jb@kvin.kastelo.net"
version string // "v1.1.4-rc.1+30-g6aaae618-dirty-crashrep"
tag string // "v1.1.4-rc.1"
commit string // "6aaae618", blank when absent
codename string // "Erbium Earthworm"
runtime string // "go1.12.5"
goos string // "darwin"
goarch string // "amd64"
builder string // "jb@kvin.kastelo.net"
extra []string // "foo", "bar"
}
func (v version) environment() string {
@@ -191,6 +213,7 @@ func parseVersion(line string) (version, error) {
goarch: m[5],
builder: m[6],
}
parts := strings.Split(v.version, "+")
v.tag = parts[0]
if len(parts) > 1 {
@@ -200,5 +223,38 @@ func parseVersion(line string) (version, error) {
}
}
if len(m) >= 8 && m[7] != "" {
tags := strings.Split(m[7], ",")
for i := range tags {
tags[i] = strings.TrimSpace(tags[i])
}
v.extra = tags
}
return v, nil
}
func packet(version version, reportType string) *raven.Packet {
pkt := &raven.Packet{
Platform: "go",
Release: version.tag,
Environment: version.environment(),
Tags: raven.Tags{
raven.Tag{Key: "version", Value: version.version},
raven.Tag{Key: "tag", Value: version.tag},
raven.Tag{Key: "codename", Value: version.codename},
raven.Tag{Key: "runtime", Value: version.runtime},
raven.Tag{Key: "goos", Value: version.goos},
raven.Tag{Key: "goarch", Value: version.goarch},
raven.Tag{Key: "builder", Value: version.builder},
raven.Tag{Key: "report_type", Value: reportType},
},
}
if version.commit != "" {
pkt.Tags = append(pkt.Tags, raven.Tag{Key: "commit", Value: version.commit})
}
for _, tag := range version.extra {
pkt.Tags = append(pkt.Tags, raven.Tag{Key: tag, Value: "1"})
}
return pkt
}

View File

@@ -30,16 +30,30 @@ func TestParseVersion(t *testing.T) {
builder: "jb@kvin.kastelo.net",
},
},
{
longVersion: `syncthing v1.1.4-rc.1+30-g6aaae618-dirty-crashrep "Erbium Earthworm" (go1.12.5 darwin-amd64) jb@kvin.kastelo.net 2019-05-23 16:08:14 UTC [foo, bar]`,
parsed: version{
version: "v1.1.4-rc.1+30-g6aaae618-dirty-crashrep",
tag: "v1.1.4-rc.1",
commit: "6aaae618",
codename: "Erbium Earthworm",
runtime: "go1.12.5",
goos: "darwin",
goarch: "amd64",
builder: "jb@kvin.kastelo.net",
extra: []string{"foo", "bar"},
},
},
}
for _, tc := range cases {
v, err := parseVersion(tc.longVersion)
if err != nil {
t.Error(err)
t.Errorf("%s\nerror: %v\n", tc.longVersion, err)
continue
}
if v != tc.parsed {
t.Error(v)
if fmt.Sprint(v) != fmt.Sprint(tc.parsed) {
t.Errorf("%s\nA: %v\nE: %v\n", tc.longVersion, v, tc.parsed)
}
}
}
@@ -50,7 +64,7 @@ func TestParseReport(t *testing.T) {
t.Fatal(err)
}
pkt, err := parseReport("1/2/345", bs)
pkt, err := parseCrashReport("1/2/345", bs)
if err != nil {
t.Fatal(err)
}
@@ -62,3 +76,66 @@ func TestParseReport(t *testing.T) {
fmt.Printf("%s\n", bs)
}
func TestCrashReportFingerprint(t *testing.T) {
cases := []struct {
message, exp string
ldb bool
}{
{
message: "panic: leveldb/table: corruption on data-block (pos=51308946): checksum mismatch, want=0xa89f9aa0 got=0xd27cc4c7 [file=004003.ldb]",
exp: "panic: leveldb/table: corruption on data-block (pos=x): checksum mismatch, want=0xX got=0xX [file=x.ldb]",
ldb: true,
},
{
message: "panic: leveldb/table: corruption on table-footer (pos=248): bad magic number [file=001370.ldb]",
exp: "panic: leveldb/table: corruption on table-footer (pos=x): bad magic number [file=x.ldb]",
ldb: true,
},
{
message: "panic: runtime error: slice bounds out of range [4294967283:4194304]",
exp: "panic: runtime error: slice bounds out of range [x]",
},
{
message: "panic: runtime error: slice bounds out of range [-2:]",
exp: "panic: runtime error: slice bounds out of range [x]",
},
{
message: "panic: runtime error: slice bounds out of range [:4294967283] with capacity 32768",
exp: "panic: runtime error: slice bounds out of range [x] with capacity x",
},
{
message: "panic: runtime error: index out of range [0] with length 0",
exp: "panic: runtime error: index out of range [x] with length x",
},
{
message: `panic: leveldb: internal key "\x01", len=1: invalid length`,
exp: `panic: leveldb: internal key "x", len=x: invalid length`,
ldb: true,
},
{
message: `panic: write /var/syncthing/config/index-v0.14.0.db/2732813.log: cannot allocate memory`,
exp: `panic: write x: cannot allocate memory`,
ldb: true,
},
{
message: `panic: filling Blocks: read C:\Users\Serv-Resp-Tizayuca\AppData\Local\Syncthing\index-v0.14.0.db\006561.ldb: Error de datos (comprobación de redundancia cíclica).`,
exp: `panic: filling Blocks: read x: Error de datos (comprobación de redundancia cíclica).`,
ldb: true,
},
}
for i, tc := range cases {
fingerprint := crashReportFingerprint(tc.message)
expLen := 2
if tc.ldb {
expLen = 1
}
if l := len(fingerprint); l != expLen {
t.Errorf("tc %v: Unexpected fingerprint length: %v != %v", i, l, expLen)
} else if msg := fingerprint[expLen-1]; msg != tc.exp {
t.Errorf("tc %v:\n\"%v\" !=\n\"%v\"", i, msg, tc.exp)
}
}
}

View File

@@ -72,8 +72,12 @@ func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]b
url := urlPrefix + l.version + filename[idx:]
resp, err := l.client.Get(url)
if err != nil || resp.StatusCode != http.StatusOK {
fmt.Println("Loading source:", err.Error())
if err != nil {
fmt.Println("Loading source:", err)
return nil, 0
}
if resp.StatusCode != http.StatusOK {
fmt.Println("Loading source:", resp.Status)
return nil, 0
}
data, err := ioutil.ReadAll(resp.Body)

View File

@@ -4,18 +4,11 @@
// 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/.
// Command stcrashreceiver is a trivial HTTP server that allows two things:
//
// - uploading files (crash reports) named like a SHA256 hash using a PUT request
// - checking whether such file exists using a HEAD request
//
// Typically this should be deployed behind something that manages HTTPS.
package main
import (
"bytes"
"compress/gzip"
"flag"
"io"
"io/ioutil"
"log"
@@ -26,25 +19,6 @@ import (
"strings"
)
const maxRequestSize = 1 << 20 // 1 MiB
func main() {
dir := flag.String("dir", ".", "Directory to store reports in")
dsn := flag.String("dsn", "", "Sentry DSN")
listen := flag.String("listen", ":22039", "HTTP listen address")
flag.Parse()
cr := &crashReceiver{
dir: *dir,
dsn: *dsn,
}
log.SetOutput(os.Stdout)
if err := http.ListenAndServe(*listen, cr); err != nil {
log.Fatalln("HTTP serve:", err)
}
}
type crashReceiver struct {
dir string
dsn string
@@ -145,10 +119,18 @@ func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWrite
// Send the report to Sentry
if r.dsn != "" {
// Remote ID
user := userIDFor(req)
go func() {
// There's no need for the client to have to wait for this part.
if err := sendReport(r.dsn, reportID, bs); err != nil {
log.Println("Failed to send report:", err)
pkt, err := parseCrashReport(reportID, bs)
if err != nil {
log.Println("Failed to parse crash report:", err)
return
}
if err := sendReport(r.dsn, pkt, user); err != nil {
log.Println("Failed to send crash report:", err)
}
}()
}

View File

@@ -7,6 +7,7 @@
package main
import (
"context"
"crypto/rand"
"encoding/binary"
"flag"
@@ -47,14 +48,16 @@ func main() {
log.Println("My ID:", myID)
}
runbeacon(beacon.NewMulticast(mc), fake)
runbeacon(beacon.NewBroadcast(bc), fake)
ctx := context.Background()
runbeacon(ctx, beacon.NewMulticast(mc), fake)
runbeacon(ctx, beacon.NewBroadcast(bc), fake)
select {}
}
func runbeacon(bc beacon.Interface, fake bool) {
go bc.Serve()
func runbeacon(ctx context.Context, bc beacon.Interface, fake bool) {
go bc.Serve(ctx)
go recv(bc)
if fake {
go send(bc)

View File

@@ -66,12 +66,12 @@ func newAPISrv(addr string, cert tls.Certificate, db database, repl replicator,
}
}
func (s *apiSrv) Serve() {
func (s *apiSrv) Serve(ctx context.Context) error {
if s.useHTTP {
listener, err := net.Listen("tcp", s.addr)
if err != nil {
log.Println("Listen:", err)
return
return err
}
s.listener = listener
} else {
@@ -93,7 +93,7 @@ func (s *apiSrv) Serve() {
tlsListener, err := tls.Listen("tcp", s.addr, tlsCfg)
if err != nil {
log.Println("Listen:", err)
return
return err
}
s.listener = tlsListener
}
@@ -107,9 +107,11 @@ func (s *apiSrv) Serve() {
MaxHeaderBytes: httpMaxHeaderBytes,
}
if err := srv.Serve(s.listener); err != nil {
err := srv.Serve(s.listener)
if err != nil {
log.Println("Serve:", err)
}
return err
}
var topCtx = context.Background()
@@ -132,11 +134,19 @@ func (s *apiSrv) handler(w http.ResponseWriter, req *http.Request) {
log.Println(reqID, req.Method, req.URL)
}
var remoteIP net.IP
remoteAddr := &net.TCPAddr{
IP: nil,
Port: -1,
}
if s.useHTTP {
remoteIP = net.ParseIP(req.Header.Get("X-Forwarded-For"))
remoteAddr.IP = net.ParseIP(req.Header.Get("X-Forwarded-For"))
if parsedPort, err := strconv.ParseInt(req.Header.Get("X-Client-Port"), 10, 0); err == nil {
remoteAddr.Port = int(parsedPort)
}
} else {
addr, err := net.ResolveTCPAddr("tcp", req.RemoteAddr)
var err error
remoteAddr, err = net.ResolveTCPAddr("tcp", req.RemoteAddr)
if err != nil {
log.Println("remoteAddr:", err)
lw.Header().Set("Retry-After", errorRetryAfterString())
@@ -144,14 +154,13 @@ func (s *apiSrv) handler(w http.ResponseWriter, req *http.Request) {
apiRequestsTotal.WithLabelValues("no_remote_addr").Inc()
return
}
remoteIP = addr.IP
}
switch req.Method {
case "GET":
s.handleGET(ctx, lw, req)
case "POST":
s.handlePOST(ctx, remoteIP, lw, req)
s.handlePOST(ctx, remoteAddr, lw, req)
default:
http.Error(lw, "Method Not Allowed", http.StatusMethodNotAllowed)
}
@@ -217,7 +226,7 @@ func (s *apiSrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http
w.Write(bs)
}
func (s *apiSrv) handlePOST(ctx context.Context, remoteIP net.IP, w http.ResponseWriter, req *http.Request) {
func (s *apiSrv) handlePOST(ctx context.Context, remoteAddr *net.TCPAddr, w http.ResponseWriter, req *http.Request) {
reqID := ctx.Value(idKey).(requestID)
rawCert := certificateBytes(req)
@@ -244,7 +253,7 @@ func (s *apiSrv) handlePOST(ctx context.Context, remoteIP net.IP, w http.Respons
deviceID := protocol.NewDeviceID(rawCert)
addresses := fixupAddresses(remoteIP, ann.Addresses)
addresses := fixupAddresses(remoteAddr, ann.Addresses)
if len(addresses) == 0 {
announceRequestsTotal.WithLabelValues("bad_request").Inc()
w.Header().Set("Retry-After", errorRetryAfterString())
@@ -252,7 +261,7 @@ func (s *apiSrv) handlePOST(ctx context.Context, remoteIP net.IP, w http.Respons
return
}
if err := s.handleAnnounce(remoteIP, deviceID, addresses); err != nil {
if err := s.handleAnnounce(deviceID, addresses); err != nil {
announceRequestsTotal.WithLabelValues("internal_error").Inc()
w.Header().Set("Retry-After", errorRetryAfterString())
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
@@ -269,7 +278,7 @@ func (s *apiSrv) Stop() {
s.listener.Close()
}
func (s *apiSrv) handleAnnounce(remote net.IP, deviceID protocol.DeviceID, addresses []string) error {
func (s *apiSrv) handleAnnounce(deviceID protocol.DeviceID, addresses []string) error {
key := deviceID.String()
now := time.Now()
expire := now.Add(addressExpiryTime).UnixNano()
@@ -364,7 +373,7 @@ func certificateBytes(req *http.Request) []byte {
// fixupAddresses checks the list of addresses, removing invalid ones and
// replacing unspecified IPs with the given remote IP.
func fixupAddresses(remote net.IP, addresses []string) []string {
func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
fixed := make([]string, 0, len(addresses))
for _, annAddr := range addresses {
uri, err := url.Parse(annAddr)
@@ -384,27 +393,34 @@ func fixupAddresses(remote net.IP, addresses []string) []string {
continue
}
if host == "" || ip.IsUnspecified() {
// Replace the unspecified IP with the request source.
if remote != nil {
if host == "" || ip.IsUnspecified() {
// Replace the unspecified IP with the request source.
// ... unless the request source is the loopback address or
// multicast/unspecified (can't happen, really).
if remote.IsLoopback() || remote.IsMulticast() || remote.IsUnspecified() {
continue
// ... unless the request source is the loopback address or
// multicast/unspecified (can't happen, really).
if remote.IP.IsLoopback() || remote.IP.IsMulticast() || remote.IP.IsUnspecified() {
continue
}
// Do not use IPv6 remote address if requested scheme is ...4
// (i.e., tcp4, etc.)
if strings.HasSuffix(uri.Scheme, "4") && remote.IP.To4() == nil {
continue
}
// Do not use IPv4 remote address if requested scheme is ...6
if strings.HasSuffix(uri.Scheme, "6") && remote.IP.To4() != nil {
continue
}
host = remote.IP.String()
}
// Do not use IPv6 remote address if requested scheme is ...4
// (i.e., tcp4, etc.)
if strings.HasSuffix(uri.Scheme, "4") && remote.To4() == nil {
continue
// If zero port was specified, use remote port.
if port == "0" && remote.Port > 0 {
port = fmt.Sprintf("%d", remote.Port)
}
// Do not use IPv4 remote address if requested scheme is ...6
if strings.HasSuffix(uri.Scheme, "6") && remote.To4() != nil {
continue
}
host = remote.String()
}
uri.Host = net.JoinHostPort(host, port)

View File

@@ -14,7 +14,7 @@ import (
func TestFixupAddresses(t *testing.T) {
cases := []struct {
remote net.IP
remote *net.TCPAddr
in []string
out []string
}{
@@ -22,37 +22,53 @@ func TestFixupAddresses(t *testing.T) {
in: []string{"tcp://1.2.3.4:22000"},
out: []string{"tcp://1.2.3.4:22000"},
}, { // unspecified replaced by remote
remote: net.ParseIP("1.2.3.4"),
remote: addr("1.2.3.4", 22000),
in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"},
out: []string{"tcp://1.2.3.4:22000", "tcp://192.0.2.42:22000"},
}, { // unspecified not used as replacement
remote: net.ParseIP("0.0.0.0"),
remote: addr("0.0.0.0", 22000),
in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"},
out: []string{"tcp://192.0.2.42:22000"},
}, { // unspecified not used as replacement
remote: net.ParseIP("::"),
remote: addr("::", 22000),
in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"},
out: []string{"tcp://192.0.2.42:22000"},
}, { // localhost not used as replacement
remote: net.ParseIP("127.0.0.1"),
remote: addr("127.0.0.1", 22000),
in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"},
out: []string{"tcp://192.0.2.42:22000"},
}, { // localhost not used as replacement
remote: net.ParseIP("::1"),
remote: addr("::1", 22000),
in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"},
out: []string{"tcp://192.0.2.42:22000"},
}, { // multicast not used as replacement
remote: net.ParseIP("224.0.0.1"),
remote: addr("224.0.0.1", 22000),
in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"},
out: []string{"tcp://192.0.2.42:22000"},
}, { // multicast not used as replacement
remote: net.ParseIP("ff80::42"),
remote: addr("ff80::42", 22000),
in: []string{"tcp://:22000", "tcp://192.0.2.42:22000"},
out: []string{"tcp://192.0.2.42:22000"},
}, { // explicitly announced weirdness is also filtered
remote: net.ParseIP("192.0.2.42"),
remote: addr("192.0.2.42", 22000),
in: []string{"tcp://:22000", "tcp://127.1.2.3:22000", "tcp://[::1]:22000", "tcp://[ff80::42]:22000"},
out: []string{"tcp://192.0.2.42:22000"},
}, { // port remapping
remote: addr("123.123.123.123", 9000),
in: []string{"tcp://0.0.0.0:0"},
out: []string{"tcp://123.123.123.123:9000"},
}, { // unspecified port remapping
remote: addr("123.123.123.123", 9000),
in: []string{"tcp://:0"},
out: []string{"tcp://123.123.123.123:9000"},
}, { // empty remapping
remote: addr("123.123.123.123", 9000),
in: []string{"tcp://"},
out: []string{},
}, { // port only remapping
remote: addr("123.123.123.123", 9000),
in: []string{"tcp://44.44.44.44:0"},
out: []string{"tcp://44.44.44.44:9000"},
},
}
@@ -63,3 +79,10 @@ func TestFixupAddresses(t *testing.T) {
}
}
}
func addr(host string, port int) *net.TCPAddr {
return &net.TCPAddr{
IP: net.ParseIP(host),
Port: port,
}
}

View File

@@ -4,12 +4,13 @@
// 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 go run ../../script/protofmt.go database.proto
//go:generate go run ../../proto/scripts/protofmt.go database.proto
//go:generate protoc -I ../../ -I . --gogofast_out=. database.proto
package main
import (
"context"
"log"
"sort"
"time"
@@ -37,7 +38,6 @@ type database interface {
type levelDBStore struct {
db *leveldb.DB
inbox chan func()
stop chan struct{}
clock clock
marshalBuf []byte
}
@@ -50,7 +50,6 @@ func newLevelDBStore(dir string) (*levelDBStore, error) {
return &levelDBStore{
db: db,
inbox: make(chan func(), 16),
stop: make(chan struct{}),
clock: defaultClock{},
}, nil
}
@@ -155,7 +154,7 @@ func (s *levelDBStore) get(key string) (DatabaseRecord, error) {
return rec, nil
}
func (s *levelDBStore) Serve() {
func (s *levelDBStore) Serve(ctx context.Context) error {
t := time.NewTimer(0)
defer t.Stop()
defer s.db.Close()
@@ -183,7 +182,7 @@ loop:
// the next.
t.Reset(databaseStatisticsInterval)
case <-s.stop:
case <-ctx.Done():
// We're done.
close(statisticsTrigger)
break loop
@@ -192,6 +191,8 @@ loop:
// Also wait for statisticsServe to return
<-statisticsDone
return nil
}
func (s *levelDBStore) statisticsServe(trigger <-chan struct{}, done chan<- struct{}) {
@@ -255,10 +256,6 @@ func (s *levelDBStore) statisticsServe(trigger <-chan struct{}, done chan<- stru
}
}
func (s *levelDBStore) Stop() {
close(s.stop)
}
// merge returns the merged result of the two database records a and b. The
// result is the union of the two address sets, with the newer expiry time
// chosen for any duplicates.

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 {

View File

@@ -7,6 +7,7 @@
package main
import (
"context"
"fmt"
"os"
"testing"
@@ -20,8 +21,9 @@ func TestDatabaseGetSet(t *testing.T) {
if err != nil {
t.Fatal(err)
}
go db.Serve()
defer db.Stop()
ctx, cancel := context.WithCancel(context.Background())
go db.Serve(ctx)
defer cancel()
// Check missing record

View File

@@ -7,6 +7,7 @@
package main
import (
"context"
"crypto/tls"
"flag"
"log"
@@ -21,7 +22,7 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/thejerf/suture"
"github.com/thejerf/suture/v4"
)
const (
@@ -92,20 +93,21 @@ func main() {
showVersion := flag.Bool("version", false, "Show version")
flag.Parse()
log.Println(build.LongVersion)
log.Println(build.LongVersionFor("stdiscosrv"))
if *showVersion {
return
}
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
if os.IsNotExist(err) {
log.Println("Failed to load keypair. Generating one, this might take a while...")
cert, err = tlsutil.NewCertificate(certFile, keyFile, "stdiscosrv", 20*365)
if err != nil {
log.Fatalln("Failed to generate X509 key pair:", err)
}
} else if err != nil {
log.Fatalln("Failed to load keypair:", err)
}
devID := protocol.NewDeviceID(cert.Certificate[0])
log.Println("Server device ID is", devID)
@@ -182,5 +184,5 @@ func main() {
}
// Engage!
main.Serve()
main.Serve(context.Background())
}

View File

@@ -7,6 +7,7 @@
package main
import (
"context"
"crypto/tls"
"encoding/binary"
"fmt"
@@ -32,7 +33,6 @@ type replicationSender struct {
cert tls.Certificate // our certificate
allowedIDs []protocol.DeviceID
outbox chan ReplicationRecord
stop chan struct{}
}
func newReplicationSender(dst string, cert tls.Certificate, allowedIDs []protocol.DeviceID) *replicationSender {
@@ -41,11 +41,10 @@ func newReplicationSender(dst string, cert tls.Certificate, allowedIDs []protoco
cert: cert,
allowedIDs: allowedIDs,
outbox: make(chan ReplicationRecord, replicationOutboxSize),
stop: make(chan struct{}),
}
}
func (s *replicationSender) Serve() {
func (s *replicationSender) Serve(ctx context.Context) error {
// Sleep a little at startup. Peers often restart at the same time, and
// this avoid the service failing and entering backoff state
// unnecessarily, while also reducing the reconnect rate to something
@@ -62,7 +61,7 @@ func (s *replicationSender) Serve() {
conn, err := tls.Dial("tcp", s.dst, tlsCfg)
if err != nil {
log.Println("Replication connect:", err)
return
return err
}
defer func() {
conn.SetWriteDeadline(time.Now().Add(time.Second))
@@ -73,13 +72,13 @@ func (s *replicationSender) Serve() {
remoteID, err := deviceID(conn)
if err != nil {
log.Println("Replication connect:", err)
return
return err
}
// Verify it's in the set of allowed device IDs.
if !deviceIDIn(remoteID, s.allowedIDs) {
log.Println("Replication connect: unexpected device ID:", remoteID)
return
return err
}
heartBeatTicker := time.NewTicker(replicationHeartbeatInterval)
@@ -122,20 +121,16 @@ func (s *replicationSender) Serve() {
replicationSendsTotal.WithLabelValues("error").Inc()
log.Println("Replication write:", err)
// Yes, we are loosing the replication event here.
return
return err
}
replicationSendsTotal.WithLabelValues("success").Inc()
case <-s.stop:
return
case <-ctx.Done():
return nil
}
}
}
func (s *replicationSender) Stop() {
close(s.stop)
}
func (s *replicationSender) String() string {
return fmt.Sprintf("replicationSender(%q)", s.dst)
}
@@ -172,7 +167,6 @@ type replicationListener struct {
cert tls.Certificate
allowedIDs []protocol.DeviceID
db database
stop chan struct{}
}
func newReplicationListener(addr string, cert tls.Certificate, allowedIDs []protocol.DeviceID, db database) *replicationListener {
@@ -181,11 +175,10 @@ func newReplicationListener(addr string, cert tls.Certificate, allowedIDs []prot
cert: cert,
allowedIDs: allowedIDs,
db: db,
stop: make(chan struct{}),
}
}
func (l *replicationListener) Serve() {
func (l *replicationListener) Serve(ctx context.Context) error {
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{l.cert},
ClientAuth: tls.RequestClientCert,
@@ -196,14 +189,14 @@ func (l *replicationListener) Serve() {
lst, err := tls.Listen("tcp", l.addr, tlsCfg)
if err != nil {
log.Println("Replication listen:", err)
return
return err
}
defer lst.Close()
for {
select {
case <-l.stop:
return
case <-ctx.Done():
return nil
default:
}
@@ -211,7 +204,7 @@ func (l *replicationListener) Serve() {
conn, err := lst.Accept()
if err != nil {
log.Println("Replication accept:", err)
return
return err
}
// Figure out the other side device ID
@@ -231,19 +224,15 @@ func (l *replicationListener) Serve() {
continue
}
go l.handle(conn)
go l.handle(ctx, conn)
}
}
func (l *replicationListener) Stop() {
close(l.stop)
}
func (l *replicationListener) String() string {
return fmt.Sprintf("replicationListener(%q)", l.addr)
}
func (l *replicationListener) handle(conn net.Conn) {
func (l *replicationListener) handle(ctx context.Context, conn net.Conn) {
defer func() {
conn.SetWriteDeadline(time.Now().Add(time.Second))
conn.Close()
@@ -253,7 +242,7 @@ func (l *replicationListener) handle(conn net.Conn) {
for {
select {
case <-l.stop:
case <-ctx.Done():
return
default:
}

View File

@@ -28,16 +28,21 @@ func main() {
log.SetFlags(0)
target := flag.String("target", "localhost:8384", "Target Syncthing instance")
types := flag.String("types", "", "Filter for specific event types (comma-separated)")
apikey := flag.String("apikey", "", "Syncthing API key")
flag.Parse()
if *apikey == "" {
log.Fatal("Must give -apikey argument")
}
var eventsArg string
if len(*types) > 0 {
eventsArg = "&events=" + *types
}
since := 0
for {
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/rest/events?since=%d", *target, since), nil)
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/rest/events?since=%d%s", *target, since, eventsArg), nil)
if err != nil {
log.Fatal(err)
}

View File

@@ -1,112 +0,0 @@
// Copyright (C) 2015 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 main
import (
"encoding/binary"
"fmt"
"log"
"time"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/protocol"
)
func dump(ldb backend.Backend) {
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
}
for it.Next() {
key := it.Key()
switch key[0] {
case db.KeyTypeDevice:
folder := binary.BigEndian.Uint32(key[1:])
device := binary.BigEndian.Uint32(key[1+4:])
name := nulString(key[1+4+4:])
fmt.Printf("[device] F:%d D:%d N:%q", folder, device, name)
var f protocol.FileInfo
err := f.Unmarshal(it.Value())
if err != nil {
log.Fatal(err)
}
fmt.Printf(" V:%v\n", f)
case db.KeyTypeGlobal:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
var flv db.VersionList
flv.Unmarshal(it.Value())
fmt.Printf("[global] F:%d N:%q V:%s\n", folder, name, flv)
case db.KeyTypeBlock:
folder := binary.BigEndian.Uint32(key[1:])
hash := key[1+4 : 1+4+32]
name := nulString(key[1+4+32:])
fmt.Printf("[block] F:%d H:%x N:%q I:%d\n", folder, hash, name, binary.BigEndian.Uint32(it.Value()))
case db.KeyTypeDeviceStatistic:
fmt.Printf("[dstat] K:%x V:%x\n", it.Key(), it.Value())
case db.KeyTypeFolderStatistic:
fmt.Printf("[fstat] K:%x V:%x\n", it.Key(), it.Value())
case db.KeyTypeVirtualMtime:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
val := it.Value()
var real, virt time.Time
real.UnmarshalBinary(val[:len(val)/2])
virt.UnmarshalBinary(val[len(val)/2:])
fmt.Printf("[mtime] F:%d N:%q R:%v V:%v\n", folder, name, real, virt)
case db.KeyTypeFolderIdx:
key := binary.BigEndian.Uint32(it.Key()[1:])
fmt.Printf("[folderidx] K:%d V:%q\n", key, it.Value())
case db.KeyTypeDeviceIdx:
key := binary.BigEndian.Uint32(it.Key()[1:])
val := it.Value()
if len(val) == 0 {
fmt.Printf("[deviceidx] K:%d V:<nil>\n", key)
} else {
dev := protocol.DeviceIDFromBytes(val)
fmt.Printf("[deviceidx] K:%d V:%s\n", key, dev)
}
case db.KeyTypeIndexID:
device := binary.BigEndian.Uint32(it.Key()[1:])
folder := binary.BigEndian.Uint32(it.Key()[5:])
fmt.Printf("[indexid] D:%d F:%d I:%x\n", device, folder, it.Value())
case db.KeyTypeFolderMeta:
folder := binary.BigEndian.Uint32(it.Key()[1:])
fmt.Printf("[foldermeta] F:%d V:%x\n", folder, it.Value())
case db.KeyTypeMiscData:
fmt.Printf("[miscdata] K:%q V:%q\n", it.Key()[1:], it.Value())
case db.KeyTypeSequence:
folder := binary.BigEndian.Uint32(it.Key()[1:])
seq := binary.BigEndian.Uint64(it.Key()[5:])
fmt.Printf("[sequence] F:%d S:%d V:%q\n", folder, seq, it.Value())
case db.KeyTypeNeed:
folder := binary.BigEndian.Uint32(it.Key()[1:])
file := string(it.Key()[5:])
fmt.Printf("[need] F:%d V:%q\n", folder, file)
case db.KeyTypeBlockList:
fmt.Printf("[blocklist] H:%x\n", it.Key()[1:])
default:
fmt.Printf("[???]\n %x\n %x\n", it.Key(), it.Value())
}
}
}

View File

@@ -1,52 +0,0 @@
// Copyright (C) 2014 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 main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/db/backend"
)
func main() {
var mode string
log.SetFlags(0)
log.SetOutput(os.Stdout)
flag.StringVar(&mode, "mode", "dump", "Mode of operation: dump, dumpsize, idxck")
flag.Parse()
path := flag.Arg(0)
if path == "" {
path = filepath.Join(defaultConfigDir(), "index-v0.14.0.db")
}
ldb, err := backend.OpenLevelDBRO(path)
if err != nil {
log.Fatal(err)
}
switch mode {
case "dump":
dump(ldb)
case "dumpsize":
dumpsize(ldb)
case "idxck":
if !idxck(ldb) {
os.Exit(1)
}
case "account":
account(ldb)
default:
fmt.Println("Unknown mode")
}
}

View File

@@ -1,52 +0,0 @@
// Copyright (C) 2015 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 main
import (
"log"
"os"
"path/filepath"
"runtime"
"github.com/syncthing/syncthing/lib/fs"
)
func nulString(bs []byte) string {
for i := range bs {
if bs[i] == 0 {
return string(bs[:i])
}
}
return string(bs)
}
func defaultConfigDir() string {
switch runtime.GOOS {
case "windows":
if p := os.Getenv("LocalAppData"); p != "" {
return filepath.Join(p, "Syncthing")
}
return filepath.Join(os.Getenv("AppData"), "Syncthing")
case "darwin":
dir, err := fs.ExpandTilde("~/Library/Application Support/Syncthing")
if err != nil {
log.Fatal(err)
}
return dir
default:
if xdgCfg := os.Getenv("XDG_CONFIG_HOME"); xdgCfg != "" {
return filepath.Join(xdgCfg, "syncthing")
}
dir, err := fs.ExpandTilde("~/.config/syncthing")
if err != nil {
log.Fatal(err)
}
return dir
}
}

View File

@@ -1,10 +1,15 @@
// Copyright (C) 2016 The Syncthing Authors.
// 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/.
// The existence of this file means we get 0% test coverage rather than no
// test coverage at all. Remove when implementing an actual test.
//+build noassets
package stats
package auto
import "github.com/syncthing/syncthing/lib/assets"
func Assets() map[string]assets.Asset {
return nil
}

View File

@@ -9,8 +9,15 @@
<meta name="author" content=""/>
<title>Relay stats</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="//use.fontawesome.com/releases/v5.0.13/css/all.css"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
crossorigin=""></script>
<style>
#map {
@@ -38,17 +45,19 @@
<div class="container">
<h1>Relay Pool Data</h1>
<div ng-if="relays === undefined" class="text-center">
<img src="//cdnjs.cloudflare.com/ajax/libs/galleriffic/2.0.1/css/loader.gif" alt=""/>
<p>Please wait while we gather data</p>
<img src="https://cdnjs.cloudflare.com/ajax/libs/galleriffic/2.0.1/css/loader.gif" alt=""/>
<p>Please wait while we gather data</p>
</div>
<div>
<div ng-show="relays !== undefined" class="ng-hide">
<p>
Currently {{ relays.length }} relays online ({{ totals.goMaxProcs }} cores in total).
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 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">
@@ -179,15 +188,14 @@
<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>
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<script type="text/javascript" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?key=AIzaSyDk5WJ8s7ueLKb99X5DbQ-vkWtPDAKqYs0"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
<script>
@@ -228,11 +236,12 @@
numProxies: 0,
uptimeSeconds: 0,
};
$scope.map = new google.maps.Map(document.getElementById('map'), {
zoom: 1,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
$scope.mapBounds = new google.maps.LatLngBounds();
$scope.map = L.map('map').setView([40.90296, 1.90925], 2);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution: 'Leaflet',
maxZoom: 17
}).addTo($scope.map);
$scope.tooltipTemplate = $('#infoTemplate').html();
$scope.usedLocations = {};
$scope.sortType = 'stats.numActiveSessions';
@@ -279,8 +288,9 @@
}
});
$scope.map.fitBounds($scope.mapBounds);
if ($scope.relays.length == 1) {
//Center to only relay with zoom
$scope.map.panTo(new L.LatLng(relays[0].location.latitude, relays[0].location.longitude));
$scope.map.setZoom(13);
}
});
@@ -300,44 +310,50 @@
var locParts = loc.split(',');
relay.marker = new google.maps.Marker({
map: $scope.map,
position: new google.maps.LatLng(locParts[0], locParts[1]),
relay.marker = new L.Marker([relay.location.latitude, relay.location.longitude],{
title: relay.url,
});
var scope = $rootScope.$new(true);
scope.relay = relay;
relay.marker.info = new google.maps.InfoWindow({
content: $compile($scope.tooltipTemplate)(scope)[0],
var icon = new L.Icon({
iconSize: [18, 28], // size of the icon
iconAnchor: [9, 28], // point of the icon which will correspond to marker's location
shadowAnchor: [0, 0], // the same for the shadow
popupAnchor: [0, -27], // popup anchor
shadowSize: [0,0],
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
});
relay.marker = new L.marker(new L.latLng(locParts[0], locParts[1]),{icon})
.bindPopup($compile($scope.tooltipTemplate)(scope)[0],{})
.on('mouseover', function (e) {
this.openPopup();
}).on('mouseout', function (e) {
this.closePopup();
}).addTo($scope.map);
relay.showMarker = function() {
relay.marker.info.open($scope.map, relay.marker);
relay.marker.openPopup();
}
relay.hideMarker = function() {
relay.marker.info.close();
relay.marker.closePopup();
}
}
relay.marker.addListener('mouseover', relay.showMarker);
relay.marker.addListener('mouseout', relay.hideMarker);
$scope.mapBounds.extend(relay.marker.position);
}
function addCircleToMap(relay) {
relay.marker.circle = new google.maps.Circle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: $scope.map,
center: relay.marker.position,
radius: ((relay.stats.bytesProxied * 100) / $scope.totals.bytesProxied) * 10000
});
console.log(relay.location.latitude)
L.circle([relay.location.latitude, relay.location.longitude],
{
radius: ((relay.stats.bytesProxied * 100) / $scope.totals.bytesProxied) * 10000,
color: "FF0000",
fillColor: "#FF0000",
fillOpacity: 0.35,
}).addTo($scope.map);
}
function constructURI(url) {

View File

@@ -1,22 +1,18 @@
// Copyright (C) 2015 Audrius Butkevicius and Contributors (see the CONTRIBUTORS file).
//go:generate go run ../../script/genassets.go gui >auto/gui.go
package main
import (
"bytes"
"compress/gzip"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"mime"
"net"
"net/http"
"net/url"
@@ -26,11 +22,14 @@ import (
"strings"
"time"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/golang/groupcache/lru"
"github.com/oschwald/geoip2-golang"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/syncthing/syncthing/cmd/strelaypoolsrv/auto"
"github.com/syncthing/syncthing/lib/assets"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/relay/client"
"github.com/syncthing/syncthing/lib/sync"
@@ -95,33 +94,35 @@ type result struct {
}
var (
testCert tls.Certificate
knownRelaysFile = filepath.Join(os.TempDir(), "strelaypoolsrv_known_relays")
listen = ":80"
dir string
evictionTime = time.Hour
debug bool
getLRUSize = 10 << 10
getLimitBurst = 10
getLimitAvg = 2
postLRUSize = 1 << 10
postLimitBurst = 2
postLimitAvg = 2
getLimit time.Duration
postLimit time.Duration
permRelaysFile string
ipHeader string
geoipPath string
proto string
statsRefresh = time.Minute / 2
testCert tls.Certificate
knownRelaysFile = filepath.Join(os.TempDir(), "strelaypoolsrv_known_relays")
listen = ":80"
dir string
evictionTime = time.Hour
debug bool
getLRUSize = 10 << 10
getLimitBurst = 10
getLimitAvg = 2
postLRUSize = 1 << 10
postLimitBurst = 2
postLimitAvg = 2
getLimit time.Duration
postLimit time.Duration
permRelaysFile string
ipHeader string
geoipPath string
proto string
statsRefresh = time.Minute / 2
requestQueueLen = 10
requestProcessors = 1
getMut = sync.NewRWMutex()
getMut = sync.NewMutex()
getLRUCache *lru.Cache
postMut = sync.NewRWMutex()
postMut = sync.NewMutex()
postLRUCache *lru.Cache
requests = make(chan request, 10)
requests chan request
mut = sync.NewRWMutex()
knownRelays = make([]*relay, 0)
@@ -134,6 +135,9 @@ const (
)
func main() {
log.SetOutput(os.Stdout)
log.SetFlags(log.Lshortfile)
flag.StringVar(&listen, "listen", listen, "Listen address")
flag.StringVar(&dir, "keys", dir, "Directory where http-cert.pem and http-key.pem is stored for TLS listening")
flag.BoolVar(&debug, "debug", debug, "Enable debug output")
@@ -149,9 +153,13 @@ func main() {
flag.StringVar(&geoipPath, "geoip", "GeoLite2-City.mmdb", "Path to GeoLite2-City database")
flag.StringVar(&proto, "protocol", "tcp", "Protocol used for listening. 'tcp' for IPv4 and IPv6, 'tcp4' for IPv4, 'tcp6' for IPv6")
flag.DurationVar(&statsRefresh, "stats-refresh", statsRefresh, "Interval at which to refresh relay stats")
flag.IntVar(&requestQueueLen, "request-queue", requestQueueLen, "Queue length for incoming test requests")
flag.IntVar(&requestProcessors, "request-processors", requestProcessors, "Number of request processor routines")
flag.Parse()
requests = make(chan request, requestQueueLen)
getLimit = 10 * time.Second / time.Duration(getLimitAvg)
postLimit = time.Minute / time.Duration(postLimitAvg)
@@ -167,7 +175,9 @@ func main() {
testCert = createTestCertificate()
go requestProcessor()
for i := 0; i < requestProcessors; i++ {
go requestProcessor()
}
// Load relays from cache in the background.
// Load them in a serial fashion to make sure any genuine requests
@@ -201,6 +211,7 @@ func main() {
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS10, // No SSLv3
ClientAuth: tls.RequestClientCert,
CipherSuites: []uint16{
// No RC4
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
@@ -256,88 +267,27 @@ func handleMetrics(w http.ResponseWriter, r *http.Request) {
func handleAssets(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache, must-revalidate")
assets := auto.Assets()
path := r.URL.Path[1:]
if path == "" {
path = "index.html"
}
bs, ok := assets[path]
as, ok := auto.Assets()[path]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
etag := fmt.Sprintf("%d", auto.Generated)
modified := time.Unix(auto.Generated, 0).UTC()
w.Header().Set("Last-Modified", modified.Format(http.TimeFormat))
w.Header().Set("Etag", etag)
mtype := mimeTypeForFile(path)
if len(mtype) != 0 {
w.Header().Set("Content-Type", mtype)
}
if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modified.Add(time.Second).After(t) {
w.WriteHeader(http.StatusNotModified)
return
}
if match := r.Header.Get("If-None-Match"); match != "" {
if strings.Contains(match, etag) {
w.WriteHeader(http.StatusNotModified)
return
}
}
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
} else {
// ungzip if browser not send gzip accepted header
var gr *gzip.Reader
gr, _ = gzip.NewReader(bytes.NewReader(bs))
bs, _ = ioutil.ReadAll(gr)
gr.Close()
}
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(bs)))
w.Write(bs)
}
func mimeTypeForFile(file string) string {
// We use a built in table of the common types since the system
// TypeByExtension might be unreliable. But if we don't know, we delegate
// to the system.
ext := filepath.Ext(file)
switch ext {
case ".htm", ".html":
return "text/html"
case ".css":
return "text/css"
case ".js":
return "application/javascript"
case ".json":
return "application/json"
case ".png":
return "image/png"
case ".ttf":
return "application/x-font-ttf"
case ".woff":
return "application/x-font-woff"
case ".svg":
return "image/svg+xml"
default:
return mime.TypeByExtension(ext)
}
assets.Serve(w, r, as)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
timer := prometheus.NewTimer(apiRequestsSeconds.WithLabelValues(r.Method))
lw := NewLoggingResponseWriter(w)
w = NewLoggingResponseWriter(w)
defer func() {
timer.ObserveDuration()
lw := w.(*loggingResponseWriter)
apiRequestsTotal.WithLabelValues(r.Method, strconv.Itoa(lw.statusCode)).Inc()
}()
@@ -368,8 +318,11 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
func handleGetRequest(rw http.ResponseWriter, r *http.Request) {
rw.Header().Set("Content-Type", "application/json; charset=utf-8")
mut.RLock()
relays := append(permanentRelays, knownRelays...)
relays := make([]*relay, len(permanentRelays)+len(knownRelays))
n := copy(relays, permanentRelays)
copy(relays[n:], knownRelays)
mut.RUnlock()
// Shuffle
@@ -389,6 +342,12 @@ func handleGetRequest(rw http.ResponseWriter, r *http.Request) {
}
func handlePostRequest(w http.ResponseWriter, r *http.Request) {
var relayCert *x509.Certificate
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
relayCert = r.TLS.PeerCertificates[0]
log.Printf("Got TLS cert from relay server")
}
var newRelay relay
err := json.NewDecoder(r.Body).Decode(&newRelay)
r.Body.Close()
@@ -397,7 +356,7 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
if debug {
log.Println("Failed to parse payload")
}
http.Error(w, err.Error(), 500)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
@@ -406,16 +365,26 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
if debug {
log.Println("Failed to parse URI", newRelay.URL)
}
http.Error(w, err.Error(), 500)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if relayCert != nil {
advertisedId := uri.Query().Get("id")
idFromCert := protocol.NewDeviceID(relayCert.Raw).String()
if advertisedId != idFromCert {
log.Println("Warning: Relay server requested to join with an ID different from the join request, rejecting")
http.Error(w, "mismatched advertised id and join request cert", http.StatusBadRequest)
return
}
}
host, port, err := net.SplitHostPort(uri.Host)
if err != nil {
if debug {
log.Println("Failed to split URI", newRelay.URL)
}
http.Error(w, err.Error(), 500)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
@@ -430,7 +399,7 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
if ip == nil || ip.IsUnspecified() {
uri.Host = net.JoinHostPort(rhost, port)
newRelay.URL = uri.String()
} else if host != rhost {
} else if host != rhost && relayCert == nil {
if debug {
log.Println("IP address advertised does not match client IP address", r.RemoteAddr, uri)
}
@@ -491,11 +460,11 @@ func handleRelayTest(request request) {
if debug {
log.Println("Request for", request.relay)
}
if !client.TestRelay(context.TODO(), request.relay.uri, []tls.Certificate{testCert}, time.Second, 2*time.Second, 3) {
if err := client.TestRelay(context.TODO(), request.relay.uri, []tls.Certificate{testCert}, time.Second, 2*time.Second, 3); err != nil {
if debug {
log.Println("Test for relay", request.relay, "failed")
log.Println("Test for relay", request.relay, "failed:", err)
}
request.result <- result{errors.New("connection test failed"), 0}
request.result <- result{err, 0}
return
}
@@ -507,7 +476,7 @@ func handleRelayTest(request request) {
updateMetrics(request.relay.uri.Host, *stats, location)
}
request.relay.Stats = stats
request.relay.StatsRetrieved = time.Now()
request.relay.StatsRetrieved = time.Now().Truncate(time.Second)
request.relay.Location = location
timer, ok := evictionTimers[request.relay.uri.Host]
@@ -573,26 +542,21 @@ func evict(relay *relay) func() {
}
}
func limit(addr string, cache *lru.Cache, lock sync.RWMutex, intv time.Duration, burst int) bool {
func limit(addr string, cache *lru.Cache, lock sync.Mutex, intv time.Duration, burst int) bool {
if host, _, err := net.SplitHostPort(addr); err == nil {
addr = host
}
lock.RLock()
bkt, ok := cache.Get(addr)
lock.RUnlock()
if ok {
bkt := bkt.(*rate.Limiter)
if !bkt.Allow() {
// Rate limit
return true
}
} else {
lock.Lock()
cache.Add(addr, rate.NewLimiter(rate.Every(intv), burst))
lock.Unlock()
lock.Lock()
v, _ := cache.Get(addr)
bkt, ok := v.(*rate.Limiter)
if !ok {
bkt = rate.NewLimiter(rate.Every(intv), burst)
cache.Add(addr, bkt)
}
return false
lock.Unlock()
return !bkt.Allow()
}
func loadRelays(file string) []*relay {

View File

@@ -0,0 +1,67 @@
// Copyright © 2020 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 main
import (
"bytes"
"encoding/json"
"fmt"
"net/http/httptest"
"strings"
"sync"
"testing"
)
func init() {
for i := 0; i < 10; i++ {
u := fmt.Sprintf("permanent%d", i)
permanentRelays = append(permanentRelays, &relay{URL: u})
}
knownRelays = []*relay{
{URL: "known1"},
{URL: "known2"},
{URL: "known3"},
}
mut = new(sync.RWMutex)
}
// Regression test: handleGetRequest should not modify permanentRelays.
func TestHandleGetRequest(t *testing.T) {
needcap := len(permanentRelays) + len(knownRelays)
if needcap > cap(permanentRelays) {
t.Fatalf("test setup failed: need cap(permanentRelays) >= %d, have %d",
needcap, cap(permanentRelays))
}
w := httptest.NewRecorder()
w.Body = new(bytes.Buffer)
handleGetRequest(w, httptest.NewRequest("GET", "/", nil))
result := make(map[string][]*relay)
err := json.NewDecoder(w.Body).Decode(&result)
if err != nil {
t.Fatalf("invalid JSON: %v", err)
}
relays := result["relays"]
expect, actual := len(knownRelays)+len(permanentRelays), len(relays)
if actual != expect {
t.Errorf("expected %d relays, got %d", expect, actual)
}
// Check for changes in permanentRelays.
for i, r := range permanentRelays {
switch {
case !strings.HasPrefix(r.URL, "permanent"):
t.Errorf("relay %q among permanent relays", r.URL)
case r.URL != fmt.Sprintf("permanent%d", i):
t.Error("order of permanent relays changed")
}
}
}

View File

@@ -121,11 +121,11 @@ Relay related libraries used by this repo
----
##### Relay protocol definition.
[Available here](https://github.com/syncthing/syncthing/tree/master/lib/relay/protocol)
[Available here](https://github.com/syncthing/syncthing/tree/main/lib/relay/protocol)
##### Relay client
Only used by the testutil.
[Available here](https://github.com/syncthing/syncthing/tree/master/lib/relay/client)
[Available here](https://github.com/syncthing/syncthing/tree/main/lib/relay/client)

View File

@@ -149,7 +149,15 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
protocol.WriteMessage(conn, protocol.ResponseSuccess)
case protocol.ConnectRequest:
requestedPeer := syncthingprotocol.DeviceIDFromBytes(msg.ID)
requestedPeer, err := syncthingprotocol.DeviceIDFromBytes(msg.ID)
if err != nil {
if debug {
log.Println(id, "is looking for an invalid peer ID")
}
protocol.WriteMessage(conn, protocol.ResponseNotFound)
conn.Close()
continue
}
outboxesMut.RLock()
peerOutbox, ok := outboxes[requestedPeer]
outboxesMut.RUnlock()

View File

@@ -3,6 +3,7 @@
package main
import (
"context"
"crypto/tls"
"flag"
"fmt"
@@ -98,12 +99,13 @@ func main() {
flag.IntVar(&natRenewal, "nat-renewal", 30, "NAT renewal frequency in minutes")
flag.IntVar(&natTimeout, "nat-timeout", 10, "NAT discovery timeout in seconds")
flag.BoolVar(&pprofEnabled, "pprof", false, "Enable the built in profiling on the status server")
flag.IntVar(&networkBufferSize, "network-buffer", 2048, "Network buffer size (two of these per proxied connection)")
flag.IntVar(&networkBufferSize, "network-buffer", 65536, "Network buffer size (two of these per proxied connection)")
showVersion := flag.Bool("version", false, "Show version")
flag.Parse()
longVer := build.LongVersionFor("strelaysrv")
if *showVersion {
fmt.Println(build.LongVersion)
fmt.Println(longVer)
return
}
@@ -135,7 +137,7 @@ func main() {
}
}
log.Println(build.LongVersion)
log.Println(longVer)
maxDescriptors, err := osutil.MaximizeOpenFileLimit()
if maxDescriptors > 0 {
@@ -183,17 +185,20 @@ func main() {
log.Println("ID:", id)
}
wrapper := config.Wrap("config", config.New(id), events.NoopLogger)
wrapper.SetOptions(config.OptionsConfiguration{
NATLeaseM: natLease,
NATRenewalM: natRenewal,
NATTimeoutS: natTimeout,
wrapper := config.Wrap("config", config.New(id), id, events.NoopLogger)
go wrapper.Serve(context.TODO())
wrapper.Modify(func(cfg *config.Configuration) {
cfg.Options.NATLeaseM = natLease
cfg.Options.NATRenewalM = natRenewal
cfg.Options.NATTimeoutS = natTimeout
})
natSvc := nat.NewService(id, wrapper)
mapping := mapping{natSvc.NewMapping(nat.TCP, addr.IP, addr.Port)}
if natEnabled {
go natSvc.Serve()
ctx, cancel := context.WithCancel(context.Background())
go natSvc.Serve(ctx)
defer cancel()
found := make(chan struct{})
mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) {
select {
@@ -228,6 +233,7 @@ func main() {
uri, err := url.Parse(fmt.Sprintf("relay://%s/?id=%s&pingInterval=%s&networkTimeout=%s&sessionLimitBps=%d&globalLimitBps=%d&statusAddr=%s&providedBy=%s", mapping.Address(), id, pingInterval, networkTimeout, sessionLimitBps, globalLimitBps, statusAddr, providedBy))
if err != nil {
log.Fatalln("Failed to construct URI", err)
return
}
log.Println("URI:", uri.String())
@@ -243,7 +249,7 @@ func main() {
for _, pool := range pools {
pool = strings.TrimSpace(pool)
if len(pool) > 0 {
go poolHandler(pool, uri, mapping)
go poolHandler(pool, uri, mapping, cert)
}
}

View File

@@ -4,14 +4,20 @@ package main
import (
"bytes"
"crypto/tls"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"net/url"
"time"
)
func poolHandler(pool string, uri *url.URL, mapping mapping) {
const (
httpStatusEnhanceYourCalm = 429
)
func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certificate) {
if debug {
log.Println("Joining", pool)
}
@@ -26,40 +32,81 @@ func poolHandler(pool string, uri *url.URL, mapping mapping) {
uriCopy.String(),
})
resp, err := httpClient.Post(pool, "application/json", &b)
poolUrl, err := url.Parse(pool)
if err != nil {
log.Println("Error joining pool", pool, err)
} else if resp.StatusCode == 500 {
bs, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println("Failed to join", pool, "due to an internal server error. Could not read response:", err)
} else {
log.Println("Failed to join", pool, "due to an internal server error:", string(bs))
log.Printf("Could not parse pool url '%s': %v", pool, err)
}
client := http.DefaultClient
if poolUrl.Scheme == "https" {
// Sent our certificate in join request
client = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{ownCert},
},
},
}
resp.Body.Close()
} else if resp.StatusCode == 429 {
log.Println(pool, "under load, will retry in a minute")
}
resp, err := client.Post(pool, "application/json", &b)
if err != nil {
log.Printf("Error joining pool %v: HTTP request: %v", pool, err)
time.Sleep(time.Minute)
continue
} else if resp.StatusCode == 401 {
log.Println(pool, "failed to join due to IP address not matching external address. Aborting")
return
} else if resp.StatusCode == 200 {
}
bs, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Printf("Error joining pool %v: reading response: %v", pool, err)
time.Sleep(time.Minute)
continue
}
switch resp.StatusCode {
case http.StatusOK:
var x struct {
EvictionIn time.Duration `json:"evictionIn"`
}
err := json.NewDecoder(resp.Body).Decode(&x)
if err == nil {
if err := json.Unmarshal(bs, &x); err == nil {
rejoin := x.EvictionIn - (x.EvictionIn / 5)
log.Println("Joined", pool, "rejoining in", rejoin)
log.Printf("Joined pool %s, rejoining in %v", pool, rejoin)
time.Sleep(rejoin)
continue
} else {
log.Println("Failed to deserialize response", err)
log.Printf("Joined pool %s, failed to deserialize response: %v", pool, err)
}
} else {
log.Println(pool, "unknown response type from server", resp.StatusCode)
case http.StatusInternalServerError:
log.Printf("Failed to join %v: server error", pool)
log.Printf("Response data: %s", bs)
time.Sleep(time.Minute)
continue
case http.StatusBadRequest:
log.Printf("Failed to join %v: request or check error", pool)
log.Printf("Response data: %s", bs)
time.Sleep(time.Minute)
continue
case httpStatusEnhanceYourCalm:
log.Printf("Failed to join %v: under load (rate limiting)", pool)
time.Sleep(time.Minute)
continue
case http.StatusUnauthorized:
log.Printf("Failed to join %v: IP address not matching external address", pool)
log.Println("Aborting")
return
default:
log.Printf("Failed to join %v: unexpected status code from server: %d", pool, resp.StatusCode)
log.Printf("Response data: %s", bs)
time.Sleep(time.Minute)
continue
}
time.Sleep(time.Hour)
}
}

View File

@@ -20,7 +20,8 @@ import (
)
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
log.SetOutput(os.Stdout)
log.SetFlags(log.LstdFlags | log.Lshortfile)
@@ -56,13 +57,13 @@ 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)
}
log.Println("Created client")
go relay.Serve()
go relay.Serve(ctx)
recv := make(chan protocol.SessionInvitation)
@@ -107,10 +108,10 @@ func main() {
connectToStdio(stdin, conn)
log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr())
} else if test {
if client.TestRelay(ctx, uri, []tls.Certificate{cert}, time.Second, 2*time.Second, 4) {
if err := client.TestRelay(ctx, uri, []tls.Certificate{cert}, time.Second, 2*time.Second, 4); err == nil {
log.Println("OK")
} else {
log.Println("FAIL")
log.Println("FAIL:", err)
}
} else {
log.Fatal("Requires either join or connect")

View File

@@ -37,7 +37,7 @@ type result struct {
func main() {
flag.Parse()
prefix := strings.ToUpper(strings.Replace(flag.Arg(0), "-", "", -1))
prefix := strings.ToUpper(strings.ReplaceAll(flag.Arg(0), "-", ""))
if len(prefix) > 7 {
prefix = prefix[:7] + "-" + prefix[7:]
}

View File

@@ -7,31 +7,15 @@
package main
import (
"bytes"
"crypto/md5"
"flag"
"fmt"
"io"
"os"
"time"
"github.com/syncthing/syncthing/lib/sha256"
)
func getmd5(filePath string) ([]byte, error) {
var result []byte
file, err := os.Open(filePath)
if err != nil {
return result, err
}
defer file.Close()
hash := md5.New()
if _, err := io.Copy(hash, file); err != nil {
return result, err
}
return hash.Sum(result), nil
}
func main() {
period := flag.Duration("period", 200*time.Millisecond, "Sleep period between checks")
flag.Parse()
@@ -46,7 +30,7 @@ func main() {
exists := true
size := int64(0)
mtime := time.Time{}
hash := []byte{}
var hash [sha256.Size]byte
for {
time.Sleep(*period)
@@ -72,7 +56,7 @@ func main() {
if !exists {
size = 0
mtime = time.Time{}
hash = []byte{}
hash = [sha256.Size]byte{}
continue
}
@@ -83,12 +67,12 @@ func main() {
newSize := fi.Size()
newMtime := fi.ModTime()
newHash, err := getmd5(file)
newHash, err := sha256file(file)
if err != nil {
fmt.Println("getmd5:", err)
fmt.Println("sha256file:", err)
}
if newSize != size || newMtime != mtime || !bytes.Equal(newHash, hash) {
if newSize != size || newMtime != mtime || newHash != hash {
fmt.Println(file, "Size:", newSize, "Mtime:", newMtime, "Hash:", fmt.Sprintf("%x", newHash))
hash = newHash
size = newSize
@@ -96,3 +80,18 @@ func main() {
}
}
}
func sha256file(fname string) (hash [sha256.Size]byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
h := sha256.New()
io.Copy(h, f)
hb := h.Sum(nil)
copy(hash[:], hb)
return
}

View File

@@ -15,19 +15,17 @@ import (
"time"
)
func init() {
if innerProcess && os.Getenv("STBLOCKPROFILE") != "" {
profiler := pprof.Lookup("block")
if profiler == nil {
panic("Couldn't find block profiler")
}
l.Debugln("Starting block profiling")
go func() {
err := saveBlockingProfiles(profiler) // Only returns on error
l.Warnln("Block profiler failed:", err)
panic("Block profiler failed")
}()
func startBlockProfiler() {
profiler := pprof.Lookup("block")
if profiler == nil {
panic("Couldn't find block profiler")
}
l.Debugln("Starting block profiling")
go func() {
err := saveBlockingProfiles(profiler) // Only returns on error
l.Warnln("Block profiler failed:", err)
panic("Block profiler failed")
}()
}
func saveBlockingProfiles(profiler *pprof.Profile) error {

153
cmd/syncthing/cli/client.go Normal file
View File

@@ -0,0 +1,153 @@
// Copyright (C) 2019 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 cli
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"strings"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/protocol"
)
type APIClient interface {
Get(url string) (*http.Response, error)
Post(url, body string) (*http.Response, error)
}
type apiClient struct {
http.Client
cfg config.GUIConfiguration
apikey string
}
type apiClientFactory struct {
cfg config.GUIConfiguration
}
func (f *apiClientFactory) getClient() (APIClient, error) {
// Now if the API key and address is not provided (we are not connecting to a remote instance),
// try to rip it out of the config.
if f.cfg.RawAddress == "" && f.cfg.APIKey == "" {
var err error
f.cfg, err = loadGUIConfig()
if err != nil {
return nil, err
}
} else if f.cfg.Address() == "" || f.cfg.APIKey == "" {
return nil, errors.New("Both --gui-address and --gui-apikey should be specified")
}
httpClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(f.cfg.Network(), f.cfg.Address())
},
},
}
return &apiClient{
Client: httpClient,
cfg: f.cfg,
apikey: f.cfg.APIKey,
}, nil
}
func loadGUIConfig() (config.GUIConfiguration, error) {
// Load the certs and get the ID
cert, err := tls.LoadX509KeyPair(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
)
if err != nil {
return config.GUIConfiguration{}, fmt.Errorf("reading device ID: %w", err)
}
myID := protocol.NewDeviceID(cert.Certificate[0])
// Load the config
cfg, _, err := config.Load(locations.Get(locations.ConfigFile), myID, events.NoopLogger)
if err != nil {
return config.GUIConfiguration{}, fmt.Errorf("loading config: %w", err)
}
guiCfg := cfg.GUI()
if guiCfg.Address() == "" {
return config.GUIConfiguration{}, errors.New("Could not find GUI Address")
}
if guiCfg.APIKey == "" {
return config.GUIConfiguration{}, errors.New("Could not find GUI API key")
}
return guiCfg, nil
}
func (c *apiClient) Endpoint() string {
if c.cfg.Network() == "unix" {
return "http://unix/"
}
url := c.cfg.URL()
if !strings.HasSuffix(url, "/") {
url += "/"
}
return url
}
func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-API-Key", c.apikey)
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
}
return resp, checkResponse(resp)
}
func (c *apiClient) Get(url string) (*http.Response, error) {
request, err := http.NewRequest("GET", c.Endpoint()+"rest/"+url, nil)
if err != nil {
return nil, err
}
return c.Do(request)
}
func (c *apiClient) Post(url, body string) (*http.Response, error) {
request, err := http.NewRequest("POST", c.Endpoint()+"rest/"+url, bytes.NewBufferString(body))
if err != nil {
return nil, err
}
return c.Do(request)
}
var errNotFound = errors.New("invalid endpoint or API call")
func checkResponse(response *http.Response) error {
if response.StatusCode == http.StatusNotFound {
return errNotFound
} else if response.StatusCode == http.StatusUnauthorized {
return errors.New("invalid API key")
} else if response.StatusCode != http.StatusOK {
data, err := responseToBArray(response)
if err != nil {
return err
}
body := strings.TrimSpace(string(data))
return fmt.Errorf("unexpected HTTP status returned: %s\n%s", response.Status, body)
}
return nil
}

View File

@@ -0,0 +1,87 @@
// 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 cli
import (
"encoding/json"
"fmt"
"reflect"
"github.com/AudriusButkevicius/recli"
"github.com/pkg/errors"
"github.com/syncthing/syncthing/lib/config"
"github.com/urfave/cli"
)
type configHandler struct {
original, cfg config.Configuration
client APIClient
err error
}
func getConfigCommand(f *apiClientFactory) (cli.Command, error) {
h := new(configHandler)
h.client, h.err = f.getClient()
if h.err == nil {
h.cfg, h.err = getConfig(h.client)
}
h.original = h.cfg.Copy()
// Copy the config and set the default flags
recliCfg := recli.DefaultConfig
recliCfg.IDTag.Name = "xml"
recliCfg.SkipTag.Name = "json"
commands, err := recli.New(recliCfg).Construct(&h.cfg)
if err != nil {
return cli.Command{}, fmt.Errorf("config reflect: %w", err)
}
return cli.Command{
Name: "config",
HideHelp: true,
Usage: "Configuration modification command group",
Subcommands: commands,
Before: h.configBefore,
After: h.configAfter,
}, nil
}
func (h *configHandler) configBefore(c *cli.Context) error {
for _, arg := range c.Args() {
if arg == "--help" || arg == "-h" {
return nil
}
}
return h.err
}
func (h *configHandler) configAfter(c *cli.Context) error {
if h.err != nil {
// Error was already returned in configBefore
return nil
}
if reflect.DeepEqual(h.cfg, h.original) {
return nil
}
body, err := json.MarshalIndent(h.cfg, "", " ")
if err != nil {
return err
}
resp, err := h.client.Post("system/config", string(body))
if err != nil {
return err
}
if resp.StatusCode != 200 {
body, err := responseToBArray(resp)
if err != nil {
return err
}
return errors.New(string(body))
}
return nil
}

View File

@@ -0,0 +1,55 @@
// 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 cli
import (
"fmt"
"net/url"
"github.com/urfave/cli"
)
var debugCommand = cli.Command{
Name: "debug",
HideHelp: true,
Usage: "Debug command group",
Subcommands: []cli.Command{
{
Name: "file",
Usage: "Show information about a file (or directory/symlink)",
ArgsUsage: "FOLDER-ID PATH",
Action: expects(2, debugFile()),
},
indexCommand,
{
Name: "profile",
Usage: "Save a profile to help figuring out what Syncthing does.",
ArgsUsage: "cpu | heap",
Action: expects(1, profile()),
},
},
}
func debugFile() cli.ActionFunc {
return func(c *cli.Context) error {
query := make(url.Values)
query.Set("folder", c.Args()[0])
query.Set("file", normalizePath(c.Args()[1]))
return indexDumpOutput("debug/file?" + query.Encode())(c)
}
}
func profile() cli.ActionFunc {
return func(c *cli.Context) error {
switch t := c.Args()[0]; t {
case "cpu", "heap":
return saveToFile(fmt.Sprintf("debug/%vprof", c.Args()[0]))(c)
default:
return fmt.Errorf("expected cpu or heap as argument, got %v", t)
}
}
}

View File

@@ -4,7 +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/.
package main
package cli
import (
"errors"
@@ -22,7 +22,7 @@ var errorsCommand = cli.Command{
{
Name: "show",
Usage: "Show pending errors",
Action: expects(0, dumpOutput("system/error")),
Action: expects(0, indexDumpOutput("system/error")),
},
{
Name: "push",
@@ -39,7 +39,7 @@ var errorsCommand = cli.Command{
}
func errorsPush(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
client := c.App.Metadata["client"].(APIClient)
errStr := strings.Join(c.Args(), " ")
response, err := client.Post("system/error", strings.TrimSpace(errStr))
if err != nil {

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2014 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 cli
import (
"github.com/urfave/cli"
)
var indexCommand = cli.Command{
Name: "index",
Usage: "Show information about the index (database)",
Subcommands: []cli.Command{
{
Name: "dump",
Usage: "Print the entire db",
Action: expects(0, indexDump),
},
{
Name: "dump-size",
Usage: "Print the db size of different categories of information",
Action: expects(0, indexDumpSize),
},
{
Name: "check",
Usage: "Check the database for inconsistencies",
Action: expects(0, indexCheck),
},
{
Name: "account",
Usage: "Print key and value size statistics per key type",
Action: expects(0, indexAccount),
},
},
}

View File

@@ -4,22 +4,26 @@
// 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 main
package cli
import (
"fmt"
"log"
"os"
"text/tabwriter"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/urfave/cli"
)
// account prints key and data size statistics per class
func account(ldb backend.Backend) {
// indexAccount prints key and data size statistics per class
func indexAccount(*cli.Context) error {
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
return err
}
var ksizes [256]int
@@ -55,4 +59,6 @@ func account(ldb backend.Backend) {
}
fmt.Fprintf(tw, "Total\t%d items,\t%d KB keys +\t%d KB data.\t\n", toti, totks/1000, totds/1000)
tw.Flush()
return nil
}

View File

@@ -0,0 +1,160 @@
// Copyright (C) 2015 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 cli
import (
"encoding/binary"
"fmt"
"time"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/protocol"
)
func indexDump(*cli.Context) error {
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
return err
}
for it.Next() {
key := it.Key()
switch key[0] {
case db.KeyTypeDevice:
folder := binary.BigEndian.Uint32(key[1:])
device := binary.BigEndian.Uint32(key[1+4:])
name := nulString(key[1+4+4:])
fmt.Printf("[device] F:%d D:%d N:%q", folder, device, name)
var f protocol.FileInfo
err := f.Unmarshal(it.Value())
if err != nil {
return err
}
fmt.Printf(" V:%v\n", f)
case db.KeyTypeGlobal:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
var flv db.VersionList
flv.Unmarshal(it.Value())
fmt.Printf("[global] F:%d N:%q V:%s\n", folder, name, flv)
case db.KeyTypeBlock:
folder := binary.BigEndian.Uint32(key[1:])
hash := key[1+4 : 1+4+32]
name := nulString(key[1+4+32:])
fmt.Printf("[block] F:%d H:%x N:%q I:%d\n", folder, hash, name, binary.BigEndian.Uint32(it.Value()))
case db.KeyTypeDeviceStatistic:
fmt.Printf("[dstat] K:%x V:%x\n", key, it.Value())
case db.KeyTypeFolderStatistic:
fmt.Printf("[fstat] K:%x V:%x\n", key, it.Value())
case db.KeyTypeVirtualMtime:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
val := it.Value()
var realTime, virtualTime time.Time
realTime.UnmarshalBinary(val[:len(val)/2])
virtualTime.UnmarshalBinary(val[len(val)/2:])
fmt.Printf("[mtime] F:%d N:%q R:%v V:%v\n", folder, name, realTime, virtualTime)
case db.KeyTypeFolderIdx:
key := binary.BigEndian.Uint32(key[1:])
fmt.Printf("[folderidx] K:%d V:%q\n", key, it.Value())
case db.KeyTypeDeviceIdx:
key := binary.BigEndian.Uint32(key[1:])
val := it.Value()
device := "<nil>"
if len(val) > 0 {
dev, err := protocol.DeviceIDFromBytes(val)
if err != nil {
device = fmt.Sprintf("<invalid %d bytes>", len(val))
} else {
device = dev.String()
}
}
fmt.Printf("[deviceidx] K:%d V:%s\n", key, device)
case db.KeyTypeIndexID:
device := binary.BigEndian.Uint32(key[1:])
folder := binary.BigEndian.Uint32(key[5:])
fmt.Printf("[indexid] D:%d F:%d I:%x\n", device, folder, it.Value())
case db.KeyTypeFolderMeta:
folder := binary.BigEndian.Uint32(key[1:])
fmt.Printf("[foldermeta] F:%d", folder)
var cs db.CountsSet
if err := cs.Unmarshal(it.Value()); err != nil {
fmt.Printf(" (invalid)\n")
} else {
fmt.Printf(" V:%v\n", cs)
}
case db.KeyTypeMiscData:
fmt.Printf("[miscdata] K:%q V:%q\n", key[1:], it.Value())
case db.KeyTypeSequence:
folder := binary.BigEndian.Uint32(key[1:])
seq := binary.BigEndian.Uint64(key[5:])
fmt.Printf("[sequence] F:%d S:%d V:%q\n", folder, seq, it.Value())
case db.KeyTypeNeed:
folder := binary.BigEndian.Uint32(key[1:])
file := string(key[5:])
fmt.Printf("[need] F:%d V:%q\n", folder, file)
case db.KeyTypeBlockList:
fmt.Printf("[blocklist] H:%x\n", key[1:])
case db.KeyTypeBlockListMap:
folder := binary.BigEndian.Uint32(key[1:])
hash := key[5:37]
fileName := string(key[37:])
fmt.Printf("[blocklistmap] F:%d H:%x N:%s\n", folder, hash, fileName)
case db.KeyTypeVersion:
fmt.Printf("[version] H:%x", key[1:])
var v protocol.Vector
err := v.Unmarshal(it.Value())
if err != nil {
fmt.Printf(" (invalid)\n")
} else {
fmt.Printf(" V:%v\n", v)
}
case db.KeyTypePendingFolder:
device := binary.BigEndian.Uint32(key[1:])
folder := string(key[5:])
var of db.ObservedFolder
of.Unmarshal(it.Value())
fmt.Printf("[pendingFolder] D:%d F:%s V:%v\n", device, folder, of)
case db.KeyTypePendingDevice:
device := "<invalid>"
dev, err := protocol.DeviceIDFromBytes(key[1:])
if err == nil {
device = dev.String()
}
var od db.ObservedDevice
od.Unmarshal(it.Value())
fmt.Printf("[pendingDevice] D:%v V:%v\n", device, od)
default:
fmt.Printf("[??? %d]\n %x\n %x\n", key[0], key, it.Value())
}
}
return nil
}

View File

@@ -4,16 +4,16 @@
// 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 main
package cli
import (
"container/heap"
"encoding/binary"
"fmt"
"log"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
)
type SizedElement struct {
@@ -39,13 +39,18 @@ func (h *ElementHeap) Pop() interface{} {
return x
}
func dumpsize(ldb backend.Backend) {
func indexDumpSize(*cli.Context) error {
ldb, err := getDB()
if err != nil {
return err
}
h := &ElementHeap{}
heap.Init(h)
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
return err
}
var ele SizedElement
for it.Next() {
@@ -96,4 +101,6 @@ func dumpsize(ldb backend.Backend) {
ele = heap.Pop(h).(SizedElement)
fmt.Println(ele.key, ele.size)
}
return nil
}

View File

@@ -4,17 +4,18 @@
// 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 main
package cli
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"log"
"sort"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/protocol"
)
@@ -34,7 +35,12 @@ type sequenceKey struct {
sequence uint64
}
func idxck(ldb backend.Backend) (success bool) {
func indexCheck(*cli.Context) (err error) {
ldb, err := getDB()
if err != nil {
return err
}
folders := make(map[uint32]string)
devices := make(map[uint32]string)
deviceToIDs := make(map[string]uint32)
@@ -43,13 +49,24 @@ func idxck(ldb backend.Backend) (success bool) {
sequences := make(map[sequenceKey]string)
needs := make(map[globalKey]struct{})
blocklists := make(map[string]struct{})
versions := make(map[string]protocol.Vector)
usedBlocklists := make(map[string]struct{})
usedVersions := make(map[string]struct{})
var localDeviceKey uint32
success = true
success := true
defer func() {
if err == nil {
if success {
fmt.Println("Index check completed succesfully.")
} else {
err = errors.New("Inconsistencies found in the index")
}
}
}()
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
return err
}
for it.Next() {
key := it.Key()
@@ -106,6 +123,16 @@ func idxck(ldb backend.Backend) (success bool) {
case db.KeyTypeBlockList:
hash := string(key[1:])
blocklists[hash] = struct{}{}
case db.KeyTypeVersion:
hash := string(key[1:])
var v protocol.Vector
if err := v.Unmarshal(it.Value()); err != nil {
fmt.Println("Unable to unmarshal Vector:", err)
success = false
continue
}
versions[hash] = v
}
}
@@ -157,6 +184,23 @@ func idxck(ldb backend.Backend) (success bool) {
usedBlocklists[key] = struct{}{}
}
}
if fi.VersionHash != nil {
key := string(fi.VersionHash)
if _, ok := versions[key]; !ok {
fmt.Printf("Missing version vector for file %q, version hash %x\n", fi.Name, fi.VersionHash)
success = false
} else {
usedVersions[key] = struct{}{}
}
}
_, ok := globals[globalKey{fk.folder, fk.name}]
if !ok {
fmt.Printf("Missing global for file %q\n", fi.Name)
success = false
continue
}
}
// Aggregate the ranges of missing sequence entries, print them
@@ -190,10 +234,10 @@ func idxck(ldb backend.Backend) (success bool) {
fmt.Printf("Unknown folder ID %d for VersionList %q\n", gk.folder, gk.name)
success = false
}
for i, fv := range vl.Versions {
dev, ok := deviceToIDs[string(fv.Device)]
checkGlobal := func(i int, device []byte, version protocol.Vector, invalid, deleted bool) {
dev, ok := deviceToIDs[string(device)]
if !ok {
fmt.Printf("VersionList %q, folder %q refers to unknown device %q\n", gk.name, folder, fv.Device)
fmt.Printf("VersionList %q, folder %q refers to unknown device %q\n", gk.name, folder, device)
success = false
}
fi, ok := fileInfos[fileInfoKey{gk.folder, dev, gk.name}]
@@ -201,14 +245,31 @@ func idxck(ldb backend.Backend) (success bool) {
fmt.Printf("VersionList %q, folder %q, entry %d refers to unknown FileInfo\n", gk.name, folder, i)
success = false
}
if !fi.Version.Equal(fv.Version) {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo version mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, fv.Version, fi.Version)
fiv := fi.Version
if fi.VersionHash != nil {
fiv = versions[string(fi.VersionHash)]
}
if !fiv.Equal(version) {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo version mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, version, fi.Version)
success = false
}
if fi.IsInvalid() != fv.Invalid {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo invalid mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, fv.Invalid, fi.IsInvalid())
if fi.IsInvalid() != invalid {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo invalid mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, invalid, fi.IsInvalid())
success = false
}
if fi.IsDeleted() != deleted {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo deleted mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, deleted, fi.IsDeleted())
success = false
}
}
for i, fv := range vl.RawVersions {
for _, device := range fv.Devices {
checkGlobal(i, device, fv.Version, false, fv.Deleted)
}
for _, device := range fv.InvalidDevices {
checkGlobal(i, device, fv.Version, true, fv.Deleted)
}
}
// If we need this file we should have a need entry for it. False
@@ -217,7 +278,9 @@ func idxck(ldb backend.Backend) (success bool) {
if needsLocally(vl) {
_, ok := needs[gk]
if !ok {
dev := deviceToIDs[string(vl.Versions[0].Device)]
fv, _ := vl.GetGlobal()
devB, _ := fv.FirstDevice()
dev := deviceToIDs[string(devB)]
fi := fileInfos[fileInfoKey{gk.folder, dev, gk.name}]
if !fi.IsDeleted() && !fi.IsIgnored() {
fmt.Printf("Missing need entry for needed file %q, folder %q\n", gk.name, folder)
@@ -277,20 +340,18 @@ func idxck(ldb backend.Backend) (success bool) {
if d := len(blocklists) - len(usedBlocklists); d > 0 {
fmt.Printf("%d block list entries out of %d needs GC\n", d, len(blocklists))
}
if d := len(versions) - len(usedVersions); d > 0 {
fmt.Printf("%d version entries out of %d needs GC\n", d, len(versions))
}
return
return nil
}
func needsLocally(vl db.VersionList) bool {
var lv *protocol.Vector
for _, fv := range vl.Versions {
if bytes.Equal(fv.Device, protocol.LocalDeviceID[:]) {
lv = &fv.Version
break
}
gfv, gok := vl.GetGlobal()
if !gok { // That's weird, but we hardly need something non-existant
return false
}
if lv == nil {
return true // proviosinally, it looks like we need the file
}
return !lv.GreaterEqual(vl.Versions[0].Version)
fv, ok := vl.Get(protocol.LocalDeviceID[:])
return db.Need(gfv, ok, fv.Version)
}

160
cmd/syncthing/cli/main.go Normal file
View File

@@ -0,0 +1,160 @@
// Copyright (C) 2019 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 cli
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/alecthomas/kong"
"github.com/flynn-archive/go-shlex"
"github.com/pkg/errors"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/lib/config"
)
type preCli struct {
GUIAddress string `name:"gui-address"`
GUIAPIKey string `name:"gui-apikey"`
HomeDir string `name:"home"`
ConfDir string `name:"config"`
DataDir string `name:"data"`
}
func Run() error {
// This is somewhat a hack around a chicken and egg problem. We need to set
// the home directory and potentially other flags to know where the
// syncthing instance is running in order to get it's config ... which we
// then use to construct the actual CLI ... at which point it's too late to
// add flags there...
c := preCli{}
parseFlags(&c)
// Not set as default above because the strings can be really long.
err := cmdutil.SetConfigDataLocationsFromFlags(c.HomeDir, c.ConfDir, c.DataDir)
if err != nil {
return errors.Wrap(err, "Command line options:")
}
clientFactory := &apiClientFactory{
cfg: config.GUIConfiguration{
RawAddress: c.GUIAddress,
APIKey: c.GUIAPIKey,
},
}
configCommand, err := getConfigCommand(clientFactory)
if err != nil {
return err
}
// Implement the same flags at the upper CLI, but do nothing with them.
// This is so that the usage text is the same
fakeFlags := []cli.Flag{
cli.StringFlag{
Name: "gui-address",
Value: "URL",
Usage: "Override GUI address (e.g. \"http://192.0.2.42:8443\")",
},
cli.StringFlag{
Name: "gui-apikey",
Value: "API-KEY",
Usage: "Override GUI API key",
},
cli.StringFlag{
Name: "home",
Value: "PATH",
Usage: "Set configuration and data directory",
},
cli.StringFlag{
Name: "conf",
Value: "PATH",
Usage: "Set configuration directory (config and keys)",
},
}
// Construct the actual CLI
app := cli.NewApp()
app.Author = "The Syncthing Authors"
app.Metadata = map[string]interface{}{
"clientFactory": clientFactory,
}
app.Commands = []cli.Command{{
Name: "cli",
Usage: "Syncthing command line interface",
Flags: fakeFlags,
Subcommands: []cli.Command{
configCommand,
showCommand,
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()
},
},
},
}}
return app.Run(os.Args)
}
func parseFlags(c *preCli) error {
// kong only needs to parse the global arguments after "cli" and before the
// subcommand (if any).
if len(os.Args) <= 2 {
return nil
}
args := os.Args[2:]
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "--") {
args = args[:i]
break
}
if !strings.Contains(args[i], "=") {
i++
}
}
// We don't want kong to print anything nor os.Exit (e.g. on -h)
parser, err := kong.New(c, kong.Writers(ioutil.Discard, ioutil.Discard), kong.Exit(func(int) {}))
if err != nil {
return err
}
_, err = parser.Parse(args)
return err
}

View File

@@ -4,7 +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/.
package main
package cli
import (
"fmt"
@@ -27,11 +27,6 @@ var operationCommand = cli.Command{
Usage: "Shutdown syncthing",
Action: expects(0, emptyPost("system/shutdown")),
},
{
Name: "reset",
Usage: "Reset syncthing deleting all folders and devices",
Action: expects(0, emptyPost("system/reset")),
},
{
Name: "upgrade",
Usage: "Upgrade syncthing (if a newer version is available)",
@@ -39,7 +34,7 @@ var operationCommand = cli.Command{
},
{
Name: "folder-override",
Usage: "Override changes on folder (remote for sendonly, local for receiveonly)",
Usage: "Override changes on folder (remote for sendonly, local for receiveonly). WARNING: Destructive - deletes/changes your data.",
ArgsUsage: "[folder id]",
Action: expects(1, foldersOverride),
},
@@ -47,7 +42,10 @@ var operationCommand = cli.Command{
}
func foldersOverride(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
cfg, err := getConfig(client)
if err != nil {
return err

View File

@@ -4,7 +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/.
package main
package cli
import (
"github.com/urfave/cli"
@@ -18,27 +18,27 @@ var showCommand = cli.Command{
{
Name: "version",
Usage: "Show syncthing client version",
Action: expects(0, dumpOutput("system/version")),
Action: expects(0, indexDumpOutput("system/version")),
},
{
Name: "config-status",
Usage: "Show configuration status, whether or not a restart is required for changes to take effect",
Action: expects(0, dumpOutput("system/config/insync")),
Action: expects(0, indexDumpOutput("config/restart-required")),
},
{
Name: "system",
Usage: "Show system status",
Action: expects(0, dumpOutput("system/status")),
Action: expects(0, indexDumpOutput("system/status")),
},
{
Name: "connections",
Usage: "Report about connections to other devices",
Action: expects(0, dumpOutput("system/connections")),
Action: expects(0, indexDumpOutput("system/connections")),
},
{
Name: "usage",
Usage: "Show usage report",
Action: expects(0, dumpOutput("svc/report")),
Action: expects(0, indexDumpOutput("svc/report")),
},
},
}

View File

@@ -4,16 +4,21 @@
// 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 main
package cli
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"mime"
"net/http"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/locations"
"github.com/urfave/cli"
)
@@ -27,16 +32,25 @@ func responseToBArray(response *http.Response) ([]byte, error) {
func emptyPost(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
_, err := client.Post(url, "")
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
_, err = client.Post(url, "")
return err
}
}
func dumpOutput(url string) cli.ActionFunc {
func indexDumpOutput(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
client, err := getClientFactory(c).getClient()
if err != nil {
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
}
@@ -44,7 +58,43 @@ func dumpOutput(url string) cli.ActionFunc {
}
}
func getConfig(c *APIClient) (config.Configuration, error) {
func saveToFile(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
response, err := client.Get(url)
if err != nil {
return err
}
_, params, err := mime.ParseMediaType(response.Header.Get("Content-Disposition"))
if err != nil {
return err
}
filename := params["filename"]
if filename == "" {
return errors.New("Missing filename in response")
}
bs, err := responseToBArray(response)
if err != nil {
return err
}
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(bs)
if err != nil {
return err
}
fmt.Println("Wrote results to", filename)
return err
}
}
func getConfig(c APIClient) (config.Configuration, error) {
cfg := config.Configuration{}
response, err := c.Get("system/config")
if err != nil {
@@ -92,3 +142,24 @@ func prettyPrintResponse(c *cli.Context, response *http.Response) error {
// TODO: Check flag for pretty print format
return prettyPrintJSON(data)
}
func getDB() (backend.Backend, error) {
return backend.OpenLevelDBRO(locations.Get(locations.Database))
}
func nulString(bs []byte) string {
for i := range bs {
if bs[i] == 0 {
return string(bs[:i])
}
}
return string(bs)
}
func normalizePath(path string) string {
return filepath.ToSlash(filepath.Clean(path))
}
func getClientFactory(c *cli.Context) *apiClientFactory {
return c.App.Metadata["clientFactory"].(*apiClientFactory)
}

View File

@@ -0,0 +1,35 @@
// Copyright (C) 2014 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 cmdutil
import (
"errors"
"github.com/syncthing/syncthing/lib/locations"
)
func SetConfigDataLocationsFromFlags(homeDir, confDir, dataDir string) error {
homeSet := homeDir != ""
confSet := confDir != ""
dataSet := dataDir != ""
switch {
case dataSet != confSet:
return errors.New("either both or none of -conf and -data must be given, use -home to set both at once")
case homeSet && dataSet:
return errors.New("-home must not be used together with -conf and -data")
case homeSet:
confDir = homeDir
dataDir = homeDir
fallthrough
case dataSet:
if err := locations.SetBaseDir(locations.ConfigBaseDir, confDir); err != nil {
return err
}
return locations.SetBaseDir(locations.DataBaseDir, dataDir)
}
return nil
}

View File

@@ -0,0 +1,275 @@
// 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 decrypt implements the `syncthing decrypt` subcommand.
package decrypt
import (
"encoding/binary"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/scanner"
)
type CLI struct {
Path string `arg:"" required:"1" help:"Path to encrypted folder"`
To string `xor:"mode" placeholder:"PATH" help:"Destination directory, when decrypting"`
VerifyOnly bool `xor:"mode" help:"Don't write decrypted files to disk (but verify plaintext hashes)"`
Password string `help:"Folder password for decryption / verification" env:"FOLDER_PASSWORD"`
FolderID string `help:"Folder ID of the encrypted folder, if it cannot be determined automatically"`
Continue bool `help:"Continue processing next file in case of error, instead of aborting"`
Verbose bool `help:"Show verbose progress information"`
TokenPath string `placeholder:"PATH" help:"Path to the token file within the folder (used to determine folder ID)"`
folderKey *[32]byte
}
type storedEncryptionToken struct {
FolderID string
Token []byte
}
func (c *CLI) Run() error {
log.SetFlags(0)
if c.To == "" && !c.VerifyOnly {
return fmt.Errorf("must set --to or --verify")
}
if c.TokenPath == "" {
// This is a bit long to show as default in --help
c.TokenPath = filepath.Join(config.DefaultMarkerName, config.EncryptionTokenName)
}
if c.FolderID == "" {
// We should try to figure out the folder ID
folderID, err := c.getFolderID()
if err != nil {
log.Println("No --folder-id given and couldn't read folder token")
return fmt.Errorf("getting folder ID: %w", err)
}
c.FolderID = folderID
if c.Verbose {
log.Println("Found folder ID:", c.FolderID)
}
}
c.folderKey = protocol.KeyFromPassword(c.FolderID, c.Password)
return c.walk()
}
// walk finds and processes every file in the encrypted folder
func (c *CLI) walk() error {
srcFs := fs.NewFilesystem(fs.FilesystemTypeBasic, c.Path)
var dstFs fs.Filesystem
if c.To != "" {
dstFs = fs.NewFilesystem(fs.FilesystemTypeBasic, c.To)
}
return srcFs.Walk(".", func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsRegular() {
return nil
}
if fs.IsInternal(path) {
return nil
}
return c.withContinue(c.process(srcFs, dstFs, path))
})
}
// If --continue was set we just mention the error and return nil to
// continue processing.
func (c *CLI) withContinue(err error) error {
if err == nil {
return nil
}
if c.Continue {
log.Println("Warning:", err)
return nil
}
return err
}
// getFolderID returns the folder ID found in the encrypted token, or an
// error.
func (c *CLI) getFolderID() (string, error) {
tokenPath := filepath.Join(c.Path, c.TokenPath)
bs, err := ioutil.ReadFile(tokenPath)
if err != nil {
return "", fmt.Errorf("reading folder token: %w", err)
}
var tok storedEncryptionToken
if err := json.Unmarshal(bs, &tok); err != nil {
return "", fmt.Errorf("parsing folder token: %w", err)
}
return tok.FolderID, nil
}
// process handles the file named path in srcFs, decrypting it into dstFs
// unless dstFs is nil.
func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) error {
if c.Verbose {
log.Printf("Processing %q", path)
}
encFd, err := srcFs.Open(path)
if err != nil {
return err
}
defer encFd.Close()
encFi, err := c.loadEncryptedFileInfo(encFd)
if err != nil {
return fmt.Errorf("%s: loading metadata trailer: %w", path, err)
}
// Workaround for a bug in <= v1.15.0-rc.5 where we stored names
// in native format, while protocol expects wire format (slashes).
encFi.Name = osutil.NormalizedFilename(encFi.Name)
plainFi, err := protocol.DecryptFileInfo(*encFi, c.folderKey)
if err != nil {
return fmt.Errorf("%s: decrypting metadata: %w", path, err)
}
if c.Verbose {
log.Printf("Plaintext filename is %q", plainFi.Name)
}
var plainFd fs.File
if dstFs != nil {
if err := dstFs.MkdirAll(filepath.Dir(plainFi.Name), 0700); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
plainFd, err = dstFs.Create(plainFi.Name)
if err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
defer plainFd.Close() // also closed explicitly in the return
}
if err := c.decryptFile(encFi, &plainFi, encFd, plainFd); err != nil {
// Decrypting the file failed, leaving it in an inconsistent state.
// Delete it. Even --continue currently doesn't mean "leave broken
// stuff in place", it just means "try the next file instead of
// aborting".
if plainFd != nil {
_ = dstFs.Remove(plainFd.Name())
}
return fmt.Errorf("%s: %s: %w", path, plainFi.Name, err)
} else if c.Verbose {
log.Printf("Data verified for %q", plainFi.Name)
}
if plainFd != nil {
return plainFd.Close()
}
return nil
}
// decryptFile reads, decrypts and verifies all the blocks in src, writing
// it to dst if dst is non-nil. (If dst is nil it just becomes a
// read-and-verify operation.)
func (c *CLI) decryptFile(encFi *protocol.FileInfo, plainFi *protocol.FileInfo, src io.ReaderAt, dst io.WriterAt) error {
// The encrypted and plaintext files must consist of an equal number of blocks
if len(encFi.Blocks) != len(plainFi.Blocks) {
return fmt.Errorf("block count mismatch: encrypted %d != plaintext %d", len(encFi.Blocks), len(plainFi.Blocks))
}
fileKey := protocol.FileKey(plainFi.Name, c.folderKey)
for i, encBlock := range encFi.Blocks {
// Read the encrypted block
buf := make([]byte, encBlock.Size)
if _, err := src.ReadAt(buf, encBlock.Offset); err != nil {
return fmt.Errorf("encrypted block %d (%d bytes): %w", i, encBlock.Size, err)
}
// Decrypt it
dec, err := protocol.DecryptBytes(buf, fileKey)
if err != nil {
return fmt.Errorf("encrypted block %d (%d bytes): %w", i, encBlock.Size, err)
}
// Verify the block size against the expected plaintext
plainBlock := plainFi.Blocks[i]
if i == len(plainFi.Blocks)-1 && len(dec) > plainBlock.Size {
// The last block might be padded, which is fine (we skip the padding)
dec = dec[:plainBlock.Size]
} else if len(dec) != plainBlock.Size {
return fmt.Errorf("plaintext block %d size mismatch, actual %d != expected %d", i, len(dec), plainBlock.Size)
}
// Verify the hash against the plaintext block info
if !scanner.Validate(dec, plainBlock.Hash, 0) {
// The block decrypted correctly but fails the hash check. This
// is odd and unexpected, but it it's still a valid block from
// the source. The file might have changed while we pulled it?
err := fmt.Errorf("plaintext block %d (%d bytes) failed validation after decryption", i, plainBlock.Size)
if c.Continue {
log.Printf("Warning: %s: %s: %v", encFi.Name, plainFi.Name, err)
} else {
return err
}
}
// Write it to the destination, unless we're just verifying.
if dst != nil {
if _, err := dst.WriteAt(dec, plainBlock.Offset); err != nil {
return err
}
}
}
return nil
}
// loadEncryptedFileInfo loads the encrypted FileInfo trailer from a file on
// disk.
func (c *CLI) loadEncryptedFileInfo(fd fs.File) (*protocol.FileInfo, error) {
// Seek to the size of the trailer block
if _, err := fd.Seek(-4, io.SeekEnd); err != nil {
return nil, err
}
var bs [4]byte
if _, err := io.ReadFull(fd, bs[:]); err != nil {
return nil, err
}
size := int64(binary.BigEndian.Uint32(bs[:]))
// Seek to the start of the trailer
if _, err := fd.Seek(-(4 + size), io.SeekEnd); err != nil {
return nil, err
}
trailer := make([]byte, size)
if _, err := io.ReadFull(fd, trailer); err != nil {
return nil, err
}
var encFi protocol.FileInfo
if err := encFi.Unmarshal(trailer); err != nil {
return nil, err
}
return &encFi, nil
}

View File

@@ -11,24 +11,17 @@ import (
"os"
"runtime"
"runtime/pprof"
"strconv"
"syscall"
"time"
)
func init() {
if innerProcess && os.Getenv("STHEAPPROFILE") != "" {
rate := 1
if i, err := strconv.Atoi(os.Getenv("STHEAPPROFILE")); err == nil {
rate = i
}
l.Debugln("Starting heap profiling")
go func() {
err := saveHeapProfiles(rate) // Only returns on error
l.Warnln("Heap profiler failed:", err)
panic("Heap profiler failed")
}()
}
func startHeapProfiler() {
l.Debugln("Starting heap profiling")
go func() {
err := saveHeapProfiles(1) // Only returns on error
l.Warnln("Heap profiler failed:", err)
panic("Heap profiler failed")
}()
}
func saveHeapProfiles(rate int) error {

View File

File diff suppressed because it is too large Load Diff

View File

@@ -25,8 +25,8 @@ import (
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/svcutil"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/syncthing"
)
var (
@@ -36,20 +36,21 @@ var (
)
const (
countRestarts = 4
loopThreshold = 60 * time.Second
restartCounts = 4
restartPause = 1 * time.Second
restartLoopThreshold = 60 * time.Second
logFileAutoCloseDelay = 5 * time.Second
logFileMaxOpenTime = time.Minute
panicUploadMaxWait = 30 * time.Second
panicUploadNoticeWait = 10 * time.Second
)
func monitorMain(runtimeOptions RuntimeOptions) {
func monitorMain(options serveOptions) {
l.SetPrefix("[monitor] ")
var dst io.Writer = os.Stdout
logFile := runtimeOptions.logFile
logFile := options.LogFile
if logFile != "-" {
if expanded, err := fs.ExpandTilde(logFile); err == nil {
logFile = expanded
@@ -59,8 +60,8 @@ func monitorMain(runtimeOptions RuntimeOptions) {
open := func(name string) (io.WriteCloser, error) {
return newAutoclosedFile(name, logFileAutoCloseDelay, logFileMaxOpenTime)
}
if runtimeOptions.logMaxSize > 0 {
fileDst, err = newRotatedFile(logFile, open, int64(runtimeOptions.logMaxSize), runtimeOptions.logMaxFiles)
if options.LogMaxSize > 0 {
fileDst, err = newRotatedFile(logFile, open, int64(options.LogMaxSize), options.LogMaxFiles)
} else {
fileDst, err = open(logFile)
}
@@ -84,7 +85,7 @@ func monitorMain(runtimeOptions RuntimeOptions) {
}
args := os.Args
var restarts [countRestarts]time.Time
var restarts [restartCounts]time.Time
stopSign := make(chan os.Signal, 1)
signal.Notify(stopSign, os.Interrupt, sigTerm)
@@ -97,9 +98,9 @@ func monitorMain(runtimeOptions RuntimeOptions) {
for {
maybeReportPanics()
if t := time.Since(restarts[0]); t < loopThreshold {
l.Warnf("%d restarts in %v; not retrying further", countRestarts, t)
os.Exit(syncthing.ExitError.AsInt())
if t := time.Since(restarts[0]); t < restartLoopThreshold {
l.Warnf("%d restarts in %v; not retrying further", restartCounts, t)
os.Exit(svcutil.ExitError.AsInt())
}
copy(restarts[0:], restarts[1:])
@@ -169,15 +170,15 @@ func monitorMain(runtimeOptions RuntimeOptions) {
if err == nil {
// Successful exit indicates an intentional shutdown
os.Exit(syncthing.ExitSuccess.AsInt())
os.Exit(svcutil.ExitSuccess.AsInt())
}
if exiterr, ok := err.(*exec.ExitError); ok {
exitCode := exiterr.ExitCode()
if stopped || runtimeOptions.noRestart {
if stopped || options.NoRestart {
os.Exit(exitCode)
}
if exitCode == syncthing.ExitUpgrade.AsInt() {
if exitCode == svcutil.ExitUpgrade.AsInt() {
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
l.Infoln("Restarting monitor...")
@@ -188,12 +189,12 @@ func monitorMain(runtimeOptions RuntimeOptions) {
}
}
if runtimeOptions.noRestart {
os.Exit(syncthing.ExitError.AsInt())
if options.NoRestart {
os.Exit(svcutil.ExitError.AsInt())
}
l.Infoln("Syncthing exited:", err)
time.Sleep(1 * time.Second)
time.Sleep(restartPause)
if first {
// Let the next child process know that this is not the first time
@@ -311,6 +312,11 @@ func copyStdout(stdout io.Reader, dst io.Writer) {
}
func restartMonitor(args []string) error {
// Set the STRESTART environment variable to indicate to the next
// process that this is a restart and not initial start. This prevents
// opening the browser on startup.
os.Setenv("STRESTART", "yes")
if runtime.GOOS != "windows" {
// syscall.Exec is the cleanest way to restart on Unixes as it
// replaces the current process with the new one, keeping the pid and
@@ -558,7 +564,7 @@ func childEnv() []string {
// panicUploadMaxWait uploading panics...
func maybeReportPanics() {
// Try to get a config to see if/where panics should be reported.
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger, true)
if err != nil {
l.Warnln("Couldn't load config; not reporting crash")
return

View File

@@ -0,0 +1,13 @@
// 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/.
// +build !windows
package main
type buildServeOptions struct {
HideConsole bool `hidden:""`
}

View File

@@ -0,0 +1,11 @@
// 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 main
type buildServeOptions struct {
HideConsole bool `name:"no-console" help:"Hide console window"`
}

View File

@@ -18,10 +18,8 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
)
func init() {
if innerProcess && os.Getenv("STPERFSTATS") != "" {
go savePerfStats(fmt.Sprintf("perfstats-%d.csv", syscall.Getpid()))
}
func startPerfStats() {
go savePerfStats(fmt.Sprintf("perfstats-%d.csv", syscall.Getpid()))
}
func savePerfStats(file string) {

View File

@@ -1,13 +1,12 @@
// Copyright (C) 2017 The Syncthing Authors.
// 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/.
//+build noupgrade
// +build solaris windows
package build
package main
func init() {
Tags = append(Tags, "noupgrade")
func startPerfStats() {
}

View File

@@ -1,57 +0,0 @@
// Copyright (C) 2014 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 main
import (
"bytes"
"flag"
"fmt"
"io"
"text/tabwriter"
)
func optionTable(w io.Writer, rows [][]string) {
tw := tabwriter.NewWriter(w, 2, 4, 2, ' ', 0)
for _, row := range rows {
for i, cell := range row {
if i > 0 {
tw.Write([]byte("\t"))
}
tw.Write([]byte(cell))
}
tw.Write([]byte("\n"))
}
tw.Flush()
}
func usageFor(fs *flag.FlagSet, usage string, extra string) func() {
return func() {
var b bytes.Buffer
b.WriteString("Usage:\n " + usage + "\n")
var options [][]string
fs.VisitAll(func(f *flag.Flag) {
var opt = " -" + f.Name
if f.DefValue != "false" {
opt += "=" + fmt.Sprintf(`"%s"`, f.DefValue)
}
options = append(options, []string{opt, f.Usage})
})
if len(options) > 0 {
b.WriteString("\nOptions:\n")
optionTable(&b, options)
}
fmt.Println(b.String())
if len(extra) > 0 {
fmt.Println(extra)
}
}
}

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")
}
@@ -135,35 +135,35 @@ func setupDB(db *sql.DB) error {
row := db.QueryRow(`SELECT 'UniqueDayVersionIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE UNIQUE INDEX UniqueDayVersionIndex ON VersionSummary (Day, Version)`)
_, _ = db.Exec(`CREATE UNIQUE INDEX UniqueDayVersionIndex ON VersionSummary (Day, Version)`)
}
row = db.QueryRow(`SELECT 'VersionDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX VersionDayIndex ON VersionSummary (Day)`)
_, _ = db.Exec(`CREATE INDEX VersionDayIndex ON VersionSummary (Day)`)
}
row = db.QueryRow(`SELECT 'MovementDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX MovementDayIndex ON UserMovement (Day)`)
_, _ = db.Exec(`CREATE INDEX MovementDayIndex ON UserMovement (Day)`)
}
row = db.QueryRow(`SELECT 'PerformanceDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX PerformanceDayIndex ON Performance (Day)`)
_, _ = db.Exec(`CREATE INDEX PerformanceDayIndex ON Performance (Day)`)
}
row = db.QueryRow(`SELECT 'BlockStatsDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX BlockStatsDayIndex ON BlockStats (Day)`)
_, _ = db.Exec(`CREATE INDEX BlockStatsDayIndex ON BlockStats (Day)`)
}
return err
return nil
}
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{}
@@ -175,13 +175,13 @@ func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
res, err := db.Exec(`INSERT INTO VersionSummary (
SELECT
DATE_TRUNC('day', Received) AS Day,
SUBSTRING(Version FROM '^v\d.\d+') AS Ver,
SUBSTRING(Report->>'version' FROM '^v\d.\d+') AS Ver,
COUNT(*) AS Count
FROM Reports
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND Version like 'v_.%'
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
GROUP BY Day, Ver
);
`, since)
@@ -195,11 +195,12 @@ func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
func aggregateUserMovement(db *sql.DB) (int64, error) {
rows, err := db.Query(`SELECT
DATE_TRUNC('day', Received) AS Day,
UniqueID
FROM Reports
Report->>'uniqueID'
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND Version like 'v_.%'
Report->>'uniqueID' IS NOT NULL
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
ORDER BY Day
`)
if err != nil {
@@ -276,16 +277,18 @@ func aggregatePerformance(db *sql.DB, since time.Time) (int64, error) {
res, err := db.Exec(`INSERT INTO Performance (
SELECT
DATE_TRUNC('day', Received) AS Day,
AVG(TotFiles) As TotFiles,
AVG(TotMiB) As TotMiB,
AVG(SHA256Perf) As SHA256Perf,
AVG(MemorySize) As MemorySize,
AVG(MemoryUsageMiB) As MemoryUsageMiB
FROM Reports
AVG((Report->>'totFiles')::numeric) As TotFiles,
AVG((Report->>'totMiB')::numeric) As TotMiB,
AVG((Report->>'sha256Perf')::numeric) As SHA256Perf,
AVG((Report->>'memorySize')::numeric) As MemorySize,
AVG((Report->>'memoryUsageMiB')::numeric) As MemoryUsageMiB
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND Version like 'v_.%'
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)
@@ -303,22 +306,22 @@ func aggregateBlockStats(db *sql.DB, since time.Time) (int64, error) {
SELECT
DATE_TRUNC('day', Received) AS Day,
COUNT(1) As Reports,
SUM(BlocksTotal) AS Total,
SUM(BlocksRenamed) AS Renamed,
SUM(BlocksReused) AS Reused,
SUM(BlocksPulled) AS Pulled,
SUM(BlocksCopyOrigin) AS CopyOrigin,
SUM(BlocksCopyOriginShifted) AS CopyOriginShifted,
SUM(BlocksCopyElsewhere) AS CopyElsewhere
FROM Reports
SUM((Report->'blockStats'->>'total')::numeric) AS Total,
SUM((Report->'blockStats'->>'renamed')::numeric) AS Renamed,
SUM((Report->'blockStats'->>'reused')::numeric) AS Reused,
SUM((Report->'blockStats'->>'pulled')::numeric) AS Pulled,
SUM((Report->'blockStats'->>'copyOrigin')::numeric) AS CopyOrigin,
SUM((Report->'blockStats'->>'copyOriginShifted')::numeric) AS CopyOriginShifted,
SUM((Report->'blockStats'->>'copyElsewhere')::numeric) AS CopyElsewhere
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND ReportVersion = 3
AND Version like 'v_.%'
AND Version NOT LIKE 'v0.14.40%'
AND Version NOT LIKE 'v0.14.39%'
AND Version NOT LIKE 'v0.14.38%'
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%'
AND Report->>'version' NOT LIKE 'v0.14.39%'
AND Report->>'version' NOT LIKE 'v0.14.38%'
GROUP BY Day
);
`, since)

View File

@@ -114,6 +114,23 @@ func statsForInts(data []int) [4]float64 {
return res
}
func statsForInt64s(data []int64) [4]float64 {
var res [4]float64
if len(data) == 0 {
return res
}
sort.Slice(data, func(a, b int) bool {
return data[a] < data[b]
})
res[0] = float64(data[int(float64(len(data))*0.05)])
res[1] = float64(data[len(data)/2])
res[2] = float64(data[int(float64(len(data))*0.95)])
res[3] = float64(data[len(data)-1])
return res
}
func statsForFloats(data []float64) [4]float64 {
var res [4]float64
if len(data) == 0 {

View File

@@ -10,10 +10,7 @@ import (
"bytes"
"crypto/tls"
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"html/template"
"io"
"io/ioutil"
@@ -23,13 +20,16 @@ import (
"os"
"regexp"
"sort"
"strconv"
"strings"
"sync"
"time"
"unicode"
"github.com/lib/pq"
geoip2 "github.com/oschwald/geoip2-golang"
"github.com/oschwald/geoip2-golang"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/ur/contract"
)
var (
@@ -55,7 +55,7 @@ var (
{regexp.MustCompile("jenkins@build.syncthing.net"), "GitHub"},
{regexp.MustCompile("snap@build.syncthing.net"), "Snapcraft"},
{regexp.MustCompile("android-.*vagrant@basebox-stretch64"), "F-Droid"},
{regexp.MustCompile("builduser@svetlemodry"), "Arch (3rd party)"},
{regexp.MustCompile("builduser@(archlinux|svetlemodry)"), "Arch (3rd party)"},
{regexp.MustCompile("synology@kastelo.net"), "Synology (Kastelo)"},
{regexp.MustCompile("@debian"), "Debian (3rd party)"},
{regexp.MustCompile("@fedora"), "Fedora (3rd party)"},
@@ -89,7 +89,7 @@ var funcs = map[string]interface{}{
parts = append(parts, part)
}
if len(input) > 0 {
parts = append(parts, input[:])
parts = append(parts, input)
}
return parts[whichPart-1]
},
@@ -102,585 +102,44 @@ func getEnvDefault(key, def string) string {
return def
}
type IntMap map[string]int
func (p IntMap) Value() (driver.Value, error) {
return json.Marshal(p)
}
func (p *IntMap) Scan(src interface{}) error {
source, ok := src.([]byte)
if !ok {
return errors.New("Type assertion .([]byte) failed.")
}
var i map[string]int
err := json.Unmarshal(source, &i)
if err != nil {
return err
}
*p = i
return nil
}
type report struct {
Received time.Time // Only from DB
UniqueID string
Version string
LongVersion string
Platform string
NumFolders int
NumDevices int
TotFiles int
FolderMaxFiles int
TotMiB int
FolderMaxMiB int
MemoryUsageMiB int
SHA256Perf float64
MemorySize int
// v2 fields
URVersion int
NumCPU int
FolderUses struct {
SendOnly int
ReceiveOnly int
IgnorePerms int
IgnoreDelete int
AutoNormalize int
SimpleVersioning int
ExternalVersioning int
StaggeredVersioning int
TrashcanVersioning int
}
DeviceUses struct {
Introducer int
CustomCertName int
CompressAlways int
CompressMetadata int
CompressNever int
DynamicAddr int
StaticAddr int
}
Announce struct {
GlobalEnabled bool
LocalEnabled bool
DefaultServersDNS int
DefaultServersIP int
OtherServers int
}
Relays struct {
Enabled bool
DefaultServers int
OtherServers int
}
UsesRateLimit bool
UpgradeAllowedManual bool
UpgradeAllowedAuto bool
// V2.5 fields (fields that were in v2 but never added to the database
UpgradeAllowedPre bool
RescanIntvs pq.Int64Array
// v3 fields
Uptime int
NATType string
AlwaysLocalNets bool
CacheIgnoredFiles bool
OverwriteRemoteDeviceNames bool
ProgressEmitterEnabled bool
CustomDefaultFolderPath bool
WeakHashSelection string
CustomTrafficClass bool
CustomTempIndexMinBlocks bool
TemporariesDisabled bool
TemporariesCustom bool
LimitBandwidthInLan bool
CustomReleaseURL bool
RestartOnWakeup bool
CustomStunServers bool
FolderUsesV3 struct {
ScanProgressDisabled int
ConflictsDisabled int
ConflictsUnlimited int
ConflictsOther int
DisableSparseFiles int
DisableTempIndexes int
AlwaysWeakHash int
CustomWeakHashThreshold int
FsWatcherEnabled int
PullOrder IntMap
FilesystemType IntMap
FsWatcherDelays pq.Int64Array
}
GUIStats struct {
Enabled int
UseTLS int
UseAuth int
InsecureAdminAccess int
Debugging int
InsecureSkipHostCheck int
InsecureAllowFrameLoading int
ListenLocal int
ListenUnspecified int
Theme IntMap
}
BlockStats struct {
Total int
Renamed int
Reused int
Pulled int
CopyOrigin int
CopyOriginShifted int
CopyElsewhere int
}
TransportStats IntMap
IgnoreStats struct {
Lines int
Inverts int
Folded int
Deletable int
Rooted int
Includes int
EscapedIncludes int
DoubleStars int
Stars int
}
// V3 fields added late in the RC
WeakHashEnabled bool
// Generated
Date string
Address string
}
func (r *report) Validate() error {
if r.UniqueID == "" || r.Version == "" || r.Platform == "" {
return errors.New("missing required field")
}
if len(r.Date) != 8 {
return errors.New("date not initialized")
}
// Some fields may not be null.
if r.RescanIntvs == nil {
r.RescanIntvs = []int64{}
}
if r.FolderUsesV3.FsWatcherDelays == nil {
r.FolderUsesV3.FsWatcherDelays = []int64{}
}
return nil
}
func (r *report) FieldPointers() []interface{} {
// All the fields of the report, in the same order as the database fields.
return []interface{}{
&r.Received, &r.UniqueID, &r.Version, &r.LongVersion, &r.Platform,
&r.NumFolders, &r.NumDevices, &r.TotFiles, &r.FolderMaxFiles,
&r.TotMiB, &r.FolderMaxMiB, &r.MemoryUsageMiB, &r.SHA256Perf,
&r.MemorySize, &r.Date,
// V2
&r.URVersion, &r.NumCPU, &r.FolderUses.SendOnly, &r.FolderUses.IgnorePerms,
&r.FolderUses.IgnoreDelete, &r.FolderUses.AutoNormalize, &r.DeviceUses.Introducer,
&r.DeviceUses.CustomCertName, &r.DeviceUses.CompressAlways,
&r.DeviceUses.CompressMetadata, &r.DeviceUses.CompressNever,
&r.DeviceUses.DynamicAddr, &r.DeviceUses.StaticAddr,
&r.Announce.GlobalEnabled, &r.Announce.LocalEnabled,
&r.Announce.DefaultServersDNS, &r.Announce.DefaultServersIP,
&r.Announce.OtherServers, &r.Relays.Enabled, &r.Relays.DefaultServers,
&r.Relays.OtherServers, &r.UsesRateLimit, &r.UpgradeAllowedManual,
&r.UpgradeAllowedAuto, &r.FolderUses.SimpleVersioning,
&r.FolderUses.ExternalVersioning, &r.FolderUses.StaggeredVersioning,
&r.FolderUses.TrashcanVersioning,
// V2.5
&r.UpgradeAllowedPre, &r.RescanIntvs,
// V3
&r.Uptime, &r.NATType, &r.AlwaysLocalNets, &r.CacheIgnoredFiles,
&r.OverwriteRemoteDeviceNames, &r.ProgressEmitterEnabled, &r.CustomDefaultFolderPath,
&r.WeakHashSelection, &r.CustomTrafficClass, &r.CustomTempIndexMinBlocks,
&r.TemporariesDisabled, &r.TemporariesCustom, &r.LimitBandwidthInLan,
&r.CustomReleaseURL, &r.RestartOnWakeup, &r.CustomStunServers,
&r.FolderUsesV3.ScanProgressDisabled, &r.FolderUsesV3.ConflictsDisabled,
&r.FolderUsesV3.ConflictsUnlimited, &r.FolderUsesV3.ConflictsOther,
&r.FolderUsesV3.DisableSparseFiles, &r.FolderUsesV3.DisableTempIndexes,
&r.FolderUsesV3.AlwaysWeakHash, &r.FolderUsesV3.CustomWeakHashThreshold,
&r.FolderUsesV3.FsWatcherEnabled,
&r.FolderUsesV3.PullOrder, &r.FolderUsesV3.FilesystemType,
&r.FolderUsesV3.FsWatcherDelays,
&r.GUIStats.Enabled, &r.GUIStats.UseTLS, &r.GUIStats.UseAuth,
&r.GUIStats.InsecureAdminAccess,
&r.GUIStats.Debugging, &r.GUIStats.InsecureSkipHostCheck,
&r.GUIStats.InsecureAllowFrameLoading, &r.GUIStats.ListenLocal,
&r.GUIStats.ListenUnspecified, &r.GUIStats.Theme,
&r.BlockStats.Total, &r.BlockStats.Renamed,
&r.BlockStats.Reused, &r.BlockStats.Pulled, &r.BlockStats.CopyOrigin,
&r.BlockStats.CopyOriginShifted, &r.BlockStats.CopyElsewhere,
&r.TransportStats,
&r.IgnoreStats.Lines, &r.IgnoreStats.Inverts, &r.IgnoreStats.Folded,
&r.IgnoreStats.Deletable, &r.IgnoreStats.Rooted, &r.IgnoreStats.Includes,
&r.IgnoreStats.EscapedIncludes, &r.IgnoreStats.DoubleStars, &r.IgnoreStats.Stars,
// V3 added late in the RC
&r.WeakHashEnabled,
&r.Address,
// Receive only folders
&r.FolderUses.ReceiveOnly,
}
}
func (r *report) FieldNames() []string {
// The database fields that back this struct in PostgreSQL
return []string{
// V1
"Received",
"UniqueID",
"Version",
"LongVersion",
"Platform",
"NumFolders",
"NumDevices",
"TotFiles",
"FolderMaxFiles",
"TotMiB",
"FolderMaxMiB",
"MemoryUsageMiB",
"SHA256Perf",
"MemorySize",
"Date",
// V2
"ReportVersion",
"NumCPU",
"FolderRO",
"FolderIgnorePerms",
"FolderIgnoreDelete",
"FolderAutoNormalize",
"DeviceIntroducer",
"DeviceCustomCertName",
"DeviceCompressAlways",
"DeviceCompressMetadata",
"DeviceCompressNever",
"DeviceDynamicAddr",
"DeviceStaticAddr",
"AnnounceGlobalEnabled",
"AnnounceLocalEnabled",
"AnnounceDefaultServersDNS",
"AnnounceDefaultServersIP",
"AnnounceOtherServers",
"RelayEnabled",
"RelayDefaultServers",
"RelayOtherServers",
"RateLimitEnabled",
"UpgradeAllowedManual",
"UpgradeAllowedAuto",
// v0.12.19+
"FolderSimpleVersioning",
"FolderExternalVersioning",
"FolderStaggeredVersioning",
"FolderTrashcanVersioning",
// V2.5
"UpgradeAllowedPre",
"RescanIntvs",
// V3
"Uptime",
"NATType",
"AlwaysLocalNets",
"CacheIgnoredFiles",
"OverwriteRemoteDeviceNames",
"ProgressEmitterEnabled",
"CustomDefaultFolderPath",
"WeakHashSelection",
"CustomTrafficClass",
"CustomTempIndexMinBlocks",
"TemporariesDisabled",
"TemporariesCustom",
"LimitBandwidthInLan",
"CustomReleaseURL",
"RestartOnWakeup",
"CustomStunServers",
"FolderScanProgressDisabled",
"FolderConflictsDisabled",
"FolderConflictsUnlimited",
"FolderConflictsOther",
"FolderDisableSparseFiles",
"FolderDisableTempIndexes",
"FolderAlwaysWeakHash",
"FolderCustomWeakHashThreshold",
"FolderFsWatcherEnabled",
"FolderPullOrder",
"FolderFilesystemType",
"FolderFsWatcherDelays",
"GUIEnabled",
"GUIUseTLS",
"GUIUseAuth",
"GUIInsecureAdminAccess",
"GUIDebugging",
"GUIInsecureSkipHostCheck",
"GUIInsecureAllowFrameLoading",
"GUIListenLocal",
"GUIListenUnspecified",
"GUITheme",
"BlocksTotal",
"BlocksRenamed",
"BlocksReused",
"BlocksPulled",
"BlocksCopyOrigin",
"BlocksCopyOriginShifted",
"BlocksCopyElsewhere",
"Transport",
"IgnoreLines",
"IgnoreInverts",
"IgnoreFolded",
"IgnoreDeletable",
"IgnoreRooted",
"IgnoreIncludes",
"IgnoreEscapedIncludes",
"IgnoreDoubleStars",
"IgnoreStars",
// V3 added late in the RC
"WeakHashEnabled",
"Address",
// Receive only folders
"FolderRecvOnly",
}
}
func setupDB(db *sql.DB) error {
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS Reports (
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS ReportsJson (
Received TIMESTAMP NOT NULL,
UniqueID VARCHAR(32) NOT NULL,
Version VARCHAR(32) NOT NULL,
LongVersion VARCHAR(256) NOT NULL,
Platform VARCHAR(32) NOT NULL,
NumFolders INTEGER NOT NULL,
NumDevices INTEGER NOT NULL,
TotFiles INTEGER NOT NULL,
FolderMaxFiles INTEGER NOT NULL,
TotMiB INTEGER NOT NULL,
FolderMaxMiB INTEGER NOT NULL,
MemoryUsageMiB INTEGER NOT NULL,
SHA256Perf DOUBLE PRECISION NOT NULL,
MemorySize INTEGER NOT NULL,
Date VARCHAR(8) NOT NULL
Report JSONB NOT NULL
)`)
if err != nil {
return err
}
var t string
row := db.QueryRow(`SELECT 'UniqueIDIndex'::regclass`)
if err := row.Scan(&t); err != nil {
if _, err = db.Exec(`CREATE UNIQUE INDEX UniqueIDIndex ON Reports (Date, UniqueID)`); err != nil {
if err := db.QueryRow(`SELECT 'UniqueIDJsonIndex'::regclass`).Scan(&t); err != nil {
if _, err = db.Exec(`CREATE UNIQUE INDEX UniqueIDJsonIndex ON ReportsJson ((Report->>'date'), (Report->>'uniqueID'))`); err != nil {
return err
}
}
row = db.QueryRow(`SELECT 'ReceivedIndex'::regclass`)
if err := row.Scan(&t); err != nil {
if _, err = db.Exec(`CREATE INDEX ReceivedIndex ON Reports (Received)`); err != nil {
if err := db.QueryRow(`SELECT 'ReceivedJsonIndex'::regclass`).Scan(&t); err != nil {
if _, err = db.Exec(`CREATE INDEX ReceivedJsonIndex ON ReportsJson (Received)`); err != nil {
return err
}
}
// V2
row = db.QueryRow(`SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'reports') AND attname = 'reportversion'`)
if err := row.Scan(&t); err != nil {
// The ReportVersion column doesn't exist; add the new columns.
_, err = db.Exec(`ALTER TABLE Reports
ADD COLUMN ReportVersion INTEGER NOT NULL DEFAULT 0,
ADD COLUMN NumCPU INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderRO INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderIgnorePerms INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderIgnoreDelete INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderAutoNormalize INTEGER NOT NULL DEFAULT 0,
ADD COLUMN DeviceIntroducer INTEGER NOT NULL DEFAULT 0,
ADD COLUMN DeviceCustomCertName INTEGER NOT NULL DEFAULT 0,
ADD COLUMN DeviceCompressAlways INTEGER NOT NULL DEFAULT 0,
ADD COLUMN DeviceCompressMetadata INTEGER NOT NULL DEFAULT 0,
ADD COLUMN DeviceCompressNever INTEGER NOT NULL DEFAULT 0,
ADD COLUMN DeviceDynamicAddr INTEGER NOT NULL DEFAULT 0,
ADD COLUMN DeviceStaticAddr INTEGER NOT NULL DEFAULT 0,
ADD COLUMN AnnounceGlobalEnabled BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN AnnounceLocalEnabled BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN AnnounceDefaultServersDNS INTEGER NOT NULL DEFAULT 0,
ADD COLUMN AnnounceDefaultServersIP INTEGER NOT NULL DEFAULT 0,
ADD COLUMN AnnounceOtherServers INTEGER NOT NULL DEFAULT 0,
ADD COLUMN RelayEnabled BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN RelayDefaultServers INTEGER NOT NULL DEFAULT 0,
ADD COLUMN RelayOtherServers INTEGER NOT NULL DEFAULT 0,
ADD COLUMN RateLimitEnabled BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN UpgradeAllowedManual BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN UpgradeAllowedAuto BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN FolderSimpleVersioning INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderExternalVersioning INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderStaggeredVersioning INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderTrashcanVersioning INTEGER NOT NULL DEFAULT 0
`)
if err != nil {
if err := db.QueryRow(`SELECT 'ReportVersionJsonIndex'::regclass`).Scan(&t); err != nil {
if _, err = db.Exec(`CREATE INDEX ReportVersionJsonIndex ON ReportsJson (cast((Report->>'urVersion') as numeric))`); err != nil {
return err
}
}
row = db.QueryRow(`SELECT 'ReportVersionIndex'::regclass`)
if err := row.Scan(&t); err != nil {
if _, err = db.Exec(`CREATE INDEX ReportVersionIndex ON Reports (ReportVersion)`); err != nil {
return err
}
}
// V2.5
row = db.QueryRow(`SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'reports') AND attname = 'upgradeallowedpre'`)
if err := row.Scan(&t); err != nil {
// The ReportVersion column doesn't exist; add the new columns.
_, err = db.Exec(`ALTER TABLE Reports
ADD COLUMN UpgradeAllowedPre BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN RescanIntvs INT[] NOT NULL DEFAULT '{}'
`)
if err != nil {
return err
}
}
// V3
row = db.QueryRow(`SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'reports') AND attname = 'uptime'`)
if err := row.Scan(&t); err != nil {
// The Uptime column doesn't exist; add the new columns.
_, err = db.Exec(`ALTER TABLE Reports
ADD COLUMN Uptime INTEGER NOT NULL DEFAULT 0,
ADD COLUMN NATType VARCHAR(32) NOT NULL DEFAULT '',
ADD COLUMN AlwaysLocalNets BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN CacheIgnoredFiles BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN OverwriteRemoteDeviceNames BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN ProgressEmitterEnabled BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN CustomDefaultFolderPath BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN WeakHashSelection VARCHAR(32) NOT NULL DEFAULT '',
ADD COLUMN CustomTrafficClass BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN CustomTempIndexMinBlocks BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN TemporariesDisabled BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN TemporariesCustom BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN LimitBandwidthInLan BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN CustomReleaseURL BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN RestartOnWakeup BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN CustomStunServers BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN FolderScanProgressDisabled INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderConflictsDisabled INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderConflictsUnlimited INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderConflictsOther INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderDisableSparseFiles INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderDisableTempIndexes INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderAlwaysWeakHash INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderCustomWeakHashThreshold INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderFsWatcherEnabled INTEGER NOT NULL DEFAULT 0,
ADD COLUMN FolderPullOrder JSONB NOT NULL DEFAULT '{}',
ADD COLUMN FolderFilesystemType JSONB NOT NULL DEFAULT '{}',
ADD COLUMN FolderFsWatcherDelays INT[] NOT NULL DEFAULT '{}',
ADD COLUMN GUIEnabled INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIUseTLS INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIUseAuth INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIInsecureAdminAccess INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIDebugging INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIInsecureSkipHostCheck INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIInsecureAllowFrameLoading INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIListenLocal INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUIListenUnspecified INTEGER NOT NULL DEFAULT 0,
ADD COLUMN GUITheme JSONB NOT NULL DEFAULT '{}',
ADD COLUMN BlocksTotal INTEGER NOT NULL DEFAULT 0,
ADD COLUMN BlocksRenamed INTEGER NOT NULL DEFAULT 0,
ADD COLUMN BlocksReused INTEGER NOT NULL DEFAULT 0,
ADD COLUMN BlocksPulled INTEGER NOT NULL DEFAULT 0,
ADD COLUMN BlocksCopyOrigin INTEGER NOT NULL DEFAULT 0,
ADD COLUMN BlocksCopyOriginShifted INTEGER NOT NULL DEFAULT 0,
ADD COLUMN BlocksCopyElsewhere INTEGER NOT NULL DEFAULT 0,
ADD COLUMN Transport JSONB NOT NULL DEFAULT '{}',
ADD COLUMN IgnoreLines INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreInverts INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreFolded INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreDeletable INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreRooted INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreIncludes INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreEscapedIncludes INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreDoubleStars INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IgnoreStars INTEGER NOT NULL DEFAULT 0
`)
if err != nil {
return err
}
}
// V3 added late in the RC
row = db.QueryRow(`SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'reports') AND attname = 'weakhashenabled'`)
if err := row.Scan(&t); err != nil {
// The WeakHashEnabled column doesn't exist; add the new columns.
_, err = db.Exec(`ALTER TABLE Reports
ADD COLUMN WeakHashEnabled BOOLEAN NOT NULL DEFAULT FALSE
ADD COLUMN Address VARCHAR(45) NOT NULL DEFAULT ''
`)
if err != nil {
return err
}
}
// Receive only added ad-hoc
row = db.QueryRow(`SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'reports') AND attname = 'folderrecvonly'`)
if err := row.Scan(&t); err != nil {
// The RecvOnly column doesn't exist; add it.
_, err = db.Exec(`ALTER TABLE Reports
ADD COLUMN FolderRecvOnly INTEGER NOT NULL DEFAULT 0
`)
if err != nil {
return err
}
// Migrate from old schema to new schema if the table exists.
if err := migrate(db); err != nil {
return err
}
return nil
}
func insertReport(db *sql.DB, r report) error {
r.Received = time.Now().UTC()
fields := r.FieldPointers()
params := make([]string, len(fields))
for i := range params {
params[i] = fmt.Sprintf("$%d", i+1)
}
query := "INSERT INTO Reports (" + strings.Join(r.FieldNames(), ", ") + ") VALUES (" + strings.Join(params, ", ") + ")"
_, err := db.Exec(query, fields...)
func insertReport(db *sql.DB, r contract.Report) error {
_, err := db.Exec("INSERT INTO ReportsJson (Report, Received) VALUES ($1, $2)", r, time.Now().UTC())
return err
}
@@ -688,9 +147,9 @@ func insertReport(db *sql.DB, r report) error {
type withDBFunc func(*sql.DB, http.ResponseWriter, *http.Request)
func withDB(db *sql.DB, f withDBFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
f(db, w, r)
})
}
}
func main() {
@@ -754,6 +213,7 @@ func main() {
http.HandleFunc("/movement.json", withDB(db, movementHandler))
http.HandleFunc("/performance.json", withDB(db, performanceHandler))
http.HandleFunc("/blockstats.json", withDB(db, blockStatsHandler))
http.HandleFunc("/locations.json", withDB(db, locationsHandler))
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
go cacheRefresher(db)
@@ -765,9 +225,10 @@ func main() {
}
var (
cacheData []byte
cacheTime time.Time
cacheMut sync.Mutex
cachedIndex []byte
cachedLocations []byte
cacheTime time.Time
cacheMut sync.Mutex
)
const maxCacheTime = 15 * time.Minute
@@ -775,7 +236,7 @@ const maxCacheTime = 15 * time.Minute
func cacheRefresher(db *sql.DB) {
ticker := time.NewTicker(maxCacheTime - time.Minute)
defer ticker.Stop()
for range ticker.C {
for ; true; <-ticker.C {
cacheMut.Lock()
if err := refreshCacheLocked(db); err != nil {
log.Println(err)
@@ -791,8 +252,15 @@ func refreshCacheLocked(db *sql.DB) error {
if err != nil {
return err
}
cacheData = buf.Bytes()
cachedIndex = buf.Bytes()
cacheTime = time.Now()
locs := rep["locations"].(map[location]int)
wlocs := make([]weightedLocation, 0, len(locs))
for loc, w := range locs {
wlocs = append(wlocs, weightedLocation{loc, w})
}
cachedLocations, _ = json.Marshal(wlocs)
return nil
}
@@ -810,13 +278,29 @@ func rootHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write(cacheData)
w.Write(cachedIndex)
} else {
http.Error(w, "Not found", 404)
return
}
}
func locationsHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
cacheMut.Lock()
defer cacheMut.Unlock()
if time.Since(cacheTime) > maxCacheTime {
if err := refreshCacheLocked(db); err != nil {
log.Println(err)
http.Error(w, "Template Error", http.StatusInternalServerError)
return
}
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(cachedLocations)
}
func newDataHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
@@ -835,7 +319,7 @@ func newDataHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
addr = ""
}
var rep report
var rep contract.Report
rep.Date = time.Now().UTC().Format("20060102")
rep.Address = addr
@@ -860,7 +344,7 @@ func newDataHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
}
if err := insertReport(db, rep); err != nil {
if err.Error() == `pq: duplicate key value violates unique constraint "uniqueidindex"` {
if err.Error() == `pq: duplicate key value violates unique constraint "uniqueidjsonindex"` {
// We already have a report today for the same unique ID; drop
// this one without complaining.
return
@@ -875,7 +359,8 @@ func newDataHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
}
func summaryHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
s, err := getSummary(db)
min, _ := strconv.Atoi(r.URL.Query().Get("min"))
s, err := getSummary(db, min)
if err != nil {
log.Println("summaryHandler:", err)
http.Error(w, "Database Error", http.StatusInternalServerError)
@@ -1016,8 +501,13 @@ func inc(storage map[string]int, key string, i interface{}) {
}
type location struct {
Latitude float64
Longitude float64
Latitude float64 `json:"lat"`
Longitude float64 `json:"lon"`
}
type weightedLocation struct {
location
Weight int `json:"weight"`
}
func getReport(db *sql.DB) map[string]interface{} {
@@ -1037,11 +527,11 @@ func getReport(db *sql.DB) map[string]interface{} {
var numDevices []int
var totFiles []int
var maxFiles []int
var totMiB []int
var maxMiB []int
var memoryUsage []int
var totMiB []int64
var maxMiB []int64
var memoryUsage []int64
var sha256Perf []float64
var memorySize []int
var memorySize []int64
var uptime []int
var compilers []string
var builders []string
@@ -1080,9 +570,9 @@ func getReport(db *sql.DB) map[string]interface{} {
var numCPU []int
var rep report
var rep contract.Report
rows, err := db.Query(`SELECT ` + strings.Join(rep.FieldNames(), ",") + ` FROM Reports WHERE Received > now() - '1 day'::INTERVAL`)
rows, err := db.Query(`SELECT Received, Report FROM ReportsJson WHERE Received > now() - '1 day'::INTERVAL`)
if err != nil {
log.Println("sql:", err)
return nil
@@ -1090,7 +580,7 @@ func getReport(db *sql.DB) map[string]interface{} {
defer rows.Close()
for rows.Next() {
err := rows.Scan(rep.FieldPointers()...)
err := rows.Scan(&rep.Received, &rep)
if err != nil {
log.Println("sql:", err)
@@ -1141,19 +631,19 @@ func getReport(db *sql.DB) map[string]interface{} {
maxFiles = append(maxFiles, rep.FolderMaxFiles)
}
if rep.TotMiB > 0 {
totMiB = append(totMiB, rep.TotMiB*(1<<20))
totMiB = append(totMiB, int64(rep.TotMiB)*(1<<20))
}
if rep.FolderMaxMiB > 0 {
maxMiB = append(maxMiB, rep.FolderMaxMiB*(1<<20))
maxMiB = append(maxMiB, int64(rep.FolderMaxMiB)*(1<<20))
}
if rep.MemoryUsageMiB > 0 {
memoryUsage = append(memoryUsage, rep.MemoryUsageMiB*(1<<20))
memoryUsage = append(memoryUsage, int64(rep.MemoryUsageMiB)*(1<<20))
}
if rep.SHA256Perf > 0 {
sha256Perf = append(sha256Perf, rep.SHA256Perf*(1<<20))
}
if rep.MemorySize > 0 {
memorySize = append(memorySize, rep.MemorySize*(1<<20))
memorySize = append(memorySize, int64(rep.MemorySize)*(1<<20))
}
if rep.Uptime > 0 {
uptime = append(uptime, rep.Uptime)
@@ -1235,8 +725,8 @@ func getReport(db *sql.DB) map[string]interface{} {
if rep.NATType != "" {
natType := rep.NATType
natType = strings.Replace(natType, "unknown", "Unknown", -1)
natType = strings.Replace(natType, "Symetric", "Symmetric", -1)
natType = strings.ReplaceAll(natType, "unknown", "Unknown")
natType = strings.ReplaceAll(natType, "Symetric", "Symmetric")
add(featureGroups["Various"]["v3"], "NAT Type", natType, 1)
}
@@ -1254,6 +744,8 @@ func getReport(db *sql.DB) map[string]interface{} {
inc(features["Folder"]["v3"], "Weak hash, always", rep.FolderUsesV3.AlwaysWeakHash)
inc(features["Folder"]["v3"], "Weak hash, custom threshold", rep.FolderUsesV3.CustomWeakHashThreshold)
inc(features["Folder"]["v3"], "Filesystem watcher", rep.FolderUsesV3.FsWatcherEnabled)
inc(features["Folder"]["v3"], "Case sensitive FS", rep.FolderUsesV3.CaseSensitiveFS)
inc(features["Folder"]["v3"], "Mode, receive encrypted", rep.FolderUsesV3.ReceiveEncrypted)
add(featureGroups["Folder"]["v3"], "Conflicts", "Disabled", rep.FolderUsesV3.ConflictsDisabled)
add(featureGroups["Folder"]["v3"], "Conflicts", "Unlimited", rep.FolderUsesV3.ConflictsUnlimited)
@@ -1263,6 +755,8 @@ func getReport(db *sql.DB) map[string]interface{} {
add(featureGroups["Folder"]["v3"], "Pull Order", prettyCase(key), value)
}
inc(features["Device"]["v3"], "Untrusted", rep.DeviceUsesV3.Untrusted)
totals["GUI"] += rep.GUIStats.Enabled
inc(features["GUI"]["v3"], "Auth Enabled", rep.GUIStats.UseAuth)
@@ -1304,14 +798,14 @@ func getReport(db *sql.DB) map[string]interface{} {
})
categories = append(categories, category{
Values: statsForInts(totMiB),
Values: statsForInt64s(totMiB),
Descr: "Data Managed per Device",
Unit: "B",
Type: NumberBinary,
})
categories = append(categories, category{
Values: statsForInts(maxMiB),
Values: statsForInt64s(maxMiB),
Descr: "Data in Largest Folder",
Unit: "B",
Type: NumberBinary,
@@ -1328,14 +822,14 @@ func getReport(db *sql.DB) map[string]interface{} {
})
categories = append(categories, category{
Values: statsForInts(memoryUsage),
Values: statsForInt64s(memoryUsage),
Descr: "Memory Usage",
Unit: "B",
Type: NumberBinary,
})
categories = append(categories, category{
Values: statsForInts(memorySize),
Values: statsForInt64s(memorySize),
Descr: "System Memory",
Unit: "B",
Type: NumberBinary,
@@ -1429,7 +923,7 @@ func getReport(db *sql.DB) map[string]interface{} {
}
var (
plusRe = regexp.MustCompile(`\+.*$`)
plusRe = regexp.MustCompile(`(\+.*|\.dev\..*)$`)
plusStr = "(+dev)"
)
@@ -1488,7 +982,9 @@ func (s *summary) MarshalJSON() ([]byte, error) {
for v := range s.versions {
versions = append(versions, v)
}
sort.Strings(versions)
sort.Slice(versions, func(a, b int) bool {
return upgrade.CompareVersions(versions[a], versions[b]) < 0
})
var filtered []string
for _, v := range versions {
@@ -1528,7 +1024,21 @@ func (s *summary) MarshalJSON() ([]byte, error) {
return json.Marshal(table)
}
func getSummary(db *sql.DB) (summary, error) {
// filter removes versions that never reach the specified min count.
func (s *summary) filter(min int) {
// We cheat and just remove the versions from the "index" and leave the
// data points alone. The version index is used to build the table when
// we do the serialization, so at that point the data points are
// filtered out as well.
for ver := range s.versions {
if s.max[ver] < min {
delete(s.versions, ver)
delete(s.max, ver)
}
}
}
func getSummary(db *sql.DB, min int) (summary, error) {
s := newSummary()
rows, err := db.Query(`SELECT Day, Version, Count FROM VersionSummary WHERE Day > now() - '2 year'::INTERVAL;`)
@@ -1559,6 +1069,7 @@ func getSummary(db *sql.DB) (summary, error) {
s.setCount(day.Format("2006-01-02"), ver, num)
}
s.filter(min)
return s, nil
}

143
cmd/ursrv/migration.go Normal file
View File

@@ -0,0 +1,143 @@
// Copyright (C) 2020 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 main
import (
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"log"
"strings"
"github.com/lib/pq"
"github.com/syncthing/syncthing/lib/ur/contract"
)
func migrate(db *sql.DB) error {
var count uint64
log.Println("Checking old table row count, this might take a while...")
if err := db.QueryRow(`SELECT COUNT(1) FROM Reports`).Scan(&count); err != nil || count == 0 {
// err != nil most likely means table does not exist.
return nil
}
log.Printf("Found %d records, will perform migration.", count)
tx, err := db.Begin()
if err != nil {
log.Println("sql:", err)
return err
}
defer tx.Rollback()
// These must be lower case, because we don't quote them when creating, so postgres creates them lower case.
// Yet pg.CopyIn quotes them, which makes them case sensitive.
stmt, err := tx.Prepare(pq.CopyIn("reportsjson", "received", "report"))
if err != nil {
log.Println("sql:", err)
return err
}
// Custom types used in the old struct.
var rep contract.Report
var rescanIntvs pq.Int64Array
var fsWatcherDelay pq.Int64Array
pullOrder := make(IntMap)
fileSystemType := make(IntMap)
themes := make(IntMap)
transportStats := make(IntMap)
rows, err := db.Query(`SELECT ` + strings.Join(rep.FieldNames(), ", ") + `, FolderFsWatcherDelays, RescanIntvs, FolderPullOrder, FolderFilesystemType, GUITheme, Transport FROM Reports`)
if err != nil {
log.Println("sql:", err)
return err
}
defer rows.Close()
var done uint64
pct := count / 100
for rows.Next() {
err := rows.Scan(append(rep.FieldPointers(), &fsWatcherDelay, &rescanIntvs, &pullOrder, &fileSystemType, &themes, &transportStats)...)
if err != nil {
log.Println("sql scan:", err)
return err
}
// Patch up parts that used to use custom types
rep.RescanIntvs = make([]int, len(rescanIntvs))
for i := range rescanIntvs {
rep.RescanIntvs[i] = int(rescanIntvs[i])
}
rep.FolderUsesV3.FsWatcherDelays = make([]int, len(fsWatcherDelay))
for i := range fsWatcherDelay {
rep.FolderUsesV3.FsWatcherDelays[i] = int(fsWatcherDelay[i])
}
rep.FolderUsesV3.PullOrder = pullOrder
rep.FolderUsesV3.FilesystemType = fileSystemType
rep.GUIStats.Theme = themes
rep.TransportStats = transportStats
_, err = stmt.Exec(rep.Received, rep)
if err != nil {
log.Println("sql insert:", err)
return err
}
done++
if done%pct == 0 {
log.Printf("Migration progress %d/%d (%d%%)", done, count, (100*done)/count)
}
}
// Tell the driver bulk copy is finished
_, err = stmt.Exec()
if err != nil {
log.Println("sql stmt exec:", err)
return err
}
err = stmt.Close()
if err != nil {
log.Println("sql stmt close:", err)
return err
}
_, err = tx.Exec("DROP TABLE Reports")
if err != nil {
log.Println("sql drop:", err)
return err
}
err = tx.Commit()
if err != nil {
log.Println("sql commit:", err)
return err
}
return nil
}
type IntMap map[string]int
func (p IntMap) Value() (driver.Value, error) {
return json.Marshal(p)
}
func (p *IntMap) Scan(src interface{}) error {
source, ok := src.([]byte)
if !ok {
return errors.New("Type assertion .([]byte) failed.")
}
var i map[string]int
err := json.Unmarshal(source, &i)
if err != nil {
return err
}
*p = i
return nil
}

View File

@@ -17,7 +17,11 @@ found in the LICENSE file.
<link href="static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="static/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=visualization&key=AIzaSyDk5WJ8s7ueLKb99X5DbQ-vkWtPDAKqYs0"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/heatmapjs@2.0.2/heatmap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/leaflet-heatmap@1.0.0/leaflet-heatmap.js"></script>
<style type="text/css">
body {
margin: 40px;
@@ -36,23 +40,25 @@ found in the LICENSE file.
}
</style>
<script type="text/javascript"
src="https://www.google.com/jsapi?autoload={
'modules':[{
'name':'visualization',
'version':'1',
'packages':['corechart']
src='https://www.google.com/jsapi?autoload={
"modules":[{
"name":"visualization",
"version":"1",
"packages":["corechart"]
}]
}"></script>
}'></script>
<script type="text/javascript">
google.setOnLoadCallback(drawVersionChart);
google.setOnLoadCallback(drawMovementChart);
google.setOnLoadCallback(drawBlockStatsChart);
google.setOnLoadCallback(drawPerformanceCharts);
google.setOnLoadCallback(drawHeatMap);
function drawVersionChart() {
var jsonData = $.ajax({url: "summary.json", dataType:"json", async: false}).responseText;
// Summary version chart for versions that at some point in the chart
// reaches 250 devices. This filters out versions that are old and
// uninteresting yet linger forever with like four users.
var jsonData = $.ajax({url: "summary.json?min=250", dataType:"json", async: false}).responseText;
var rows = JSON.parse(jsonData);
var data = new google.visualization.DataTable();
@@ -211,47 +217,46 @@ found in the LICENSE file.
var locations = [];
{{range $location, $weight := .locations}}
locations.push({location: new google.maps.LatLng({{- $location.Latitude -}}, {{- $location.Longitude -}}), weight: {{- $weight -}}});
locations.push({lat:{{- $location.Latitude -}},lng:{{- $location.Longitude -}},count:Math.min(100, {{- $weight -}})});
{{- end}}
function drawHeatMap() {
if (locations.length == 0) {
return;
}
var mapBounds = new google.maps.LatLngBounds();
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 1,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var heatmap = new google.maps.visualization.HeatmapLayer({
var testData = {
data: locations
};
var baseLayer = L.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
attribution: '...',
maxZoom: 18
}
);
var cfg = {
"radius": 1,
"minOpacity": .25,
"maxOpacity": .8,
"scaleRadius": true,
"useLocalExtrema": true,
latField: 'lat',
lngField: 'lng',
valueField: 'count',
gradient: {
'.1': 'cyan',
'.8': 'blue',
'.95': 'red'
}
};
var heatmapLayer = new HeatmapOverlay(cfg);
var map = new L.Map('map', {
center: new L.LatLng(25, 0),
zoom: 1,
layers: [baseLayer, heatmapLayer]
});
heatmap.set('radius', 10);
heatmap.set('maxIntensity', 20);
heatmap.set('gradient', [
'rgba(0, 255, 255, 0)',
'rgba(0, 255, 255, 1)',
'rgba(0, 191, 255, 1)',
'rgba(0, 127, 255, 1)',
'rgba(0, 63, 255, 1)',
'rgba(0, 0, 255, 1)',
'rgba(0, 0, 223, 1)',
'rgba(0, 0, 191, 1)',
'rgba(0, 0, 159, 1)',
'rgba(0, 0, 127, 1)',
'rgba(63, 0, 91, 1)',
'rgba(127, 0, 63, 1)',
'rgba(191, 0, 31, 1)',
'rgba(255, 0, 0, 1)'
]);
heatmap.setMap(map);
for (var x = 0; x < locations.length; x++) {
mapBounds.extend(locations[x].location);
}
map.fitBounds(mapBounds);
if (locations.length == 1) {
map.setZoom(13);
}
heatmapLayer.setData(testData);
}
</script>
</head>
@@ -296,7 +301,7 @@ found in the LICENSE file.
{{if .locations}}
<div class="img-thumbnail" id="map" style="width: 1130px; height: 400px; padding: 10px;"></div>
<p class="text-muted">
Heatmap max intensity is capped at 20 reports within a location.
Heatmap max intensity is capped at 100 reports within a location.
</p>
<div class="panel panel-default">
<div class="panel-heading">
@@ -651,6 +656,7 @@ found in the LICENSE file.
</p>
<script type="text/javascript">
$('[data-toggle="tooltip"]').tooltip({html:true});
drawHeatMap();
</script>
</body>
</html>

View File

@@ -1,7 +1,7 @@
[syncthing]
title=Syncthing
description=Syncthing file synchronisation
ports=22000/tcp|21027/udp
ports=22000|21027/udp
[syncthing-gui]
title=Syncthing-GUI

View File

@@ -38,13 +38,14 @@ syncthing_group=${syncthing_group:-$syncthing_user}
command=/usr/local/bin/syncthing
pidfile=/var/run/syncthing.pid
syncthing_flags="${syncthing_home:+-home=${syncthing_home}} ${syncthing_log_file:+-logfile=${syncthing_log_file}}"
syncthing_cmd=serve
syncthing_flags="${syncthing_home:+--home=${syncthing_home}} ${syncthing_log_file:+--logfile=${syncthing_log_file}}"
syncthing_start() {
echo "Starting syncthing"
touch ${pidfile} && chown ${syncthing_user} ${pidfile}
touch ${syncthing_log_file} && chown ${syncthing_user} ${syncthing_log_file}
/usr/sbin/daemon -cf -p ${pidfile} -u ${syncthing_user} ${command} ${syncthing_flags}
/usr/sbin/daemon -cf -p ${pidfile} -u ${syncthing_user} ${command} ${syncthing_cmd} ${syncthing_flags}
}
syncthing_cleanup() {

View File

@@ -2,7 +2,7 @@
Name=Start Syncthing
GenericName=File synchronization
Comment=Starts the main syncthing process in the background.
Exec=/usr/bin/syncthing -no-browser -logfile=~/.config/syncthing/syncthing.log
Exec=/usr/bin/syncthing serve --no-browser --logfile=default
Icon=syncthing
Terminal=false
Type=Application

View File

@@ -5,5 +5,4 @@ export HOME="/home/$USERNAME"
export SYNCTHING="$HOME/bin/syncthing"
exec 2>&1
exec chpst -u "$USERNAME" "$SYNCTHING" -logflags 0
exec chpst -u "$USERNAME" "$SYNCTHING" serve --logflags 0

View File

@@ -0,0 +1,3 @@
# Increase maximum receive socket buffer size to 2MiB for QUIC connections
# see https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size
net.core.rmem_max = 2097152

View File

@@ -0,0 +1,21 @@
sysctl configuration to raise UDP buffer size
===================
Installation
-----------
**Please note:** When you installed syncthing using the official deb package, you can skip the copying.
Copy the file `30-syncthing.conf` to `/etc/sysctl.d/` (root permissions required).
In a terminal run
```
sudo sysctl -q --system
```
to apply the sysctl changes.
Verification
----------
You can verify that the new limit is active using
```
sysctl net.core.rmem_max
```

View File

@@ -2,11 +2,14 @@
Description=Syncthing - Open Source Continuous File Synchronization for %I
Documentation=man:syncthing(1)
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=4
[Service]
User=%i
ExecStart=/usr/bin/syncthing -no-browser -no-restart -logflags=0
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0
Restart=on-failure
RestartSec=1
SuccessExitStatus=3 4
RestartForceExitStatus=3 4

View File

@@ -1,10 +1,13 @@
[Unit]
Description=Syncthing - Open Source Continuous File Synchronization
Documentation=man:syncthing(1)
StartLimitIntervalSec=60
StartLimitBurst=4
[Service]
ExecStart=/usr/bin/syncthing -no-browser -no-restart -logflags=0
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0
Restart=on-failure
RestartSec=1
SuccessExitStatus=3 4
RestartForceExitStatus=3 4

79
go.mod
View File

@@ -1,58 +1,57 @@
module github.com/syncthing/syncthing
require (
github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6
github.com/AudriusButkevicius/recli v0.0.5
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
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.0.0-20180726100737-be486d185f3d
github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 // indirect
github.com/ccding/go-stun v0.1.3
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-ole/go-ole v1.2.4 // indirect
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-20190702054246-869f871628b6
github.com/golang/mock v1.3.1 // indirect
github.com/jackpal/gateway v1.0.5
github.com/gogo/protobuf v1.3.2
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
github.com/golang/protobuf v1.5.2
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/kr/pretty v0.1.0 // indirect
github.com/lib/pq v1.2.0
github.com/lucas-clemente/quic-go v0.12.1
github.com/maruel/panicparse v1.3.0
github.com/mattn/go-isatty v0.0.11
github.com/minio/sha256-simd v0.1.1
github.com/onsi/ginkgo v1.9.0 // indirect
github.com/onsi/gomega v1.6.0 // indirect
github.com/oschwald/geoip2-golang v1.4.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.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/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.2.1
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563
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 v0.0.0-20190714054239-47ef3260b6bf
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/syncthing/notify v0.0.0-20190709140112-69c7a957d3e2
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
github.com/thejerf/suture v3.0.2+incompatible
github.com/urfave/cli v1.22.2
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.1
github.com/urfave/cli v1.22.5
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
github.com/willf/bitset v1.1.10 // indirect
github.com/willf/bloom v2.0.3+incompatible
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
golang.org/x/text v0.3.2
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/ldap.v2 v2.5.1
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
)
go 1.13
// https://github.com/spaolacci/murmur3/pull/30
replace github.com/spaolacci/murmur3 v1.1.0 => github.com/calmh/murmur3 v1.1.1-0.20200226160057-74e9af8f47ac
go 1.14

708
go.sum
View File

@@ -1,276 +1,706 @@
github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6 h1:Apvc4kyfdrOxG+F5dn8osz+45kwGJa6CySQn0tB38SU=
github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6/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=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
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-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=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
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.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 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
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=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bkaradzic/go-lz4 v0.0.0-20160924222819-7224d8d8f27e h1:2augTYh6E+XoNrrivZJBadpThP/dsvYKj0nzqfQ8tM4=
github.com/bkaradzic/go-lz4 v0.0.0-20160924222819-7224d8d8f27e/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/calmh/murmur3 v1.1.1-0.20200226160057-74e9af8f47ac h1:mc24tiVsBenJuhJFQzgvTo1ECJxCGXUgNktcfEhJHHo=
github.com/calmh/murmur3 v1.1.1-0.20200226160057-74e9af8f47ac/go.mod h1:nZyyz8Qrw2g3CakiZkVTsiwKlCgQSCf2ZCAFB3DHbaI=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
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/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 h1:8k9FLYBLKT+9v2HQJ/a95ZemmTx+/ltJcAiRhVushG8=
github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
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-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=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/chmduquesne/rollinghash v0.0.0-20180912150627-a60f8e7142b5 h1:Wg96Dh0MLTanEaPO0OkGtUIaa2jOnShAIOVUIzRHUxo=
github.com/chmduquesne/rollinghash v0.0.0-20180912150627-a60f8e7142b5/go.mod h1:Uc2I36RRfTAf7Dge82bi3RU0OQUmXT9iweIcPqvr8A0=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
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/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=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.2.2 h1:9DFz8tQwl9pTVt5iok/9zKyzA1Q6bRGiF3HPiEEVr9I=
github.com/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BMXYYRWTLOJKlh+lOBt6nUQgXAfB7oVIQt5cNreqSLI=
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
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/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.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-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
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.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
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/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/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.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
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.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
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/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=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
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/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=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
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.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/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=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
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/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=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
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.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=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
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.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
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=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
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.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lucas-clemente/quic-go v0.12.1 h1:BPITli+6KnKogtTxBk2aS4okr5dUHz2LtIDAP1b8UL4=
github.com/lucas-clemente/quic-go v0.12.1/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s=
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
github.com/marten-seemann/qtls v0.3.2 h1:O7awy4bHEzSX/K3h+fZig3/Vo03s/RxlxgsAk9sYamI=
github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
github.com/maruel/panicparse v1.3.0 h1:1Ep/RaYoSL1r5rTILHQQbyzHG8T4UP5ZbQTYTo4bdDc=
github.com/maruel/panicparse v1.3.0/go.mod h1:vszMjr5QQ4F5FSRfraldcIA/BCw5xrdLL+zEcU2nRBs=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
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=
github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc=
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
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.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/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
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/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-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 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=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.9.0 h1:SZjF721BByVj8QH636/8S2DnX4n0Re3SteMmw3N+tzc=
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.6.0 h1:8XTW0fcJZEq9q+Upcyws4JSGua2MFysCL5xkaSgHc+M=
github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
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/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
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.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=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k=
github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
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.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-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
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=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
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.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.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
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.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
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.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-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/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/shirou/gopsutil v0.0.0-20190714054239-47ef3260b6bf h1:c9SV5NzG4KOk448TUE7iqCmb4E4y79CZF4zDdc1Jx3Q=
github.com/shirou/gopsutil v0.0.0-20190714054239-47ef3260b6bf/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
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.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=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
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/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=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syncthing/notify v0.0.0-20190709140112-69c7a957d3e2 h1:6tuEEEpg+mxM82E0YingzoXzXXISYR/o/7I9n573LWI=
github.com/syncthing/notify v0.0.0-20190709140112-69c7a957d3e2/go.mod h1:Sn4ChoS7e4FxjCN1XHPVBT43AgnRLbuaB8pEc1Zcdjg=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/thejerf/suture v3.0.2+incompatible h1:GtMydYcnK4zBJ0KL6Lx9vLzl6Oozb65wh252FTBxrvM=
github.com/thejerf/suture v3.0.2+incompatible/go.mod h1:ibKwrVj+Uzf3XZdAiNWUouPaAbSoemxOHLmJmwheEMc=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
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.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.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.1/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/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX8Wdm2/JPA=
github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
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=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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-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=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/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=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
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-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=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76 h1:Dho5nD6R3PcW2SH1or8vS0dszDaXRxIw55lBX7XiE5g=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
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/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.3.3/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-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-20181030221726-6c7e314b6563/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-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=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
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/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=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
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/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/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/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

View File

@@ -21,7 +21,7 @@ ul+h5 {
margin-top: 1.5em;
}
#content {
.content {
margin-bottom: 50px;
}
@@ -41,6 +41,12 @@ ul+h5 {
float: none; /* issue #1197 */
}
#advancedAccordion input.form-control[type="checkbox"] {
box-shadow: none;
margin: 0;
width: auto;
}
.popover {
max-width: none;
min-width: 250px;
@@ -114,7 +120,8 @@ table.table-dynamic {
word-break: break-all;
}
table.table-condensed td {
table.table-condensed td,
table.table-condensed th {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -136,6 +143,11 @@ table.table-auto td {
max-width: 0px;
}
/* Wrap long file paths to prevent text overflow. See issue #6268. */
.file-path {
word-break: break-all;
}
.folder-advanced {
padding: 1rem;
margin-bottom: 15px;
@@ -236,6 +248,7 @@ identicon {
.identicon {
width: 1em;
height: 1em;
shape-rendering: crispEdges;
}
a.toggler {
@@ -351,7 +364,8 @@ ul.three-columns li, ul.two-columns li {
overflow-y: scroll;
}
table.table-condensed td {
table.table-condensed td,
table.table-condensed th {
/* for mobile phones to allow linebreaks in long repro folder/shared with
* columns. */
white-space: normal;
@@ -415,3 +429,23 @@ ul.three-columns li, ul.two-columns li {
margin-bottom: 1rem;
}
}
.form-horizontal .form-group {
margin-bottom: 5px;
}
.form-horizontal {
margin-bottom: 10px;
}
/* Use the same style as Bootstrap uses for disabled <select>. */
.form-control option[disabled] {
background-color: #eeeeee;
opacity: 1;
}
/* Make a "well" look more like a readonly text input when grouped with a button */
.input-group .well-sm {
padding-top: 6px;
padding-bottom: 6px;
}

View File

@@ -2,77 +2,84 @@
"A device with that ID is already added.": "Устройство с този идентификатор е вече добавено.",
"A negative number of days doesn't make sense.": "Няма логика в задаването на отрицателен брой дни.",
"A new major version may not be compatible with previous versions.": "Нова основна версия, която може да не е съвместима с предишни версии.",
"API Key": "API Ключ",
"API Key": "Ключ за ППИ",
"About": "За програмата",
"Action": "Действие",
"Actions": "Меню",
"Add": "Добави",
"Add Device": "Добави устройство",
"Add Folder": "Добави папка",
"Add Remote Device": "Добави ново устройство",
"Add devices from the introducer to our device list, for mutually shared folders.": "Добавяне на нови устройства през устройства предлагащи други устройства, за взаимно споделени папки.",
"Add new folder?": "Добави нова папка?",
"Add Remote Device": "Ново отдалечено устройство",
"Add devices from the introducer to our device list, for mutually shared folders.": "Добавяйте устройства през поръчителите за взаимно споделени папки.",
"Add new folder?": "Добавяне на папка?",
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "Също така интервалът за повторно сканиране ще бъде увеличен (60 пъти, пр. новият интервал бъде 1ч). Освен това може да го зададете и ръчно за всяка папка след като изберете Не.",
"Address": "Адрес",
"Addresses": "Адреси",
"Advanced": "Допълнителни",
"Advanced Configuration": "Допълнителни настройки",
"Advanced settings": "Допълнителни настройки",
"Advanced Configuration": "Разширени настройки",
"All Data": "Всички данни",
"Allow Anonymous Usage Reporting?": "Разрешаване изпращането на анонимни статистически данни?",
"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.": "Друга команда се занимава с версиите. Тази команда трябва да премахне файла от синхронизираната папка.",
"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 synced folder.": "Друга команда се занимава с версиите. Тази команда трябва да премахни файла от синхронизираната папка.",
"Anonymous Usage Reporting": "Анонимен доклад",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Форматът на анонимния доклад е променен. Желаете ли да преминете към новия формат?",
"Any devices configured on an introducer device will be added to this device as well.": "Устройства настроени да представят други устройства също ще бъдат добавени към това устройство.",
"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 upgrade?": "Are you sure you want to upgrade?",
"Auto Accept": "Автоматично приемане",
"Automatic Crash Reporting": "Automatic Crash Reporting",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Автоматичното обновяване вече предлага избор между стабилни версии и кандидат версии.",
"Automatic Crash Reporting": "Автоматично изпращане на доклад за срив",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Автоматичното обновяване вече предлага избор между стабилни и предварителни издания.",
"Automatic upgrades": "Автоматично обновяване",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Автоматичното обновяване е винаги включено за предварителните издания.",
"Automatically create or share folders that this device advertises at the default path.": "Автоматично създаване или споделяне на папки, които това устройство предлага в пътя по подразбиране.",
"Available debug logging facilities:": "Дебъгинг функционалност на разположение:",
"Available debug logging facilities:": "Available debug logging facilities:",
"Be careful!": "Внимание!",
"Bugs": "Бъгове",
"CPU Utilization": "Използван процесор",
"Bugs": "Дефекти",
"Changelog": "Списък с промени",
"Clean out after": "Изчисти след",
"Clean out after": "Clean out after",
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Натиснете, за да видите грешки при откриването",
"Close": "Затвори",
"Click to see full identification string and QR code.": "Щракнете, за да видите целия идентификатор и код за QR.",
"Close": "Затваряне",
"Command": "Команда",
"Comment, when used at the start of a line": "Коментар, използван в началото на реда",
"Compression": "Компресиране",
"Configured": "Настроен",
"Connected (Unused)": "Connected (Unused)",
"Connection Error": "Грешка при свързването",
"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. При промени по файловете се стартира сканиране само за променените папки. Ползите са, че промените биват синхронизирани по-бързо, без да се изисква цялостно сканирания на папките.",
"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 original": "Копиран от оригинала",
"Copyright © 2014-2016 the following Contributors:": "Всички правата запазени © 2014-2016 Сътрудници:",
"Copyright © 2014-2017 the following Contributors:": "Всички правата запазени © 2014-2017. Сътрудници:",
"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": "Currently Shared With Devices",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "При създаване на шаблони за отхвърляне, съществуващият файл {{path}}“ ще бъде презаписан.",
"Currently Shared With Devices": "Устройства, с които е споделена",
"Danger!": "Опасност!",
"Debugging Facilities": "Дебъг функционалност",
"Debugging Facilities": "Debugging Facilities",
"Default Configuration": "Default Configuration",
"Default Device": "Default Device",
"Default Folder": "Default Folder",
"Default Folder Path": "Път до папка по подразбиране",
"Defaults": "Defaults",
"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.",
"Deselect devices to stop sharing this folder with.": "Махнете отметката от устройство, за да спрете споделяне с него.",
"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}}\" ({{device}}) с адрес {{address}} желае да се свърже. Да бъде ли добавено?",
"Device ID": "Идентификатор на устройство",
"Device Identification": "Идентификатор на устройството",
"Device Identification": "Идентификатор на устройство",
"Device Name": "Име на устройството",
"Device rate limits": "Device rate limits",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device rate limits": "Ограничаване на скоростта",
"Device that last modified the item": "Устройство, което последно промени обекта",
"Devices": "Устройства",
"Disable Crash Reporting": "Disable Crash Reporting",
@@ -80,22 +87,28 @@
"Disabled periodic scanning and disabled watching for changes": "Периодичните сканирания и наблюденията за промяна са деактивирани.",
"Disabled periodic scanning and enabled watching for changes": "Периодичните сканирания са деактивирани , а наблюденията за промяна са активирани.",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Периодичните сканирания са деактивирани и задаването на наблюдение за промени е неуспешно, ще опита пак след 1мин:",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Изключва сравняването и синхронизацията не правата на файловете. Полезно за системи с липсващи или специфични права (като FAT, exFAT, Synology, Android).",
"Discard": "Discard",
"Disconnected": "Не е свързано",
"Disconnected (Unused)": "Disconnected (Unused)",
"Discovered": "Открит",
"Discovery": "Откриване",
"Discovery Failures": "Грешка в откриването",
"Do not restore": "Не възстановявай",
"Do not restore all": "Не възстановявай всички",
"Dismiss": "Dismiss",
"Do not add it to the ignore list, so this notification may recur.": "Do not add it to the ignore list, so this notification may recur.",
"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 all": "Без възстановяване всички",
"Do you want to enable watching for changes for all your folders?": "Желаете ли да активирате наблюдението за промени на всички папки?",
"Documentation": "Документация",
"Download Rate": "Скорост на сваляне",
"Downloaded": "Изтеглен",
"Downloading": "Изтегляне",
"Edit": "Промени",
"Edit": "Редактиране",
"Edit Device": "Промяна на устройството",
"Edit Device Defaults": "Подразбирани настройки на устройство",
"Edit Folder": "Промяна на папката",
"Editing": "Променяне",
"Edit Folder Defaults": "Подразбирани настройки на папка",
"Editing {%path%}.": "Променяне на {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable NAT traversal": "Разреши NAT traversal",
@@ -103,26 +116,20 @@
"Enabled": "Активирано",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Въведете не отрицателно число (пр. \"2.35\") и изберете единица.\nПроцентите са като част от размера на цялото дисково пространство.",
"Enter a non-privileged port number (1024 - 65535).": "Въведете непривилегирован номер на порт (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Въведете адреси разделени със запетая (\"tcp://ip:port\", \"tcp://host:port\") или \"dynamic\", за автоматично откриване на наличните адреси.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Въведете адреси разделени със запетая (\"tcp://ip:port\", \"tcp://host:port\") или \"dynamic\", за автоматично откриване на наличните адреси.",
"Enter ignore patterns, one per line.": "Добавете шаблони за игнориране, по един на ред.",
"Enter up to three octal digits.": "Enter up to three octal digits.",
"Error": "Грешка",
"External File Versioning": "Външно управление на версиите",
"External File Versioning": "Външно управление на версии",
"Failed Items": "Неуспешни",
"Failed to load ignore patterns": "Неуспешно зареждане на шаблони за игнориране",
"Failed to setup, retrying": "Неуспешно конфигуриране, правенe на повторен опит",
"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": "Версии на файловете",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Битовете за права за достъп ще бъдат игнорирани, когато се проверява за промени. Ползвайте за файлови системи тип FAT.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Файловете биват преместени в .stversions папка, когато са заменени или изтрити от Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Файловете биват преместени в .stversions папка, когато са заменени или изтрити от Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Когато Syncthing замени или изтрие файл той бива преместен в папката .stversions и преименуван - с добавяне на дата и час.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Когато Syncthing замени или изтрие файл той бива преместен в папката .stversions и преименуван - с добавяне на дата и час.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Защитава локалните файловете от промени направени на други устройства, но промените направени на това устройство ще бъдат синхронизирани с останалите устройства.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Промените направени на други устройства ще бъдат прилагани локално, но локалните промени няма да бъдат синхронизирани с останалите устройства.",
"Filesystem Notifications": "Известия на системата",
"Filesystem Watcher Errors": "Filesystem Watcher Errors",
"Filter by date": "Филтриране по дата",
"Filter by name": "Филтриране по име",
@@ -130,61 +137,61 @@
"Folder ID": "Идентификатор на папката",
"Folder Label": "Име на папката",
"Folder Path": "Път до папката",
"Folder Type": "Вид папка",
"Folder Type": "Вид на папката",
"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.": "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.",
"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.": "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": "Потребител за интерфейса",
"GUI Listen Address": "Адрес на слушане на GUI-то",
"GUI Listen Addresses": "Адрес за свързване с потребителския интерфейс",
"GUI Authentication: Set User and Password": "GUI Authentication: Set User and Password",
"GUI Listen Address": "Адрес на слушане",
"GUI Theme": "Тема за потребителския интерфейс",
"General": "Общи",
"Generate": "Генерирай",
"Global Changes": "Глобални промени",
"Global Discovery": "Глобално откриване",
"Global Discovery Servers": "Сървъри за глобално откриване",
"Global State": "Глобално състояние",
"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": "Идентификация",
"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 Permissions": "Игнорирай правата за достъп",
"Ignore Permissions": "Незачитане на права",
"Ignored Devices": "Игнорирани устройства",
"Ignored Folders": "Игнорирани папки",
"Ignored at": "Ignored at",
"Incoming Rate Limit (KiB/s)": "Лимит на скоростта за сваляне (KiB/s)",
"Incoming Rate Limit (KiB/s)": "При изтегляне (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Неправилни настройки могат да повредят файлове и да попречат на синхронизирането.",
"Introduced By": "Предложено от",
"Introducer": "Може да предлага други устройства",
"Introducer": "Поръчител",
"Inversion of the given condition (i.e. do not exclude)": "Обратното на даденото условие (пр. не изключвай)",
"Keep Versions": "Пази версии",
"LDAP": "LDAP",
"Largest First": " Първо най-големите",
"Last File Received": "Последния получен файл",
"Last Scan": "Последно сканирана",
"Last seen": "Последно видяно",
"Later": "По-късно",
"Latest Change": "Последна промяна",
"Learn more": "Научете повече",
"Limit": "Limit",
"Listeners": "Синхронизиращи устройства",
"Limit": "Ограничение",
"Listeners": "Listeners",
"Loading data...": "Зареждане на информация...",
"Loading...": "Зареждане...",
"Local Additions": "Local Additions",
"Local Discovery": "Локално откриване",
"Local State": "Локално състояние",
"Local State (Total)": "Локално състояние (общо)",
"Local Discovery": "Local Discovery",
"Local State": "Local State",
"Local State (Total)": "Local State (Total)",
"Locally Changed Items": "Locally Changed Items",
"Log": оклад",
"Log tailing paused. Click here to continue.": "Докладът е замразен. Натиснете, за да продължите.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Доклади",
"Log": невник",
"Log tailing paused. Scroll to the bottom to continue.": "Добавяне на редове към дневника е спряно. Плъзнете най-долу за да продължи.",
"Logs": "Дневници",
"Major Upgrade": "Основно Обновяване",
"Mass actions": "Действия за всички",
"Master": "Главен",
"Maximum Age": "Максимална възраст",
"Metadata Only": "Само мета информация",
"Minimum Free Disk Space": "Минимално свободно дисково пространство",
@@ -200,7 +207,7 @@
"No File Versioning": "Без версии",
"No files will be deleted as a result of this operation.": "Няма да бъдат изтрити файлове като резултат от тази операция.",
"No upgrades": "Няма обновления",
"Normal": "Нормален",
"Not shared": "Not shared",
"Notice": "Известие",
"OK": "ОК",
"Off": "Изключено",
@@ -209,47 +216,49 @@
"Options": "Настройки",
"Out of Sync": "Несинхронизирано",
"Out of Sync Items": "Несинхронизирани елементи",
"Outgoing Rate Limit (KiB/s)": "Лимит на скорост за качване (KiB/s)",
"Outgoing Rate Limit (KiB/s)": "При качване (KiB/s)",
"Override Changes": "Наложи локалните промени",
"Path": "Път",
"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": "Път до папката на това устройство. Ако не съществува ще бъде създадена. Символът тилда (~) може да бъде използван като заместител на",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Къде да бъдат създавани, автоматично приети папки, както и предложението за път, при добавяне на нови папки от потребителският интерфейс. Символът тилда (~) ще бъде заменян с {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": ътят, където версиите да бъдат складирани (оставете празно за папката .stversions).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Пътят, където версиите да бъдат складирани(остави празно за папката .stversions).",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": апка, в която да бъдат съхранявани версиите (оставете празно за подразбираната директория .stversions в споделената папка).",
"Pause": "Пауза",
"Pause All": "Пауза на всички",
"Paused": "На пауза",
"Paused (Unused)": "Paused (Unused)",
"Pending changes": "Pending 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 failed setting up watching for changes, retrying every 1m:": "Периодично сканиране, през определен интервал, мониторинга за промени не може да стартира. Всяка минута минута се прави опит за стартиране:",
"Permissions": "Права за достъп",
"Please consult the release notes before performing a major upgrade.": "Моля прочети бележките по обновяването преди да започнеш.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Моля задайте потребителско име и парола за потребителския интерфейс в секцията Настройки.",
"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 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": "Права",
"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 wait": "Моля изчакайте",
"Prefix indicating that the file can be deleted if preventing directory removal": "Представка, която индикира, че файлът може да бъде изтрит ако пречи на премахването на папка",
"Prefix indicating that the pattern should be matched without case sensitivity": "Представка, която индикира, че шаблона няма да прави разлика между главни/малки букви",
"Prefix indicating that the file can be deleted if preventing directory removal": "Представка, указваща че файлът може да бъде изтрит ако пречи на премахването на папка",
"Prefix indicating that the pattern should be matched without case sensitivity": "Представка, указваща че шаблонът не прави разлика в регистъра на буквите",
"Preparing to Sync": "Preparing to Sync",
"Preview": "Преглед",
"Preview Usage Report": "Преглед на статистиката",
"Quick guide to supported patterns": "Бърз наръчник към поддържаните шаблони",
"RAM Utilization": "Използванa RAM",
"Preview Usage Report": "Преглед на отчета за употребата",
"Quick guide to supported patterns": "Кратък наръчник на поддържаните шаблони",
"Random": "Произволен",
"Receive Encrypted": "Receive Encrypted",
"Receive Only": "Само получаване",
"Received data is already encrypted": "Received data is already encrypted",
"Recent Changes": "Последни промени",
"Reduced by ignore patterns": "Намалено посредством шаблон за игнориране",
"Release Notes": "Бележки по обновяването",
"Reduced by ignore patterns": "Намалено посредством шаблон за отхвърляне",
"Release Notes": "Бележки по изданието",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Кандидат версиите съдържат най-новата функционалност и поправки. Те са близки до традиционните дву-седмични Synchthing обновления.",
"Remote Devices": "Устройства",
"Remove": "Премахни",
"Remote Devices": "Отдалачени устройства",
"Remote GUI": "Отдалечен ГПИ",
"Remove": "Премахване",
"Remove Device": "Премахване на устройство",
"Remove Folder": "Премахване на папка",
"Required identifier for the folder. Must be the same on all cluster devices.": "Задължителен идентификатор за папката. Трябва да бъде един и същ на всяко устройство.",
"Required identifier for the folder. Must be the same on all cluster devices.": "Задължителен идентификатор на папката. Трябва е еднакъв на всички устройства.",
"Rescan": "Сканирай",
"Rescan All": "Сканирай всички",
"Rescan Interval": "Интервал за повторно сканиране",
"Rescans": "Повторни сканирания",
"Restart": "Рестартирай",
"Restart": "Рестартиране",
"Restart Needed": "Изисква се рестартиране",
"Restarting": "Рестартиране",
"Restore": "Възстановяване",
@@ -258,49 +267,52 @@
"Resume All": "Пусни всички",
"Reused": "Повторно използван",
"Revert Local Changes": "Revert Local Changes",
"Running": "Изпълнява се",
"Save": "Запази",
"Scan Time Remaining": "Оставащо време за сканиране",
"Scanning": "Сканиране",
"See external versioner help for supported templated command line parameters.": "Прегледайте документацията на външното приложение за версии и поддържаните от него командни параметри. ",
"See external versioning help for supported templated command line parameters.": "Прегледайте външната документацията за поддържаните командни параметри. ",
"Save": "Запазване",
"Scan Time Remaining": "Оставащо време до обхождане",
"Scanning": "Обхождане",
"See external versioning help for supported templated command line parameters.": "Прочетете ръководството за външно управление на версии, за да се запознаете с шаблонните параметри.",
"Select All": "Всички",
"Select a version": "Изберете версия",
"Select additional devices to share this folder with.": "Select additional devices to share this folder with.",
"Select additional devices to share this folder with.": "Изберете други устройства, с които да споделите с папката.",
"Select additional folders to share with this device.": "Изберете други папки, които да споделите с устройството.",
"Select latest version": "Избор на най-новата версия",
"Select oldest version": "Избор на най-старата версия",
"Select the devices to share this folder with.": "Изберете устройствата, с които да споделите папката.",
"Select the folders to share with this device.": "Изберете папките за споделяне с това устройство.",
"Select the folders to share with this device.": "Изберете папките, които да споделите с устройството.",
"Send & Receive": "Изпращане и получаване",
"Send Only": "Само изпращане",
"Settings": "Настройки",
"Share": "Сподели",
"Share Folder": "Сподели папка",
"Share": "Споделяне",
"Share Folder": "Споделяне на папка",
"Share Folders With Device": "Споделяне на папки с устройството",
"Share With Devices": "Споделяне с устройства",
"Share this folder?": "Сподели тази папка?",
"Shared Folders": "Споделени папки",
"Shared With": "Споделена с",
"Sharing": "Споделяне",
"Show ID": "Покажи идентификатора",
"Show QR": окажи QR",
"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 updated to the name the device advertises if left empty.": "Показва се вместо идентификатора на устройството в статуса на клъстъра. Ще бъде попълнено с името, с което се е представило устройството, ако оставите полето празно.",
"Shutdown": "Спри програмата",
"Show QR": реглед на QR",
"Show detailed discovery status": "Show detailed discovery status",
"Show detailed listener status": "Show detailed listener status",
"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.",
"Shutdown": "Изключване",
"Shutdown Complete": "Спирането завършено",
"Simple File Versioning": "Опростени версии",
"Single level wildcard (matches within a directory only)": "Маска на едно ниво (покрива само в папка)",
"Size": "Размер",
"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 listening addresses could not be enabled to accept connections:": "Some listening addresses could not be enabled to accept connections:",
"Source Code": "Сорс код",
"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 and release candidates": "Стабилни и предварителни издания",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Стабилните издания биват забавяни с две седмици. През този период те преминават през изпитване като предварителни издания.",
"Stable releases only": "Само стабилни версии",
"Staggered File Versioning": "Наслагващи се версии",
"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.": "Съхранява и синхронизира само шифровани данни. Папките на всички свързани устройства трябва да бъдат настроени със същата парола или също да са от вида „{{receiveEncrypted}}“.",
"Support": "Помощ",
"Support Bundle": "Support Bundle",
"Sync Protocol Listen Addresses": "Адрес за слушане на синхронизиращия протокол",
@@ -308,41 +320,51 @@
"Syncthing has been shut down.": "Syncthing е спрян.",
"Syncthing includes the following software or portions thereof:": "Syncthing уползотворява частично или изцяло следните софтуерни продукти:",
"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 се рестартира",
"Syncthing is upgrading.": "Syncthing се обновява.",
"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.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Изглежда, че Syncthing не е включен, или има проблем с връзката с Интернет. Повторен опит...",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Изглежда, че Syncthing не работи или няма достъп до интернет. Извършва се повторен опит",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing има проблем при обработването на заявката. Моля, презаредете браузъра или рестартирайте Syncthing ако проблемът продължи.",
"Take me back": "Take me back",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.",
"The Syncthing Authors": "The Syncthing Authors",
"The Syncthing admin interface is configured to allow remote access without a password.": "Администраторският панел на Syncthing разрешава дистанционен достъп без да изисква парола.",
"The aggregated statistics are publicly available at the URL below.": "Обобщение на събраните статистически ще намерите на долния URL адрес.",
"The aggregated statistics are publicly available at the URL below.": "Обобщение на събраните статистически данни ще намерите на адреса по-долу.",
"The cleanup interval cannot be blank.": "The cleanup interval cannot be blank.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Конфигурацията е запазена, но не е активирана. Syncthing трябва да рестартира, за да се активира новата конфигурация.",
"The device ID cannot be blank.": "Полето идентификатор на устройство не може да бъде празно.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Идентификатор на устройство за въвеждане тук, може да бъде намерен в \"Промени > Покажи идентификатора\" на другото устройство. Интервалите и тиретата са пожелание (биват прескачани).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Криптиран статистически доклад ще се изпраща ежедневно. Ползва се, за отичане на ползваните платформи, размер на папки и версии на приложението. При промяна в събираните данни, ще бъдете информирани от подобен на този прозорец.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Шифрованият отчет за употреба се изпраща ежедневно. Използваме го за отчитане на най-често срещаните платформи, размери на папки и издания на приложението. При промяна в събираните данни отново ще бъде поискано вашето съгласие.",
"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.": "Въведеният идентификатор на устройство не е валиден. Трябва да бъде 52 или 56 символа и да се състои от букви и цифри, като интервалите и тиретата са пожелание.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "Първият параметър за командата е пътя до папката, а вторият е релативния път в самата папка.",
"The folder ID cannot be blank.": "Полето идентификатор на папка не може да бъде празно.",
"The folder ID must be unique.": "Идентификаторът на папката трябва да бъде уникален.",
"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 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.": "Следните елементи не могат да бъдат синхронизирани.",
"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.",
"The maximum age must be a number and cannot be blank.": "Максималната възраст трябва да е число, полето не може да бъде празно.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Максималното време за пазене на версия (в дни, задайте 0 за да не бъдат изтривани версии).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Минималното свободно дисково пространство в проценти трябва да е между 0 и 100 (включително).",
"The number of days must be a number and cannot be blank.": "Броят дни трябва да бъде число и не може да бъде празно.",
"The number of days to keep files in the trash can. Zero means forever.": "Броят дни за запазване на файловете в кошчето. Нула значи завинаги.",
"The number of old versions to keep, per file.": "Броят стари версии, които да бъдат пазени за всеки файл.",
"The number of versions must be a number and cannot be blank.": "Броят версии трябва да бъде число и не може да бъде празно.",
"The path cannot be blank.": "Пътят не може да бъде празен.",
"The rate limit must be a non-negative number (0: no limit)": "Ограничението на скоростта трябва да бъде положително число (0: неограничено)",
"The rescan interval must be a non-negative number of seconds.": "Интервала на сканиране трябва да бъде не отрицателно число в секунди.",
"The rescan interval must be a non-negative number of seconds.": "Интервалът на обхождане трябва да е неотрицателен брой на секунди.",
"There are no devices to share this folder with.": "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.",
"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 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 setting controls the free space required on the home (i.e., index database) disk.": "Тази настройка контролира нужното свободното място на основния (пр. този с базата данни) диск.",
"Time": "Време",
@@ -353,40 +375,42 @@
"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.",
"Unignore": "Unignore",
"Unknown": "Неясно",
"Unshared": "Несподелена",
"Unshared Devices": "Unshared Devices",
"Unused": "Неизползвано",
"Unshared Devices": "Устройства, с които не е споделено",
"Unshared Folders": "Несподелени папки",
"Untrusted": "Недоверено",
"Up to Date": "Синхронизирано",
"Updated": "Обновено",
"Upgrade": "Обнови",
"Upgrade To {%version%}": "Обновен до {{version}}",
"Upgrade": "Обновяване",
"Upgrade To {%version%}": "Обновено до {{version}}",
"Upgrading": "Обновяване",
"Upload Rate": "Скорост на качване",
"Uptime": "Работи от",
"Usage reporting is always enabled for candidate releases.": "Докладът за ползването е винаги включен за кандидат нови версии.",
"Use HTTPS for GUI": "Използвай HTTPS за потребителския интерфейс",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Usage reporting is always enabled for candidate releases.": "Отчитането на употребата винаги е включено за предварителните издания.",
"Use HTTPS for GUI": "Потребителският интерфейс работи под HTTPS",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Username/Password has not been set for the GUI authentication. Please consider setting it up.",
"Version": "Версия",
"Versions": "Версии",
"Versions Path": "Път до версиите",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Версиите биват изтривани автоматично, когато са по-стари от максималната възраст или надминават броя версии разрешени в даден интервал.",
"Waiting to Clean": "Waiting to Clean",
"Waiting to Scan": "Waiting to Scan",
"Waiting to Sync": "Waiting to Sync",
"Waiting to scan": "Waiting to scan",
"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}}, трябва да я деактивирате.",
"Watch for Changes": "Мониторинг за промени",
"Watching for Changes": "Мониторинг за промени",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Предупреждение: Ако използвате външно приложение за наблюдение като {{syncthingInotify}}, трябва да го спрете.",
"Watch for Changes": "Watch for Changes",
"Watching for Changes": "Watching for Changes",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Когато добавяте ново устройство имайте предвид, че това устройство също трябва да бъде добавено от другата страна.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Когато добавяте нов идентификатор на папка имайте предвид, че той се използва за свързване на папките между отделните устройства. Идентификатора разграничава главни/малки букви.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Като добавяте папката имайте предвид, че той се използва за еднозначно указване на папката между устройствата. Има разлика в регистъра на знаците и трябва изцяло да съвпада между всички устройства.",
"Yes": "Да",
"You can also select one of these nearby devices:": "Също така може да изберете едно от устройствата, които намират се наблизо:",
"You can change your choice at any time in the Settings dialog.": "Може да промените решението си по всяко време в прозореца Настройки.",
@@ -394,12 +418,15 @@
"You have no ignored devices.": "Няма игнорирани устройства.",
"You have no ignored folders.": "Няма игнорирани папки.",
"You have unsaved changes. Do you really want to discard them?": "Има незапазени промени. Наистина ли желаете да ги отмените?",
"You must keep at least one version.": "Трябва да пазиш поне една версия.",
"You must keep at least one version.": "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.",
"days": "дни",
"directories": "директории",
"files": "файла",
"full documentation": "пълна документация",
"items": "елемента",
"seconds": "секунди",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} желае да сподели папката \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} желае да сподели папката \"{{folderlabel}}\" ({{folder}})."
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} желае да сподели папката \"{{folderlabel}}\" ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "Поръчителят {{reintroducer}} може отново да предложи това устройство."
}

View File

@@ -17,17 +17,16 @@
"Addresses": "Direccions",
"Advanced": "Avançat",
"Advanced Configuration": "Configuració avançada",
"Advanced settings": "Ajustos avançats.",
"All Data": "Totes les dades",
"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?": "Permetre informes d'ús anònim?",
"Allowed Networks": "Xarxes permeses",
"Alphabetic": "Alfabètic",
"An external command handles the versioning. It has to remove the file from the shared folder.": "Un command extern maneja les versions. Té que eliminar el fitxer de la carpeta compartida.",
"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.": "Un comandament extern maneja el versionat. És necessari eliminar el fitxer de la carpeta compartida. Si la ruta a l'aplicació conté espais, hi ha que ficar-los entre cometes.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Un comando extern controla el versionat. És necessari eliminar el fitxer de la carpeta sincronitzada.",
"Anonymous Usage Reporting": "Informe d'ús anònim",
"Anonymous usage report format has changed. Would you like to move to the new format?": "El format del informe anònim d'ús ha canviat. Vols canviar al nou format?",
"Any devices configured on an introducer device will be added to this device as well.": "Tots els dispositius configurats en un dispositiu presentador seràn afegits també a aquest dispositiu.",
"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%}?": "Estàs segur de que vols eliminar el dispositiu {{name}}?",
"Are you sure you want to remove folder {%label%}?": "Estàs segur de que vols eliminar la carpeta {{label}}?",
"Are you sure you want to restore {%count%} files?": "Estàs segur de que vols restaurar {{count}} fitxers?",
@@ -41,37 +40,45 @@
"Available debug logging facilities:": "Hi han disponibles les següents utilitats per a depurar el registre:",
"Be careful!": "Tin precaució!",
"Bugs": "Errors (Bugs)",
"CPU Utilization": "Utilització de la CPU",
"Changelog": "Registre de canvis",
"Clean out after": "Netejar després de",
"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",
"Compression": "Compresió",
"Configured": "Configurat",
"Connected (Unused)": "Connected (Unused)",
"Connection Error": "Error de connexió",
"Connection Type": "Tipus de connexió",
"Connections": "Connexions",
"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.": "Ara està disponible la revisió continua de canvix dins de Syncthing. Acò detectarà els canvis i llençarà un escaneig sols a les rutes modificades. Els beneficis són que els canvis es propaguen mé ràpidamente i es necessiten menys escanejos complets.",
"Copied from elsewhere": "Copiat de qualsevol lloc",
"Copied from original": "Copiat de l'original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 els següents Col·laboradors:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 els següents Col·laboradors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 els següents Col·laboradors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creant patrons a ignorar, sobreescriguent un fitxer que ja existeix a {{path}}.",
"Currently Shared With Devices": "Currently Shared With Devices",
"Danger!": "Perill!",
"Debugging Facilities": "Utilitats de Depuració",
"Default Configuration": "Default Configuration",
"Default Device": "Default Device",
"Default Folder": "Default Folder",
"Default Folder Path": "Carpeta de la Ruta per Defecte",
"Defaults": "Defaults",
"Delete Unexpected Items": "Delete Unexpected Items",
"Deleted": "Esborrat",
"Deselect All": "Anul·lar tota la selecció",
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
"Device": "Dispositiu",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Dispositiu \"{{name}}\" ({{device}} a l'adreça {{address}}) vol connectar. Afegir nou dispositiu?",
"Device ID": "ID del dispositiu",
"Device Identification": "Identificació del dispositiu",
"Device Name": "Nom del dispositiu",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device rate limits": "Límits de la tasa del dispositiu",
"Device that last modified the item": "El dispositiu que va modificar el item per última vegada",
"Devices": "Dispositius",
@@ -80,11 +87,16 @@
"Disabled periodic scanning and disabled watching for changes": "Desactivat l'escaneig periòdic i el rastreig continu de canvis",
"Disabled periodic scanning and enabled watching for changes": "Desactivat l'escaneig periòdic i activat el rastreig continu de canvis",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Desactivat l'escaneig periòdic i errada al rastreig continu de canvis, es reintentarà cada 1 minut:",
"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": "Descartar",
"Disconnected": "Desconnectat",
"Disconnected (Unused)": "Disconnected (Unused)",
"Discovered": "Descobert",
"Discovery": "Descobriment",
"Discovery Failures": "Fallades al Descobriment",
"Dismiss": "Dismiss",
"Do not add it to the ignore list, so this notification may recur.": "Do not add it to the ignore list, so this notification may recur.",
"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": "No restaurar",
"Do not restore all": "No restaurar en absolut",
"Do you want to enable watching for changes for all your folders?": "Vols activar el rastreig continu de canvis per a totes les carpetes?",
@@ -94,8 +106,9 @@
"Downloading": "Descarregant",
"Edit": "Editar",
"Edit Device": "Editar Dispositiu",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Folder": "Editar Carpeta",
"Editing": "Editant",
"Edit Folder Defaults": "Edit Folder Defaults",
"Editing {%path%}.": "Editant {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable NAT traversal": "Permetre NAT transversal",
@@ -103,26 +116,20 @@
"Enabled": "Activat",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Introdueix un nombre no negatiu (per exemple, \"2.35\") i selecciona una unitat. Els percentatges són com a part del tamany total del disc.",
"Enter a non-privileged port number (1024 - 65535).": "Introdueix un nombre de port sense privilegis (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introdueix adreces separades per coma (\"tcp://ip:port\", \"tcp://host:port\") o \"dynamic\" per a realitzar el descobriment automàtic de l'adreça.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduïr adreces separades per coma (\"tcp://ip:port\", \"tcp://host:port\") o dinàmiques per al descobriment automàtic de l'adreça.",
"Enter ignore patterns, one per line.": "Introduïr patrons a ignorar, un per línia.",
"Enter up to three octal digits.": "Enter up to three octal digits.",
"Error": "Error",
"External File Versioning": "Versionat extern de fitxers",
"Failed Items": "Objectes fallits",
"Failed to load ignore patterns": "Errada al carregar els patrons a ignorar",
"Failed to setup, retrying": "Errada en la configuració, reintentant",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "És possible que es produïsca una fallada al connectar als servidors IPv6 si no hi ha connectivitat IPv6.",
"File Pull Order": "Ordre de fitxers del pull",
"File Versioning": "Versionat de fitxer",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Els bits de permís del fitxer són ignorats quant es busquen els canvis. Utilitzar en sistemes de fitxers FAT.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Els fitxers seràn moguts al directori .stversions quant siguen reemplaçats o esborrats per Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Els arxius es menejen a la carpeta .stversions quant són substituïts o esborrats per Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Els arxius seran moguts a un directori .stversions a versions amb control de la data quan siguen reemplaçats o esborrats per Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Els fitxers són canviats a versions amb indicació de data en una carpeta \".stversions\" quant són reemplaçats o esborrats per Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Els fitxers són protegits dels canvis fets en altres dispositius, però els canvis fets en aquest dispositiu seràn enviats a la resta del grup (cluster).",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Els fitxers es sincronitzen des-d'el cluster, però tots els canvis fets localment no s'enviaràn als altres dispositius.",
"Filesystem Notifications": "Notificacions del Sistema de Fitxers",
"Filesystem Watcher Errors": "Errors del Vigilant del Sistema de Fitxers",
"Filter by date": "Filtrar per data",
"Filter by name": "Filtrar per nom",
@@ -131,24 +138,28 @@
"Folder Label": "Etiqueta de la Carpeta",
"Folder Path": "Ruta de la carpeta",
"Folder Type": "Tipus de carpeta",
"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.",
"Folders": "Carpetes",
"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.": "Per a les següents carpetes va ocòrrer un error mentre es començava a vigilar els canvis. Es tornarà a intentar cada minut, així que potser els errors desapareguen pronte. Si persisteixen, tracta d'arreglar el motiu subjacent i demana ajuda si no pots.",
"Full Rescan Interval (s)": "Interval de l'Escaneig Complet (segons)",
"GUI": "IGU (Interfície Gràfica d'Usuari)",
"GUI Authentication Password": "Password d'autenticació de l'Interfície Gràfica d'Usuari (GUI)",
"GUI Authentication User": "Autenticació de l'usuari de l'Interfície Gràfica d'Usuari (GUI)",
"GUI Authentication: Set User and Password": "GUI Authentication: Set User and Password",
"GUI Listen Address": "Adreça d'Escolta de l'Interfície Gràfica d'Usuari (GUI).",
"GUI Listen Addresses": "Direcció d'escolta de l'Interfície Gràfica d'Usuari (GUI)",
"GUI Theme": "Tema de l'Interfície Gràfica d'Usuari (GUI)",
"General": "General",
"Generate": "Generar",
"Global Changes": "Canvis Globals",
"Global Discovery": "Descobriment global",
"Global Discovery Servers": "Servidors de Descobriment Global",
"Global State": "Estat global",
"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",
"Ignore Patterns": "Patrons a ignorar",
"Ignore Permissions": "Permisos a ignorar",
@@ -161,11 +172,10 @@
"Introducer": "Presentador",
"Inversion of the given condition (i.e. do not exclude)": "Inversió de la condició donada (per exemple no excloure)",
"Keep Versions": "Mantindre versions",
"LDAP": "LDAP",
"Largest First": "El més gran primer",
"Last File Received": "Darrer fitxer rebut",
"Last Scan": "Últim escaneig",
"Last seen": "Vist per última vegada",
"Later": "Més tard",
"Latest Change": "Últim Canvi",
"Learn more": "Saber més",
"Limit": "Límit",
@@ -178,13 +188,10 @@
"Local State (Total)": "Estat Local (Total)",
"Locally Changed Items": "Dispositius Canviats Localment",
"Log": "Registre",
"Log tailing paused. Click here to continue.": "Pausada l'adició de dades al registre. Polsa ací per continuar.",
"Log tailing paused. Scroll to bottom continue.": "Pausat el seguiment del registre. Es continua fins al final.",
"Log tailing paused. Scroll to the bottom to continue.": "Pausada l'anotació al registre. Baixeu fins al final per continuar.",
"Logs": "Registres",
"Major Upgrade": "Actualització important",
"Mass actions": "Accions en masa",
"Master": "Mestre",
"Maximum Age": "Edat màxima",
"Metadata Only": "Sols metadades",
"Minimum Free Disk Space": "Espai minim de disc lliure",
@@ -200,7 +207,7 @@
"No File Versioning": "Sense versionat de fitxer",
"No files will be deleted as a result of this operation.": "Amb aquesta operació no s'esborrarà cap fitxer.",
"No upgrades": "Sense actualitzacions",
"Normal": "Normal",
"Not shared": "Not shared",
"Notice": "Avís",
"OK": "OK",
"Off": "Off",
@@ -215,14 +222,15 @@
"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": "Ruta a la carpeta local en l'ordinador. Es crearà si no existeix. El caràcter tilde (~) es pot utilitzar com a drecera",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "La ruta on es crearan les noves carpetes acceptades automàticament, així com la ruta sugerida quan s'afigen noves carpetes des-de l'IU. El caracter tilde (~) s'expandeix a {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "La ruta on deuen guardar-se les versions (deixar buit per al directori per defecte .stversions en la carpeta compartida).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Ruta on les versions deurien estar emmagatzemades (deixar buit per a la carpeta .stversions en la carpeta).",
"Pause": "Pausa",
"Pause All": "Pausa Tot",
"Paused": "Pausat",
"Paused (Unused)": "Paused (Unused)",
"Pending changes": "Canvis pendents",
"Periodic scanning at given interval and disabled watching for changes": "Escaneig periòdic a l'interval determinat i desactivat el rastreig continu de canvis",
"Periodic scanning at given interval and enabled watching for changes": "Escaneig periòdic a l'interval determinat i activat el rastreig continu de canvis",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Escaneig periòdic a l'interval determinat i errada al activar el rastreig continu de canvis, reintentant cada 1 minut:",
"Permanently add it to the ignore list, suppressing further notifications.": "Permanently add it to the ignore list, suppressing further notifications.",
"Permissions": "Permisos",
"Please consult the release notes before performing a major upgrade.": "Per favor, consultar les notes de la versió abans de fer una actualització important.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Per favor, estableix un usuari i password per a l'Interfície Gràfica d'Usuari en el menú d'Adjustos.",
@@ -233,21 +241,22 @@
"Preview": "Vista prèvia",
"Preview Usage Report": "Informe d'ús de vista prèvia",
"Quick guide to supported patterns": "Guía ràpida de patrons suportats",
"RAM Utilization": "Utilització de la RAM",
"Random": "Aleatori",
"Receive Encrypted": "Receive Encrypted",
"Receive Only": "Només rebre",
"Received data is already encrypted": "Received data is already encrypted",
"Recent Changes": "Canvis Recents",
"Reduced by ignore patterns": "Reduït ignorant patrons",
"Release Notes": "Notes de la versió",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Les versions candidates (Release Candidates) contenen les darreres característiques i arreglos. Són paregudes a les versions tradicionals bi-semanals de Syncthing. ",
"Remote Devices": "Dispositius Remots",
"Remote GUI": "Remote GUI",
"Remove": "Eliminar",
"Remove Device": "Eliminar Dispositiu",
"Remove Folder": "Eliminar Carpeta",
"Required identifier for the folder. Must be the same on all cluster devices.": "Identificador necessari per la carpeta. Deu ser el mateix en tots els dispositius del cluster.",
"Rescan": "Tornar a buscar",
"Rescan All": "Tornar a buscar tot",
"Rescan Interval": "Interval de nova busca",
"Rescans": "Reescanejos",
"Restart": "Reiniciar",
"Restart Needed": "Reinici necesari",
@@ -258,18 +267,16 @@
"Resume All": "Continuar Tot",
"Reused": "Reutilitzat",
"Revert Local Changes": "Revertir els canvis locals",
"Running": "Executant",
"Save": "Gravar",
"Scan Time Remaining": "Temps d'escaneig restant",
"Scanning": "Rastrejant",
"See external versioner help for supported templated command line parameters.": "Consulta l'ajuda externa sobre versions per a conéixer els paràmetres de la plantilla de la línia de comandaments.",
"See external versioning help for supported templated command line parameters.": "Consulta l'ajuda externa sobre versions per a conéixer els paràmetres de la plantilla de la línia de comandaments.",
"Select All": "Sel·leccionar Tot",
"Select a version": "Seleccionar una versió",
"Select additional devices to share this folder with.": "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 latest version": "Seleccionar l'última versió",
"Select oldest version": "Seleccionar la versió més antiga",
"Select the devices to share this folder with.": "Selecciona els dispositius amb els que compartir aquesta carpeta.",
"Select the folders to share with this device.": "Selecciona les carpetes per a compartir amb aquest dispositiu.",
"Send & Receive": "Enviar i Rebre",
"Send Only": "Enviar Solament",
@@ -277,12 +284,14 @@
"Share": "Compartir",
"Share Folder": "Compartir carpeta",
"Share Folders With Device": "Compartir carpetes amb el dispositiu",
"Share With Devices": "Compartir amb els dispositius",
"Share this folder?": "Compartir aquesta carpeta?",
"Shared Folders": "Shared Folders",
"Shared With": "Compartit amb",
"Sharing": "Compartint",
"Show ID": "Mostrar ID",
"Show QR": "Mostrar QR",
"Show detailed discovery status": "Show detailed discovery status",
"Show detailed listener status": "Show detailed listener status",
"Show diff with previous version": "Mostrar les diferències amb la versió prèvia",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrat en lloc de l'ID del dispositiu en l'estat del grup (cluster). S'anunciarà als altres dispositius com el nom opcional per defecte.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrat en lloc de l'ID del dispositiu en l'estat del grup (cluster). S'actualitzarà al nom que el dispositiu anuncia si es deixa buit.",
@@ -292,7 +301,9 @@
"Single level wildcard (matches within a directory only)": "Comodí de nivell únic (coincideix sols dins d'un directori)",
"Size": "Tamany",
"Smallest First": "El més xicotet primer",
"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:": "Alguns ítems no s'han pogut restaurar:",
"Some listening addresses could not be enabled to accept connections:": "Some listening addresses could not be enabled to accept connections:",
"Source Code": "Codi font",
"Stable releases and release candidates": "Versions estables i versions candidates",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Les versions estables es retrasen sobre dos setmanes. Durant aquest temps es fiquen a prova com versions candidates.",
@@ -301,6 +312,7 @@
"Start Browser": "Iniciar navegador",
"Statistics": "Estadístiques",
"Stopped": "Parat",
"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.",
"Support": "Suport",
"Support Bundle": "Lot de Suport",
"Sync Protocol Listen Addresses": "Direccions d'escolta del protocol de sincronització",
@@ -308,6 +320,8 @@
"Syncthing has been shut down.": "Syncthing s'ha apagat",
"Syncthing includes the following software or portions thereof:": "Syncthing inclou el següent software o parts d'ell:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing és Software Gratuït i Open Source llicenciat com 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 està reiniciant.",
"Syncthing is upgrading.": "Syncthing està actualitzant-se.",
"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.",
@@ -315,23 +329,29 @@
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing pareix que té un problema processant la seua sol·licitud. Per favor, refresque la pàgina o reinicie Syncthing si el problema persistix.",
"Take me back": "Porta'm enrere",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "L'adreça del GUI és sobreescrita per les opcions d'inici. Els canvis ací no surtiràn efecte mentre la sobreescritura estiga en marxa.",
"The Syncthing Authors": "The Syncthing Authors",
"The Syncthing admin interface is configured to allow remote access without a password.": "L'interfície d'administració de Syncthing està configurat per a permetre l'accés remot sense una contrasenya.",
"The aggregated statistics are publicly available at the URL below.": "Les estadístiques agregades estàn disponibles en la URL que figura a continuació.",
"The cleanup interval cannot be blank.": "The cleanup interval cannot be blank.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuració ha sigut gravada però no activada. Syncthing deu reiniciar per tal d'activar la nova configuració.",
"The device ID cannot be blank.": "L'ID del dispositiu no pot estar buida.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "L'ID del dispositiu que hi ha que introduïr ací es pot trobar en el menú \"Accions > Mostrar ID\" en l'altre dispositiu. Els espais i les barres son opcionals (ignorats).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "L'informe encriptat d'ús s'envia diariament. S'utilitza per a rastrejar plataformes comuns, tamanys de carpetes i versions de l'aplicació. Si el conjunt de dades enviat a l'informe es canvia, se li demanarà a vosté l'autorització altra vegada.\n",
"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.": "L'ID del dispositiu introduïda no pareix vàlida. Deuria ser una cadena de 52 o 56 caracters consistents en lletres i nombre, amb espais i barres opcionals.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "El primer paràmetre de la línia de comandos és la ruta de la carpeta i el segon és la ruta relativa en la carpeta.",
"The folder ID cannot be blank.": "L'ID de la carpeta no pot estar buit.",
"The folder ID must be unique.": "L'ID de la carpeta deu ser única.",
"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 path cannot be blank.": "La ruta de la carpeta no pot estar buida.",
"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.": "S'utilitzen els següents intervals: per a la primera hora es guarda una versió cada 30 segons, per al primer dia es guarda una versió cada hora, per als primers 30 dies es guarda una versió diaria, fins l'edat màxima es guarda una versió cada setmana.",
"The following items could not be synchronized.": "Els següents objectes no s'han pogut sincronitzar.",
"The following items were changed locally.": "Els següents ítems es canviaren localment.",
"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.",
"The maximum age must be a number and cannot be blank.": "L'edat màxima deu ser un nombre i no pot estar buida.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "El temps màxim per a guardar una versió (en dies, ficar 0 per a guardar les versions per a sempre).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "El porcentatge d'espai mínim lliure en el disc deu ser un nombre no negatiu entre 0 i 100 (ambdós inclosos).",
"The number of days must be a number and cannot be blank.": "El nombre de dies deu ser un nombre i no pot estar en blanc.",
"The number of days to keep files in the trash can. Zero means forever.": "El nombre de dies per a mantindre els arxius a la paperera. Cero vol dir \"per a sempre\".",
"The number of old versions to keep, per file.": "El nombre de versions antigues per a guardar, per cada fitxer.",
@@ -340,9 +360,11 @@
"The rate limit must be a non-negative number (0: no limit)": "El llímit del ritme deu ser un nombre no negatiu (0: sense llímit)",
"The rescan interval must be a non-negative number of seconds.": "L'interval de reescaneig deu ser un nombre positiu de segons.",
"There are no devices to share this folder with.": "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.",
"They are retried automatically and will be synced when the error is resolved.": "Es reintenta automàticament i es sincronitzaràn quant el resolga l'error.",
"This Device": "Aquest Dispositiu",
"This can easily give hackers access to read and change any files on your computer.": "Açò pot donar accés fàcilment als hackers per a llegir i canviar qualsevol fitxer al teu ordinador.",
"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.": "Aquesta és una actualització important de la versió.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Aquest ajust controla l'espai lliure requerit en el disc inicial (per exemple, la base de dades de l'index).",
"Time": "Temps",
@@ -353,11 +375,14 @@
"Unavailable": "No disponible",
"Unavailable/Disabled by administrator or maintainer": "No disponible/Desactivar per l'administrador o mantenedor",
"Undecided (will prompt)": "No decidit (es preguntarà)",
"Unexpected Items": "Unexpected Items",
"Unexpected items have been found in this folder.": "Unexpected items have been found in this folder.",
"Unignore": "Designorar",
"Unknown": "Desconegut",
"Unshared": "No compartit",
"Unshared Devices": "Unshared Devices",
"Unused": "No utilitzat",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Up to Date": "Actualitzat",
"Updated": "Actualitzat",
"Upgrade": "Actualitzar",
@@ -367,16 +392,15 @@
"Uptime": "Temps de funcionament",
"Usage reporting is always enabled for candidate releases.": "Els informes d'ús sempre estan activats per a les versions candidates.",
"Use HTTPS for GUI": "Utilitzar HTTPS per a l'Interfície Gràfica d'Usuari (GUI)",
"Use notifications from the filesystem to detect changed items.": "Usar notificacions del sistema de fitxers per a detectar els ítems canviats.",
"Variable Size Blocks": "Blocs de Tamany Variable",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Els blocs de tamany variable (també coneguts com \"blocs grans\") són més eficients per als fitxers grans.",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Username/Password has not been set for the GUI authentication. Please consider setting it up.",
"Version": "Versió",
"Versions": "Versions",
"Versions Path": "Ruta de les versions",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Les versions s'esborren automàticament si són més antigues que l'edat màxima o excedixen el nombre de fitxer permesos en un interval.",
"Waiting to Clean": "Waiting to Clean",
"Waiting to Scan": "Waiting to Scan",
"Waiting to Sync": "Waiting to Sync",
"Waiting to scan": "Esperant per a escanetjar",
"Warning": "Warning",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Perill! Esta ruta és un directori pare d'una carpeta ja existent \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Perill! Esta ruta és un directori pare d'una carpeta existent \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Perill! Esta ruta és un subdirectori d'una carpeta que ja existeix nomenada \"{{otherFolder}}\".",
@@ -395,11 +419,14 @@
"You have no ignored folders.": "No tens carpetes ignorades.",
"You have unsaved changes. Do you really want to discard them?": "Tens canvis sense guardar. Realment vols descartar-los?",
"You must keep at least one version.": "Es deu mantindre al menys una versió.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "You should never add or change anything locally in a \"{{receiveEncrypted}}\" folder.",
"days": "dies",
"directories": "directoris",
"files": "arxius",
"full documentation": "Documentació completa",
"items": "Elements",
"seconds": "seconds",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} vol compartit la carpeta \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} vol compartir la carpeta \"{{folderlabel}}\" ({{folder}})."
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} vol compartir la carpeta \"{{folderlabel}}\" ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} might reintroduce this device."
}

View File

@@ -17,17 +17,16 @@
"Addresses": "Adresy",
"Advanced": "Pokročilé",
"Advanced Configuration": "Pokročilá nastavení",
"Advanced settings": "Pokročilá nastavení",
"All Data": "Všechna data",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Všechny složky sdílené s tímto zařízením musí být chráněna heslem, aby byla odesílaná data bez hesla nečitelná.",
"Allow Anonymous Usage Reporting?": "Povolit anonymní hlášení o používání?",
"Allowed Networks": "Sítě, ze kterých je umožněn přístup",
"Alphabetic": "Abecední",
"An external command handles the versioning. It has to remove the file from the shared folder.": "Správu verzí obstarává externí příkaz. U toho je třeba, aby neaktuální soubory jím byly odsouvány pryč ze sdílené složky.",
"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.": "Správu verzí obstarává externí příkaz. U toho je třeba, aby neaktuální soubory jím byly odsouvány pryč ze sdílené složky. Pokud popis umístění tohoto příkazu obsahuje mezeru, je třeba popis umístění uzavřít do uvozovek.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Správu verzí obstarává externí příkaz. U toho je třeba, aby neaktuální soubory jím byly odsouvány pryč ze synchronizované složky.",
"Anonymous Usage Reporting": "Anonymní hlášení o používání",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formát anonymního hlášení o používání byl změněn. Chcete přejít na nový formát?",
"Any devices configured on an introducer device will be added to this device as well.": "Jakákoliv zařízení, nastavená na zavaděči, budou přidána také na toto zařízení.",
"Are you sure you want to continue?": "Skutečně si přejete pokračovat?",
"Are you sure you want to permanently delete all these files?": "Skutečně chcete smazat všechny tyto soubory?",
"Are you sure you want to remove device {%name%}?": "Opravdu chcete odebrat zařízení {{name}}?",
"Are you sure you want to remove folder {%label%}?": "Opravdu chcete odebrat složku {{label}}?",
"Are you sure you want to restore {%count%} files?": "Opravdu chcete obnovit {{count}} souborů?",
@@ -41,37 +40,45 @@
"Available debug logging facilities:": "Dostupná logovací zařízení pro ladění:",
"Be careful!": "Buďte opatrní!",
"Bugs": "Chyby",
"CPU Utilization": "Využití procesoru",
"Changelog": "Seznam změn",
"Clean out after": "Vyčistit po",
"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ář",
"Compression": "Komprese",
"Configured": "Nastaveno",
"Connected (Unused)": "Připojeno (nepoužité)",
"Connection Error": "Chyba připojení",
"Connection Type": "Typ připojení",
"Connections": "Spojení",
"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 nyní umožňuje nepřetržité sledování změn. To zachytí změny na úložišti a spustí sken pouze pro umístění, ve kterých se něco změnilo. Výhodami jsou rychlejší propagace změn a méně plných skenů.",
"Copied from elsewhere": "Zkopírováno odjinud",
"Copied from original": "Zkopírováno z originálu",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 následující přispěvatelé:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 následující přispěvatelé:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 následující přispěvatelé:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Vytvářejí se vzory ignorovaného a přepisuje se jimi existující soubor v {{path}}.",
"Currently Shared With Devices": "Aktuálně sdíleno se zařízeními",
"Danger!": "Nebezpečí!",
"Debugging Facilities": "Nástroje pro ladění",
"Default Configuration": "Výchozí nastavení",
"Default Device": "Výchozí zařízení",
"Default Folder": "Výchozí složka",
"Default Folder Path": "Popis umístění výchozí složky",
"Defaults": "Výchozí hodnoty",
"Delete Unexpected Items": "Smazat neočekávané položky",
"Deleted": "Smazáno",
"Deselect All": "Zrušit výběr všeho",
"Deselect devices to stop sharing this folder with.": "Zrušte výběr zařízení, se kterými již nemá být tato složka sdílena.",
"Deselect folders to stop sharing with this device.": "Zrušte výběr složek, které se mají přestat sdílet s tímto zařízením.",
"Device": "Zařízení",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Zařízení „{{name}}“ ({{device}} na {{address}}) se chce připojit. Přidat nové zařízení?",
"Device ID": "Identifikátor zařízení",
"Device Identification": "Identifikace zařízení",
"Device Name": "Název zařízení",
"Device is untrusted, enter encryption password": "Zařízení nemá důvěru, zadejte šifrovací heslo.",
"Device rate limits": "Omezení přenosové rychlosti pro zařízení",
"Device that last modified the item": "Zařízení, které položku změnilo naposledy",
"Devices": "Zařízení",
@@ -80,11 +87,16 @@
"Disabled periodic scanning and disabled watching for changes": "Periodické skenování i sledování změn vypnuto",
"Disabled periodic scanning and enabled watching for changes": "Periodické skenování vypnuto; sledování změn zapnuto",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Periodické skenování vypnuto; nastavení sledování změn se nezdařilo, opětovný pokus každou 1 min:",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Zakazuje porovnávání a synchronizaci souborových oprávnění. To je užitečné na systémech, kde oprávnění souborů chybí, nebo jsou nestandardní (např. FAT, exFAT, Synology, Android).",
"Discard": "Zahodit",
"Disconnected": "Odpojeno",
"Disconnected (Unused)": "Odpojeno (nepoužité)",
"Discovered": "Objeveno",
"Discovery": "Oznamování",
"Discovery Failures": "Nezdary při oznamování",
"Discovery": "Objevování",
"Discovery Failures": "Nezdary při objevování",
"Dismiss": "OK",
"Do not add it to the ignore list, so this notification may recur.": "Nepřidávat k ignorování, takže oznámení se může opakovat.",
"Do not add it to the ignore list, so this notification may recurr.": "Nepřidávat k ignorování, takže oznámení se může opakovat.",
"Do not restore": "Neobnovit",
"Do not restore all": "Neobnovit nic",
"Do you want to enable watching for changes for all your folders?": "Chcete zapnout sledování změn pro všechny složky?",
@@ -94,8 +106,9 @@
"Downloading": "Stahuje se",
"Edit": "Upravit",
"Edit Device": "Upravit zařízení",
"Edit Device Defaults": "Upravit výchozí hodnoty zařízení",
"Edit Folder": "Upravit složku",
"Editing": "Upravuje se",
"Edit Folder Defaults": "Upravit výchozí hodnoty složek",
"Editing {%path%}.": "Upravuje se {{path}}.",
"Enable Crash Reporting": "Povolit hlášení pádů",
"Enable NAT traversal": "Povolit průchod skrze NAT překlad",
@@ -103,26 +116,20 @@
"Enabled": "Zapnuto",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Zadejte kladné číslo (např. „2.35“) a zvolte jednotku. Procenta znamenají část celkové velikosti úložiště.",
"Enter a non-privileged port number (1024 - 65535).": "Zadejte číslo neprivilegovaného portu (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Zadejte adresy oddělené čárkou („tcp://ip:port“, „tcp://host:port“) nebo „dynamic“ pro automatické zjišťování adres.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Zadejte adresy oddělené čárkami („tcp://ip:port“, „tcp://host:port“) nebo „dynamic“ pro automatické zjištění adresy.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Zadejte adresy oddělené čárkami („tcp://ip:port“, „tcp://host:port“) nebo „dynamic“ pro automatické objevení adresy.",
"Enter ignore patterns, one per line.": "Zadejte vzory toho, co ignorovat každý na zvlášť řádek.",
"Enter up to three octal digits.": "Zadejte nanejvýš tři osmičkové číslice.",
"Error": "Chyba",
"External File Versioning": "Externí správa verzí souborů",
"Failed Items": "Nezdařené položky",
"Failed to load ignore patterns": "Načtení vzorů ignorovaného se nezdařilo",
"Failed to setup, retrying": "Nastavování se nezdařilo, zkouší se znovu",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Je v pořádku, když připojení k IPv6 serverům nezdaří, pokud není k dispozici IPv6 konektivita.",
"File Pull Order": "Pořadí stahování souborů",
"File Versioning": "Správa verzí souborů",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Bity označující přístupová oprávnění k souborům jsou při hledání změn ignorovány. Použijte pro souborové systémy FAT.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Při nahrazování nebo mazání aplikací Syncthing jsou původní soubory přesunuty do složky .stversions.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Při nahrazování nebo mazání aplikací Syncthing jsou původní soubory přesunuty do složky .stversions.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Při nahrazování nebo mazání aplikací Syncthing jsou původní soubory opatřeny časovou značkou a takto označené verze přesunuty do složky .stversions.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Při nahrazování nebo mazání aplikací Syncthing jsou původní soubory opatřeny časovou značkou a takto označené verze přesunuty do složky .stversions.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Soubory jsou chráněny před změnami na ostatních zařízeních, ale změny provedené z tohoto zařízení budou rozeslány na zbytek clusteru.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Soubory jsou synchronizovány z clusteru, ale lokální změny nebudou rozesílány na ostatní zařízení.",
"Filesystem Notifications": "Oznámení souborového systému",
"Filesystem Watcher Errors": "Chyby sledování soubor. systému",
"Filter by date": "Vybrat podle data",
"Filter by name": "Vybrat podle názvu",
@@ -131,24 +138,28 @@
"Folder Label": "Jmenovka složky",
"Folder Path": "Popis umístění složky",
"Folder Type": "Typ složky",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Typ složky „{{receiveEncrypted}}“ lze nastavit jen při vytváření nové složky.",
"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.": "Typ složky „{{receiveEncrypted}}“ nelze změnit po přidání složky. Je třeba složku odebrat, data na disku vymazat nebo rozšifrovat, a nakonec vytvořit složku znova.",
"Folders": "Složky",
"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.": "Pokus o spuštění sledování změn v těchto složkách se nezdařil. Bude se to opětovně zkoušet každou minutu, takže se to možná brzo povede. Pokud ne, pokuste se najít příčinu. případně požádejte o pomoc.",
"Full Rescan Interval (s)": "Interval plného skenu (sek.)",
"GUI": "Grafické rozhraní",
"GUI Authentication Password": "Přihlašovací heslo pro GUI",
"GUI Authentication User": "Přihlašovací jméno pro GUI",
"GUI Authentication: Set User and Password": "Ověřování v graf. uživatelském rozhraní: Nastavit uživatele a heslo",
"GUI Listen Address": "Adresa, na které GUI očekává spojení",
"GUI Listen Addresses": "Adresy, na kterých GUI očekává spojení",
"GUI Theme": "Motiv vzhledu pro GUI",
"General": "Obecné",
"Generate": "Vytvořit",
"Global Changes": "Globální změny",
"Global Discovery": "Globální oznamování",
"Global Discovery Servers": "Servery globálního oznamování",
"Global Discovery": "Globální objevování",
"Global Discovery Servers": "Servery globálního objevování",
"Global State": "Globální status",
"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",
"Ignore Patterns": "Vzory ignorovaného",
"Ignore Permissions": "Ignorovat oprávnění",
@@ -161,11 +172,10 @@
"Introducer": "Zavaděč",
"Inversion of the given condition (i.e. do not exclude)": "Převrácení dané podmínky (např. nevynechat)",
"Keep Versions": "Kolik verzí ponechávat",
"LDAP": "LDAP",
"Largest First": "Od největších",
"Last File Received": "Poslední přijatý soubor",
"Last Scan": "Poslední sken",
"Last seen": "Naposledy spatřen",
"Later": "Později",
"Latest Change": "Poslední změna",
"Learn more": "Zjistěte více",
"Limit": "Limit",
@@ -173,18 +183,15 @@
"Loading data...": "Načítání dat…",
"Loading...": "Načítání…",
"Local Additions": "Místní příbytky",
"Local Discovery": "Místní oznamování",
"Local Discovery": "Místní objevování",
"Local State": "Místní status",
"Local State (Total)": "Místní status (Celkem)",
"Locally Changed Items": "Lokálně změněné položky",
"Log": "Záznam událostí",
"Log tailing paused. Click here to continue.": "Zaznamenávání událostí pozastaveno. Kliknutím sem v něm bude pokračováno.",
"Log tailing paused. Scroll to bottom continue.": "Zaznamenávání událostí pozastaveno. Sjeďte dolů pro pokračování.",
"Log tailing paused. Scroll to the bottom to continue.": "Zaznamenávání událostí pozastaveno. Sjeďte dolů pro pokračování.",
"Logs": "Záznamy událostí",
"Major Upgrade": "Aktualizace hlavní verze",
"Mass actions": "Hromadné akce",
"Master": "Hlavní",
"Maximum Age": "Maximální časový limit",
"Metadata Only": "Pouze metadata",
"Minimum Free Disk Space": "Minimální velikost volného místa na úložišti",
@@ -200,7 +207,7 @@
"No File Versioning": "Neuchovávat předchozí verze souborů",
"No files will be deleted as a result of this operation.": "Tato operace nesmaže žádné soubory.",
"No upgrades": "Žádné aktualizace",
"Normal": "Normální",
"Not shared": "Nesdílené",
"Notice": "Oznámení",
"OK": "OK",
"Off": "Vypnuta",
@@ -215,14 +222,15 @@
"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": "Popis umístění složky na tomto počítači. Pokud neexistuje, bude vytvořeno. Znak vlnovky (~) může být použit jako zkratka pro",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Popis umístění, ve kterém budou vytvářeny nové automaticky přijaté složky a také výchozího při přidávání nových složek v grafickém uživatelském rozhraní. Vlnovka (~) se rozvine na {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Popis umístění, ve kterém ukládat verze (ponechte prázdné pro výchozí podsložku .stversions ve sdílené složce).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Popis umístění, ve kterém ukládat verze (ponechte prázdné pro výchozí podsložku .stversions ve složce).",
"Pause": "Pozastavit",
"Pause All": "Pozastavit vše",
"Paused": "Pozastaveno",
"Paused (Unused)": "Pozastaveno (nepoužité)",
"Pending changes": "Čekající změny",
"Periodic scanning at given interval and disabled watching for changes": "Periodické skenování podle zadaného intervalu; sledování změn vypnuto",
"Periodic scanning at given interval and enabled watching for changes": "Periodické skenování podle zadaného intervalu; sledování změn zapnuto",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodické skenování podle zadaného intervalu; nastavení sledování změn se nezdařilo, opětovný pokus každou 1 min: ",
"Permanently add it to the ignore list, suppressing further notifications.": "Natrvalo ignorovat, takže oznámení již nebudou přicházet.",
"Permissions": "Oprávnění",
"Please consult the release notes before performing a major upgrade.": "Před přechodem na novější hlavní verzi si nejdříve přečtěte poznámky k vydání nové verze.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "V dialogu Nastavení zadejte uživatelské jméno a heslo pro ověření se v GUI.",
@@ -233,21 +241,22 @@
"Preview": "Náhled",
"Preview Usage Report": "Náhled hlášení o využívání",
"Quick guide to supported patterns": "Rychlá nápověda k podporovaným vzorům",
"RAM Utilization": "Využití operační paměti",
"Random": "Náhodné",
"Receive Encrypted": "Přijmout zašifrované",
"Receive Only": "Pouze přijímací",
"Received data is already encrypted": "Přijatá data jsou již zašifrována",
"Recent Changes": "Nedávné změny",
"Reduced by ignore patterns": "Redukováno o ignorované vzory",
"Release Notes": "Poznámky k vydání",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Kandidáti na vydání obsahují nejnovější změny a opravy. Podobají se tradičním dvoutýdenním vydáním Syncthing.",
"Remote Devices": "Vzdálená zařízení",
"Remote GUI": "Vzdálené GUI",
"Remove": "Odstranit",
"Remove Device": "Odebrat zařízení",
"Remove Folder": "Odebrat složku",
"Required identifier for the folder. Must be the same on all cluster devices.": "Vyžadován identifikátor složky. Je třeba, aby byl na všech zařízeních clusteru stejný.",
"Rescan": "Opakovat skenování",
"Rescan All": "Opakovat skenování všech",
"Rescan Interval": "Interval opakování skenování",
"Rescans": "Opakovaná skenování",
"Restart": "Restart",
"Restart Needed": "Je nutný restart",
@@ -258,18 +267,16 @@
"Resume All": "Pokračovat (vše)",
"Reused": "Opakovaně použité",
"Revert Local Changes": "Vrátit lokální změny",
"Running": "Probíhá",
"Save": "Uložit",
"Scan Time Remaining": "Čas do dokončení skenování",
"Scanning": "Skenování",
"See external versioner help for supported templated command line parameters.": "Pro upřesnění požadovaných parametrů příkazu navštivte nápovědu pro externí správu verzí.",
"See external versioning help for supported templated command line parameters.": "Podporované šablonové parametry příkazové řádky jsou dostupné v nápovědě k externí správě verzí.",
"Select All": "Vybrat vše",
"Select a version": "Vyberte verzi",
"Select additional devices to share this folder with.": "Vyberte další zařízení pro sdílení s touto složkou.",
"Select additional folders to share with this device.": "Vyberte další složky, které mají být sdíleny s tímto zařízením.",
"Select latest version": "Vybrat nejnovější verzi",
"Select oldest version": "Vybrat nejstarší verzi",
"Select the devices to share this folder with.": "Vybrat zařízení, se kterými sdílet tuto složku.",
"Select the folders to share with this device.": "Vybrat složky ke sdílení s tímto zařízením.",
"Send & Receive": "Odesílací a přijímací",
"Send Only": "Pouze odesílací",
@@ -277,12 +284,14 @@
"Share": "Sdílet",
"Share Folder": "Sdílet složku",
"Share Folders With Device": "Sdílet složky s tímto zařízením",
"Share With Devices": "Sdílet se zařízeními",
"Share this folder?": "Sdílet tuto složku?",
"Shared Folders": "Sdílené složky",
"Shared With": "Sdíleno s",
"Sharing": "Sdílení",
"Show ID": "Zobrazit identifikátor",
"Show QR": "Zobrazit QR kód",
"Show detailed discovery status": "Zobrazit detailní stav objevování",
"Show detailed listener status": "Zobrazit detailní stav naslouchajících",
"Show diff with previous version": "Ukázat rozdíl oproti předchozí verzi",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Zobrazeno místo identifikátoru zařízení na náhledu stavu clusteru. Bude odesíláno ostatním zařízením jako výchozí název zařízení.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Zobrazeno místo identifikátoru zařízení na náhledu stavu clusteru. Pokud nebude vyplněno, bude nastaveno na název, který zařízení odesílá.",
@@ -292,7 +301,9 @@
"Single level wildcard (matches within a directory only)": "Jednoúrovňový zástupný znak (shody pouze uvnitř složky)",
"Size": "Velikost",
"Smallest First": "Od nejmenších",
"Some discovery methods could not be established for finding other devices or announcing this device:": "Nebyly zajištěny některé metody pro objevování ostatních zařízení nebo oznamování tohoto zařízení:",
"Some items could not be restored:": "Některé položky nemohly být obnoveny:",
"Some listening addresses could not be enabled to accept connections:": "Některé adresy k naslouchání nebylo možné povolit pro příchozí spojení:",
"Source Code": "Zdrojové kódy",
"Stable releases and release candidates": "Stabilní vydání a kandidáti na vydání",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Stabilní vydání jsou opožděna zhruba o dva týdny. Po tuto dobu se testují jako kandidáti na vydání.",
@@ -301,6 +312,7 @@
"Start Browser": "Otevřít webový prohlížeč",
"Statistics": "Statistiky",
"Stopped": "Zastaveno",
"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.": "Ukládá a synchronizuje pouze zašifrovaná data. Složky na všech připojených zařízeních musí mít nastavené stejné heslo a nebo být také typu „{{receiveEncrypted}}“.",
"Support": "Podpora",
"Support Bundle": "Balík podpory",
"Sync Protocol Listen Addresses": "Adresa, na které synchronizační protokol očekává spojení",
@@ -308,6 +320,8 @@
"Syncthing has been shut down.": "Syncthing bylo vypnuto.",
"Syncthing includes the following software or portions thereof:": "Syncthing obsahuje následující software nebo jejich část:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing je svobodný a open source software licencovaný jako MPL v2.0.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "Syncthing naslouchá pro příchozí spojení na následujících síťových adresách:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Syncthing nenaslouchá pro příchozí spojení na žádné adrese. Mohou fungovat jen odchozí spojení z tohoto zařízení.",
"Syncthing is restarting.": "Syncthing se restartuje.",
"Syncthing is upgrading.": "Syncthing se aktualizuje.",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing nyní umožňuje automaticky hlásit vývojářům pády aplikace. Tato funkce je ve výchozím stavu povolena.",
@@ -315,23 +329,29 @@
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing má nejspíše problém s provedením vašeho požadavku. Pokud problém přetrvává, obnovte stránku v prohlížeči nebo restartujte Syncthing.",
"Take me back": "Jít zpět",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "Adresa v GUI je potlačena parametry při spuštění. Dokud potlačení trvá, zdejší změny nemají efekt.",
"The Syncthing Authors": "Autoři Syncthing",
"The Syncthing admin interface is configured to allow remote access without a password.": "V nastavení aplikace Syncthing je povoleno vzdálené připojení k administrátorskému rozhraní bez zadání hesla.",
"The aggregated statistics are publicly available at the URL below.": "Souhrnné statistiky jsou veřejně dostupné na níže uvedené URL.",
"The cleanup interval cannot be blank.": "Interval mazání nesmí být prázdný.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Nastavení byla uložena, ale nejsou aktivována. Pro aktivaci nového nastavení je třeba Syncthing restartovat.",
"The device ID cannot be blank.": "Identifikátor zařízení nemůže zůstat nevyplněný.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Identifikátor zařízení, který je třeba vložit, lze nalézt v dialogu „Akce > Zobrazit identifikátor“ na druhém zařízení. Mezery a pomlčky nejsou nutné (budou ignorovány).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Šifrovaná data o využití jsou zasílána denně. Jsou používána pro zjištění nejobvyklejších platforem, velikosti složek a verzí aplikace. Pokud se rozsah hlášených dat změní, budete opět upozorněni tímto dialogem.",
"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.": "Zadaný identifikátor zařízení není platný. Měl by mít 52 nebo 56 znaků a měl by obsahovat písmena a číslice. Mezery a pomlčky jsou nepovinné.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "První parametr příkazové řádky je popis umístění složky, druhý je relativní popis umístění v téže složce.",
"The folder ID cannot be blank.": "Identifikátor složky nemůže zůstat nevyplněný.",
"The folder ID must be unique.": "Je třeba, aby se identifikátor složky neopakoval.",
"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.": "Obsah složky na ostatních zařízeních bude přepsán, aby se stal identickým s tímto zařízením. Soubory, které zde chybí, budou smazány na ostatních zařízeních.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "Obsah složky na tomto zařízení bude přepsán, aby se stal identickým s ostatními zařízeními. Lokálně přidané soubory budou smazány.",
"The folder path cannot be blank.": "Popis umístění složky nemůže zůstat nevyplněný.",
"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.": "Jsou použity následující intervaly: za první hodinu jsou ponechány verze pro každých 30 sekund, za první den jsou ponechány verze pro každou hodinu, za prvních 30 dní jsou ponechány verze pro každý den a do nejvyššího nastaveného stáří jsou ponechány verze pro každý týden.",
"The following items could not be synchronized.": "Následující položky nemohly být synchronizovány.",
"The following items were changed locally.": "Tyto položky byly změněny lokálně",
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "K objevování ostatních zařízení a oznamování tohoto zařízení se používají následující metody:",
"The following unexpected items were found.": "Byly nalezeny tyto neočekávané položky.",
"The interval must be a positive number of seconds.": "Interval musí být kladný počet sekund.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "Interval (v sekundách) pro spouštění čištění ve složce s verzemi. Nula pravidelné čištění vypíná.",
"The maximum age must be a number and cannot be blank.": "Nejvyšší stáří je třeba zadat v podobě čísla a nemůže být prázdné.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Maximální doba pro zachování verze (dny, zapsáním hodnoty 0 bude ponecháno navždy).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Procentuální údaj minimální velikosti volného místa na disku musí být číslo mezi 0 až 100 (včetně).",
"The number of days must be a number and cannot be blank.": "Je třeba, aby počet dní bylo číslo a nemůže zůstat nevyplněné.",
"The number of days to keep files in the trash can. Zero means forever.": "Počet dní, po který budou soubory uchovány v koši. Nula znamená navždy.",
"The number of old versions to keep, per file.": "Počet uchovávaných starších verzí každého ze souborů.",
@@ -340,9 +360,11 @@
"The rate limit must be a non-negative number (0: no limit)": "Je třeba, aby limit rychlosti bylo kladné číslo (0: bez limitu)",
"The rescan interval must be a non-negative number of seconds.": "Je třeba, aby interval opakování skenování bylo kladné číslo.",
"There are no devices to share this folder with.": "Nejsou žádná zařízení, se kterými lze sdílet tuto složku.",
"There are no folders to share with this device.": "S tímto zařízením nejsou sdíleny žádné složky.",
"They are retried automatically and will be synced when the error is resolved.": "Nové pokusy o synchronizaci budou probíhat automaticky a položky budou synchronizovány jakmile bude chyba odstraněna.",
"This Device": "Toto zařízení",
"This can easily give hackers access to read and change any files on your computer.": "Toto může útočníkům jednoduše umožnit čtení a úpravy souborů na vašem počítači. ",
"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.": "Toto zařízení nemůže automaticky objevovat ostatní zařízení ani oznamovat ostatním vlastní adresu. Připojit se mohou jen zařízení se staticky nastavenou adresou.",
"This is a major version upgrade.": "Toto je velká aktualizace.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Toto nastavení ovládá velikost volného prostoru na hlavním datovém úložišti (to, na kterém je databáze rejstříku).",
"Time": "Čas",
@@ -353,11 +375,14 @@
"Unavailable": "Nedostupné",
"Unavailable/Disabled by administrator or maintainer": "Není k dispozici / vypnuto správcem systému či balíčku",
"Undecided (will prompt)": "Nerozhodnuto (zeptá se)",
"Unexpected Items": "Neočekávané položky",
"Unexpected items have been found in this folder.": "V této složce byly nalezeny neočekávané položky.",
"Unignore": "Přestat ignorovat",
"Unknown": "Neznámý",
"Unshared": "Nesdílený",
"Unshared Devices": "Nesdílená zařízení",
"Unused": "Nepoužitý",
"Unshared Folders": "Nesdílené složky",
"Untrusted": "Bez důvěry",
"Up to Date": "Aktuální",
"Updated": "Aktualizováno",
"Upgrade": "Přechod na novější verzi",
@@ -367,16 +392,15 @@
"Uptime": "Celkový čas běhu",
"Usage reporting is always enabled for candidate releases.": "Hlášení o používání je pro kandidáty na vydání vždy zapnuto.",
"Use HTTPS for GUI": "Použít pro grafické rozhraní zabezpečení HTTPS",
"Use notifications from the filesystem to detect changed items.": "Použít oznamování soubor. systému pro nalezení změněných položek.",
"Variable Size Blocks": "Bloky proměnlivé velikosti",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Bloky proměnlivé velikosti (také „velké bloky“) jsou účinnější pro velké soubory.",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Pro ověřování v grafickém uživatelském rozhraní nebylo nastaveno uživatelské jméno / heslo. Prosím zvažte nastavení nějakého.",
"Version": "Verze",
"Versions": "Verze",
"Versions Path": "Popis umístění verzí",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Verze jsou automaticky smazány, pokud jsou starší než maximální časový limit nebo překročí počet souborů povolených pro interval.",
"Waiting to Clean": "Čeká se na čistění",
"Waiting to Scan": "Čekání na skenování",
"Waiting to Sync": "Čekání na synchronizaci",
"Waiting to scan": "Čekání na skenování",
"Warning": "Varování",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Varování, tento popis umístění je nadřazenou složkou existující „{{otherFolder}}“.",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Varování, tento popis umístění je nadřazenou složkou existující „{{otherFolderLabel}}“ ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Varování: toto umístění je podsložkou existující „{{otherFolder}}“.",
@@ -395,11 +419,14 @@
"You have no ignored folders.": "Nemáte žádné ignorované složky.",
"You have unsaved changes. Do you really want to discard them?": "Máte neuložené změny. Opravdu je chcete zahodit?",
"You must keep at least one version.": "Je třeba ponechat alespoň jednu verzi.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Ve složce typu „{{receiveEncrypted}}“ byste neměli lokálně nic měnit ani vytvářet.",
"days": "dní",
"directories": "složek",
"directories": "složky",
"files": "souborů",
"full documentation": "úplná dokumentace",
"items": "položky",
"seconds": "sekund",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} chce sdílet složku „{{folder}}“.",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} chce sdílet složku „{{folderlabel}}“ ({{folder}})."
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} chce sdílet složku „{{folderlabel}}“ ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} může toto zařízení znovu uvést."
}

View File

@@ -17,74 +17,86 @@
"Addresses": "Adresser",
"Advanced": "Avanceret",
"Advanced Configuration": "Avanceret konfiguration",
"Advanced settings": "Avancerede indstillinger",
"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.": "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",
"An external command handles the versioning. It has to remove the file from the shared folder.": "En ekstern kommando styrer versioneringen. Den skal fjerne filen fra den delte mappe.",
"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.": "En ekstern kommando styrer versioneringen. Den skal fjerne filen fra den delte mappe. Hvis stien til programmet indeholder mellemrum, bør den sættes i anførselstegn.",
"An external command handles the versioning. It has to remove the file from the synced folder.": " ",
"Anonymous Usage Reporting": "Anonym brugerstatistik",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formatet for anonym brugerstatistik er ændret. Vil du flytte til det nye format?",
"Any devices configured on an introducer device will be added to this device as well.": "Alle enheder som er konfigureret som en introducerende enhed, vil også blive tilføjet til denne enhed.",
"Are you sure you want to continue?": "Fortsætte?",
"Are you sure you want to permanently delete all these files?": "Slette valgte filer permanent?",
"Are you sure you want to remove device {%name%}?": "Er du sikker på, at du vil fjerne enheden {{name}}?",
"Are you sure you want to remove folder {%label%}?": "Er du sikker på, at du vil fjerne mappen {{label}}?",
"Are you sure you want to restore {%count%} files?": "Er du sikker på, at du vil genskabe {{count}} filer?",
"Are you sure you want to upgrade?": "Are you sure you want to upgrade?",
"Are you sure you want to upgrade?": "Opgradere?",
"Auto Accept": "Autoacceptér",
"Automatic Crash Reporting": "Automatic Crash Reporting",
"Automatic Crash Reporting": "Automatisk nedbrud rapportering",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Den automatiske opdatering tilbyder nu valget mellem stabile udgivelser og udgivelseskandidater.",
"Automatic upgrades": "Automatisk opdatering",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Automatisk opgradering er altid aktiveret for kandidat udgivelser",
"Automatically create or share folders that this device advertises at the default path.": "Opret eller del automatisk mapper på standardstien, som denne enhed tilbyder.",
"Available debug logging facilities:": "Tilgængelige faciliteter for fejlretningslogning:",
"Be careful!": "Vær forsigtig!",
"Bugs": "Fejl",
"CPU Utilization": "CPU-forbrug",
"Changelog": "Udgivelsesnoter",
"Clean out after": "Rens efter",
"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.": "Klik for at se fuld identifikation streng og QR kode.",
"Close": "Luk",
"Command": "Kommando",
"Comment, when used at the start of a line": "Kommentar, når den bruges i starten af en linje",
"Compression": "Anvend komprimering",
"Configured": "Konfigureret",
"Connected (Unused)": "Tilsluttet (ubrugt)",
"Connection Error": "Tilslutnings fejl",
"Connection Type": "Tilslutningstype",
"Connections": "Forbindelser",
"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.": "Løbende overvågning af ændringer er nu tilgængeligt i Syncthing. Dette vil opfange ændringer på disken og igangsætte en skanning, men kun på ændrede stier. Fordelene er, er ændringer forplanter sig hurtigere, og at færre komplette skanninger er nødvendige.",
"Copied from elsewhere": "Kopieret fra et andet sted",
"Copied from original": "Kopieret fra originalen",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 de følgende bidragsydere:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 de følgende bidragsydere:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 de følgende bidragsydere:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Opretter ignoreringsmønstre; overskriver en eksisterende fil på {{path}}.",
"Currently Shared With Devices": "Currently Shared With Devices",
"Currently Shared With Devices": "i øjeblikket delt med enheder",
"Danger!": "Fare!",
"Debugging Facilities": "Faciliteter til fejlretning",
"Default Configuration": "Standard opsætning",
"Default Device": "Standard enhed",
"Default Folder": "Standard mappe",
"Default Folder Path": "Standardmappesti",
"Defaults": "Standarder",
"Delete Unexpected Items": "Slet ikke forventede elementer ",
"Deleted": "Slettet",
"Deselect All": "Fravælg alle",
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
"Deselect devices to stop sharing this folder with.": "Fravælg enheder for at stoppe mappe deling.",
"Deselect folders to stop sharing with this device.": "Fravælg mapper for at stoppe deling med denne enhed.",
"Device": "Enhed",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Enheden “{{name}}” ({{device}} på {{address}}) vil gerne forbinde. Tilføj denne enhed?",
"Device ID": "Enheds-ID",
"Device Identification": "Enhedsidentifikation",
"Device Name": "Enhedsnavn",
"Device is untrusted, enter encryption password": "Enhed er ikke-troværdig, indtast krypteringsadgangskode",
"Device rate limits": "Enhedens hastighedsbegrænsning",
"Device that last modified the item": "Enhed, som sidst ændrede filen",
"Devices": "Enheder",
"Disable Crash Reporting": "Disable Crash Reporting",
"Disable Crash Reporting": "Deaktivere nedbrud rapportering",
"Disabled": "Deaktiveret",
"Disabled periodic scanning and disabled watching for changes": "Deaktiverede periodisk skanning og deaktiverede overvågning af ændringer",
"Disabled periodic scanning and enabled watching for changes": "Deaktiverede periodisk skanning og aktiverede overvågning af ændringer",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Deaktiverede periodisk skanning fra og lykkedes ikke med at opsætte overvågning af ændringer; prøver igen hvert minut:",
"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": "Behold ikke",
"Disconnected": "Ikke tilsluttet",
"Disconnected (Unused)": "Ikke tilsluttet (ubrugt)",
"Discovered": "Opdaget",
"Discovery": "Opslag",
"Discovery Failures": "Fejl ved opdagelse",
"Dismiss": "Forlade",
"Do not add it to the ignore list, so this notification may recur.": "Tilføj ikke til ignore liste, så påmindelsen kan gentage.",
"Do not add it to the ignore list, so this notification may recurr.": "Tilføj ikke til ignore liste, så påmindelse kan gentage.",
"Do not restore": "Genskab ikke",
"Do not restore all": "Genskab ikke alle",
"Do you want to enable watching for changes for all your folders?": "Vil du aktivere løbende overvågning af ændringer for alle dine mapper?",
@@ -93,36 +105,31 @@
"Downloaded": "Downloadet",
"Downloading": "Downloader",
"Edit": "Redigér",
"Edit Device": "Redigér enhed",
"Edit Folder": "Redigér mappe",
"Editing": "Redigerer",
"Edit Device": "Redigere enhed",
"Edit Device Defaults": "Rediger enhed standarder",
"Edit Folder": "Redigere mappe",
"Edit Folder Defaults": "Rediger mappe standarder",
"Editing {%path%}.": "Redigerer {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable Crash Reporting": "Aktivere nedbrud rapportering",
"Enable NAT traversal": "Aktivér NAT-traversering",
"Enable Relaying": "Aktivér videresending",
"Enabled": "Aktiveret",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Indtast et ikke-negativt tal (fx “2,35”) og vælg en enhed. Procentsatser er ud fra total diskstørrelse.",
"Enter a non-privileged port number (1024 - 65535).": "Indtast et ikke-priviligeret portnummer (102465535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Angiv kommaseparerede adresser (“tcp://ip:port”, “tcp://host:port”) eller “dynamic” for at benytte automatisk opdagelse af adressen.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Angiv en kommaadskilt adresseliste (\"tcp://ip:port\", \"tcp://host:port\")  eller \"dynamic\" for automatisk at opdage adressen.",
"Enter ignore patterns, one per line.": "Indtast ignoreringsmønstre, ét per linje.",
"Enter up to three octal digits.": "Enter up to three octal digits.",
"Enter up to three octal digits.": "Indtast op til tre oktale cifre.",
"Error": "Fejl",
"External File Versioning": "Ekstern filversionering",
"Failed Items": "Mislykkede filer",
"Failed to load ignore patterns": "Indlæsning af ignoreringsmønstre mislykkedes",
"Failed to setup, retrying": "Opsætning mislykkedes; prøver igen",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Fejl i forbindelse med opkobling til IPv6-servere skal forventes, hvis der ikke er IPv6-forbindelse.",
"File Pull Order": "Hentningsrækkefølge for filer",
"File Versioning": "Filversionering",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Filtilladelsesbits ignoreres, når der søges efter ændringer. Brug på FAT-filsystemer.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Filer bliver flyttet til .stversions-mappen, når de bliver erstattet eller slettet af Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Filer flyttes til .stversions-mappen, når de erstattes eller slettes af Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Filer flyttes til datostemplede versioner i en .stversions-mappe, når de erstattes eller slettes af Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Filer flyttes til datostemplede versioner i en .stversions-mappe, når de erstattes eller slettes af Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Filer beskyttes mod ændringer, foretaget på andre enheder, men ændringerne på denne enhed vil blive sendt til alle andre tilknyttede enheder.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Filer synkroniseres fra tilknyttede enheder, men ændringer på denne enhed sendes ikke til andre enheder.",
"Filesystem Notifications": "Filsystemsnotifikationer",
"Filesystem Watcher Errors": "Fejl ved filsystemovervågning",
"Filter by date": "Filtrér efter dato",
"Filter by name": "Filtrér efter navn",
@@ -131,24 +138,28 @@
"Folder Label": "Mappeetiket",
"Folder Path": "Mappesti",
"Folder Type": "Mappetype",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Mappe type \"{{receiveEncrypted}}\" kan kun indstilles når en ny mappe tilføjes.",
"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.",
"Folders": "Mapper",
"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.": "For de følgende mapper opstod en fejl ved start på overvågning af ændringer. Der prøves igen hvert minut, så fejlene går eventuelt væk snart. Hvis de forbliver, kan du prøve at rette den tilgrundliggende fejl eller spørge efter hjælp, hvis du ikke kan.",
"Full Rescan Interval (s)": "Interval for komplet genskan (sek.)",
"GUI": "GUI",
"GUI Authentication Password": "GUI-adgangskode",
"GUI Authentication User": "GUI-brugernavn",
"GUI Authentication: Set User and Password": "GUI godkendelse: Angiv bruger og adgangskode",
"GUI Listen Address": "GUI-lytteadresse",
"GUI Listen Addresses": "GUI-lytteadresser",
"GUI Theme": "GUI-tema",
"General": "Generalt",
"General": "Generelt",
"Generate": "Opret",
"Global Changes": "Globale ændringer",
"Global Discovery": "Globalt opslag",
"Global Discovery Servers": "Globale opslagsservere",
"Global State": "Global tilstand",
"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": "Identifikation",
"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",
"Ignore Patterns": "Ignoreringsmønstre",
"Ignore Permissions": "Ignorér rettigheder",
@@ -161,30 +172,26 @@
"Introducer": "Introducerende enhed",
"Inversion of the given condition (i.e. do not exclude)": "Det omvendte (dvs. undlad ikke)",
"Keep Versions": "Behold versioner",
"LDAP": "LDAP",
"Largest First": "Største først",
"Last File Received": "Senest modtagne fil",
"Last Scan": "Seneste skanning",
"Last seen": "Sidst set",
"Later": "Senere",
"Latest Change": "Seneste ændring",
"Learn more": "Lær mere",
"Limit": "Grænse",
"Listeners": "Lyttere",
"Loading data...": "Indlæser data ...",
"Loading...": "Indlæser ...",
"Local Additions": "Local Additions",
"Local Additions": "Lokale tilføjelser",
"Local Discovery": "Lokal opslag",
"Local State": "Lokal tilstand",
"Local State (Total)": "Lokal tilstand (total)",
"Locally Changed Items": "Lokalt ændrede filer",
"Log": "Logbog",
"Log tailing paused. Click here to continue.": "Logfølgning pause. Klik her for at fortsætte.",
"Log tailing paused. Scroll to bottom continue.": "Logfølgning på pause. Rul til bunden for at fortsætte.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log sammenkædning er i pause. Rul til bunden for at fortsætte.",
"Logs": "Logbog",
"Major Upgrade": "Opgradering til ny hovedversion",
"Mass actions": "Massehandlinger",
"Master": "Styrende",
"Maximum Age": "Maksimal alder",
"Metadata Only": "Kun metadata",
"Minimum Free Disk Space": "Mindst ledig diskplads",
@@ -200,7 +207,7 @@
"No File Versioning": "Ingen filversionering",
"No files will be deleted as a result of this operation.": "Ingen filer vil blive slettet som resultat af denne handling.",
"No upgrades": "Ingen opgraderinger",
"Normal": "Normal",
"Not shared": "Ikke delte",
"Notice": "Bemærk",
"OK": "OK",
"Off": "Deaktiveret",
@@ -215,39 +222,41 @@
"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": "Sti til den lokale mappe. Vil blive oprettet hvis den ikke findes. Tildetegnet (~) kan bruges som en forkortelse for",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Sti hvor nye automatisk accepterede mapper oprettes, så vel som standardstien der foreslås ved tilføjelse af nye mapper gennem brugerfladen. Tildetegnet (~) udvides til {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Sti hvor versioner skal gemmes (lad være tomt for at bruge .stversions-mappen i den delte mappe).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Sti hvor versioner skal gemmes (lad være tomt for at bruge .stversions-mappen i den delte mappe).",
"Pause": "Pause",
"Pause All": "Sæt alt på pause",
"Paused": "På pause",
"Paused (Unused)": "Pauset (ubrugt)",
"Pending changes": "Ventende ændringer",
"Periodic scanning at given interval and disabled watching for changes": "Periodisk skanning med et givent interval og deaktiveret overvågning af ændringer",
"Periodic scanning at given interval and enabled watching for changes": "Periodisk skanning med et givent interval og aktiveret overvågning af ændringer",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodisk skanning med et givent interval og lykkedes ikke med at opsætte overvågning af ændringer; prøver igen hvert minut:",
"Permanently add it to the ignore list, suppressing further notifications.": "Permanent tilføj til ignore liste, undertrykker yderligere påmindelse.",
"Permissions": "Tilladelser",
"Please consult the release notes before performing a major upgrade.": "Tjek venligst udgivelsesnoterne før opgradering til en ny hovedversion.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Opret venligst en GUI-bruger og -adgangskode i opsætningen.",
"Please wait": "Vent venligst",
"Prefix indicating that the file can be deleted if preventing directory removal": "Forstavelse, der indikerer, at filen kan slettes, hvis fjernelse at mappe undgåes",
"Prefix indicating that the pattern should be matched without case sensitivity": "Forstavelse, der indikerer det mønster, der skal sammenlignes uden versalfølsomhed",
"Preparing to Sync": "Preparing to Sync",
"Preparing to Sync": "Forbereder synkronisering",
"Preview": "Forhåndsvisning",
"Preview Usage Report": "Forhåndsvisning af forbrugsrapport",
"Quick guide to supported patterns": "Kvikguide til understøttede mønstre",
"RAM Utilization": "RAM-forbrug",
"Random": "Tilfældig",
"Receive Encrypted": "Modtag krypteret",
"Receive Only": "Modtag kun",
"Received data is already encrypted": "Modtaget data er allerede krypteret",
"Recent Changes": "Nylige ændringer",
"Reduced by ignore patterns": "Reduceret af ignoreringsmønstre",
"Release Notes": "Udgivelsesnoter",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Udgivelseskandidater indeholder alle de nyeste funktioner og rettelser. De er det samme som de traditionelle tougers-udgivelser af Syncthing.",
"Remote Devices": "Fjernenheder ",
"Remote GUI": "Ekstern grafisk brugerflade",
"Remove": "Fjern",
"Remove Device": "Fjern enhed",
"Remove Folder": "Fjern mappe",
"Required identifier for the folder. Must be the same on all cluster devices.": "Nødvendig identifikator for mappen. Dette skal være det samme på alle enheder.",
"Rescan": "Skan igen",
"Rescan All": "Skan alt igen",
"Rescan Interval": "Genskanningsinterval",
"Rescans": "Genskanninger",
"Restart": "Genstart",
"Restart Needed": "Genstart påkrævet",
@@ -258,18 +267,16 @@
"Resume All": "Genoptag alt",
"Reused": "Genbrugt",
"Revert Local Changes": "Opgiv lokale ændringer",
"Running": "Kører",
"Save": "Gem",
"Scan Time Remaining": "Tid tilbage af skanningen",
"Scanning": "Skanner",
"See external versioner help for supported templated command line parameters.": "Se hjælp til ekstern versionering for understøttede kommandolinjeparametre.",
"See external versioning help for supported templated command line parameters.": "Se hjælp til ekstern versionering for understøttede kommandolinjeparametre.",
"Select All": "Vælg alle",
"Select a version": "Vælg en version",
"Select additional devices to share this folder with.": "Select additional devices to share this folder with.",
"Select additional devices to share this folder with.": "Vælg yderligere enheder at dele denne mappe med.",
"Select additional folders to share with this device.": "Vælg yderligere mapper at dele med denne enhed.",
"Select latest version": "Vælg seneste version",
"Select oldest version": "Vælg ældste version",
"Select the devices to share this folder with.": "Vælg hvilke enheder du vil dele denne mappe med.",
"Select the folders to share with this device.": "Vælg hvilke mapper du vil dele med denne enhed.",
"Send & Receive": "Send og modtag",
"Send Only": "Send kun",
@@ -277,12 +284,14 @@
"Share": "Del",
"Share Folder": "Del mappe",
"Share Folders With Device": "Del mappe med enhed",
"Share With Devices": "Del med enheder",
"Share this folder?": "Del denne mappe?",
"Shared Folders": "Delte mapper",
"Shared With": "Delt med",
"Sharing": "Deler",
"Show ID": "Vis ID",
"Show QR": "Vis QR",
"Show detailed discovery status": "Vis detaljeret opdagelse status",
"Show detailed listener status": "Vis detaljeret lytter status",
"Show diff with previous version": "Vis forskelle fra tidligere version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vises i stedet for enheds-ID i klyngestatus. Vil blive sendt til andre enheder som valgfrit standardnavn.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vises i stedet for enheds-ID i klyngestatus. Vil blive opdateret til det navn, som enheden sender, hvis det ikke er udfyldt.",
@@ -292,7 +301,9 @@
"Single level wildcard (matches within a directory only)": "Enkeltniveau-wildcard (matcher kun inden for en mappe)",
"Size": "Størrelse",
"Smallest First": "Mindste først",
"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:": "Enkelte filer kunne ikke genskabes:",
"Some listening addresses could not be enabled to accept connections:": "Some listening addresses could not be enabled to accept connections:",
"Source Code": "Kildekode",
"Stable releases and release candidates": "Stabile udgivelser og udgivelseskandidater ",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Stabile udgivelser er forsinket med omkring to uger. I denne periode gennemgår de afprøvninger som udgivelseskandidater.",
@@ -301,13 +312,16 @@
"Start Browser": "Start browser",
"Statistics": "Statistikker",
"Stopped": "Stoppet",
"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.",
"Support": "Støt",
"Support Bundle": "Støttepakke",
"Sync Protocol Listen Addresses": "Lytteadresser for synkroniseringsprotokol",
"Syncing": "Synkroniserer",
"Syncthing has been shut down.": "Syncthing er lukket ned.",
"Syncthing includes the following software or portions thereof:": "Syncthing indeholder følgende software eller dele heraf:",
"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 Free and Open Source Software licensed as MPL v2.0.": "Syncthing er fri og åben kildekode software licenseret som 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 genstarter.",
"Syncthing is upgrading.": "Syncthing opgraderer.",
"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.",
@@ -315,23 +329,29 @@
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Det ser ud til, at Syncthing har problemer med at udføre opgaven. Prøv at genindlæse siden eller genstarte Synching, hvis problemet vedbliver.",
"Take me back": "Tag mig tilbage",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.",
"The Syncthing Authors": "Syncthing udviklere",
"The Syncthing admin interface is configured to allow remote access without a password.": "Syncthing-administationsfladen er sat op til at kunne fjernstyres uden adgangskode.",
"The aggregated statistics are publicly available at the URL below.": "Den indsamlede statistik er offentligt tilgængelig på den nedenstående URL.",
"The cleanup interval cannot be blank.": "Ryd op interval kan ikke være tom.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Konfigurationen er gemt, men ikke aktiveret. Syncthing skal genstarte for at aktivere den nye konfiguration.",
"The device ID cannot be blank.": "Enhedens ID må ikke være tom.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Det enheds-ID, som skal indtastes her, kan findes under menuen “Handlinger > Vis ID” på den anden enhed. Mellemrum og bindestreger er valgfri (ignoreres).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Den krypterede forbrugsrapport sendes dagligt. Den benyttes til at spore anvendte platforme, mappestørrelser og programversioner. Hvis den opsamlede data ændres på et senere tidspunkt, vil du blive spurgt om tilladelse igen.",
"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.": "Det indtastede enheds-ID ser ikke gyldigt ud. Det skal være en streng på 52 eller 56 tegn, der består af tal og bogstaver, eventuelt med mellemrum og bindestreger.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "Den første kommandolinjeparameter er mappestien og den anden parameter er den relative sti inden i mappen.",
"The folder ID cannot be blank.": "Mappe-ID må ikke være tom.",
"The folder ID must be unique.": "Mappe-ID skal være unik.",
"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 path cannot be blank.": "Mappestien må ikke være tom.",
"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.": "De følgende intervaller er brugt: Inden for den første time bliver en version gemt hvert 30. sekund, inden for den første dag bliver en version gemt hver time, inden for de første 30 dage bliver en version gemt hver dag, og indtil den maksimale alder bliver en version gemt hver uge.",
"The following items could not be synchronized.": "Følgende filer kunne ikke synkroniseres.",
"The following items were changed locally.": "De følgende filer er ændret lokalt.",
"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.": "Følgende ikke-forventet emner blev fundet.",
"The interval must be a positive number of seconds.": "Intervallet skal være et positivt antal sekunder.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "Interval i sekunder for kørsel af oprydning i versionskatalog. Nul vil deaktivere periodisk rengøring.",
"The maximum age must be a number and cannot be blank.": "Maksimal alder skal være et tal og feltet må ikke være tomt.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Den maksimale tid, en version skal gemmes (i dage; sæt lig med 0 for at beholde gamle versioner for altid).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Procentsatsen for mindst ledig diskplads skal være et ikke-negativt tal mellem 0 og 100 (inklusive).",
"The number of days must be a number and cannot be blank.": "Antallet af dage skal være et tal og feltet må ikke være tomt.",
"The number of days to keep files in the trash can. Zero means forever.": "Antal dage, filer gemmes i papirkurven. Nul betyder for evigt.",
"The number of old versions to keep, per file.": "Antallet af gamle versioner som gemmes per fil.",
@@ -339,25 +359,30 @@
"The path cannot be blank.": "Stien må ikke være tom.",
"The rate limit must be a non-negative number (0: no limit)": "Hastighedsbegrænsningen skal være et ikke-negativt tal (0: ingen begrænsning)",
"The rescan interval must be a non-negative number of seconds.": "Genskanningsintervallet skal være et ikke-negativt antal sekunder.",
"There are no devices to share this folder with.": "There are no devices to share this folder with.",
"There are no devices to share this folder with.": "Der er ingen enheder at dele denne mappe med.",
"There are no folders to share with this device.": "Der er ingen mapper at dele med denne enhed.",
"They are retried automatically and will be synced when the error is resolved.": "De prøves igen automatisk og vil blive synkroniseret, når fejlen er løst.",
"This Device": "Denne enhed",
"This can easily give hackers access to read and change any files on your computer.": "Dette gør det nemt for hackere at få adgang til at læse og ændre filer på din 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.": "Dette er en ny hovedversion.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Denne indstilling styrer den krævede ledige plads på hjemmedrevet (dvs. drevet med indeksdatabasen).",
"Time": "Tid",
"Time the item was last modified": "Tidspunkt for seneste ændring af filen",
"Trash Can File Versioning": "Versionering med papirkurv",
"Type": "Type",
"UNIX Permissions": "UNIX Permissions",
"UNIX Permissions": "UNIX rettigheder",
"Unavailable": "Ikke tilgængelig",
"Unavailable/Disabled by administrator or maintainer": "Ikke tilgængelig / deaktiveret af administrator eller vedligeholder",
"Undecided (will prompt)": "Ubestemt (du bliver spurgt)",
"Unexpected Items": "Ikke forventede elementer",
"Unexpected items have been found in this folder.": "Ikke-forventet emner blev fundet i denne mappe.",
"Unignore": "Fjern ignorering",
"Unknown": "Ukendt",
"Unshared": "Ikke delt",
"Unshared Devices": "Unshared Devices",
"Unused": "Ubrugt",
"Unshared Devices": "Ikke delte enheder",
"Unshared Folders": "Ikke delte mapper",
"Untrusted": "Ikke troværdig",
"Up to Date": "Fuldt opdateret",
"Updated": "Opdateret",
"Upgrade": "Opgradér",
@@ -367,16 +392,15 @@
"Uptime": "Oppetid",
"Usage reporting is always enabled for candidate releases.": "Forbrugsraportering er altid aktiveret for udgivelseskandidater.",
"Use HTTPS for GUI": "Anvend HTTPS til GUI-adgang",
"Use notifications from the filesystem to detect changed items.": "Benyt notifikationer fra filsystemet til at finde filændringer.",
"Variable Size Blocks": "Skiftende blokstørrelse",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Skiftende blokstørrelse (også \"store blokke\") er mere effektivt for større filer.",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Brugernavn/adgangskode er ikke indstillet til GUI godkendelse. Overvej at konfigurere det. ",
"Version": "Version",
"Versions": "Versioner",
"Versions Path": "Versionssti",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versioner slettes automatisk, hvis de er ældre end den givne maksimum alder eller overstiger det tilladte antal filer i et interval.",
"Waiting to Scan": "Waiting to Scan",
"Waiting to Sync": "Waiting to Sync",
"Waiting to scan": "Venter på at skanne",
"Waiting to Clean": "Venter på oprydning",
"Waiting to Scan": "Venter på skanning",
"Waiting to Sync": "Venter på synkronisering",
"Warning": "Advarsel",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Advarsel: Denne sti er en forældermappe til den eksisterende mappe “{{otherFolder}}”.",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advarsel: Denne sti er en forældermappe til den eksisterende mappe “{{otherFolderLabel}}” ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Advarsel: Denne sti er en undermappe til den eksisterende mappe “{{otherFolder}}”.",
@@ -395,11 +419,14 @@
"You have no ignored folders.": "Du har ingen ignorerede mapper.",
"You have unsaved changes. Do you really want to discard them?": "Du har ændringer, som ikke er gemt. Er du sikker på, at du ikke vil beholde dem?",
"You must keep at least one version.": "Du skal beholde mindst én version.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Der bør aldrig tilføjes eller ændres noget lokalt i en \"{{receiveEncrypted}}\" mappe.",
"days": "dage",
"directories": "mapper",
"directories": "kataloger",
"files": "filer",
"full documentation": "fuld dokumentation",
"items": "filer",
"seconds": "sekunder",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} ønsker at dele mappen “{{folder}}”.",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} ønsker at dele mappen “{{folderlabel}}” ({{folder}})."
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} ønsker at dele mappen “{{folderlabel}}” ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} vil muligvis genindføre denne enhed."
}

View File

@@ -17,21 +17,20 @@
"Addresses": "Adressen",
"Advanced": "Erweitert",
"Advanced Configuration": "Erweiterte Konfiguration",
"Advanced settings": "Erweiterte Einstellungen",
"All Data": "Alle Daten",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Alle Ordner, welche mit diesem Gerät geteilt werden, müssen von einem Passwort geschützt werden, so dass die gesendeten Daten ohne Kenntnis des Passworts nicht gelesen werden können. ",
"Allow Anonymous Usage Reporting?": "Übertragung von anonymen Nutzungsberichten erlauben?",
"Allowed Networks": "Erlaubte Netzwerke",
"Alphabetic": "Alphabetisch",
"An external command handles the versioning. It has to remove the file from the shared folder.": "Ein externer Befehl führt die Versionierung durch. Er muss die Datei aus dem geteilten Ordner entfernen.",
"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.": "Ein externer Befehl behandelt die Versionierung. Die Datei aus dem freigegebenen Ordner muss entfernen werden. Wenn der Pfad der Anwendung Leerzeichen enthält, sollte dieser in Anführungszeichen stehen.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Ein externer Programmaufruf handhabt die Versionierung. Es muss die Datei aus dem zu synchronisierendem Ordner entfernen.",
"Anonymous Usage Reporting": "Anonymer Nutzungsbericht",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Das Format des anonymen Nutzungsberichts hat sich geändert. Möchten Sie auf das neue Format umsteigen?",
"Any devices configured on an introducer device will be added to this device as well.": "Alle Geräte, die beim Verteilergerät eingetragen sind, werden auch bei diesem Gerät hinzugefügt.",
"Are you sure you want to continue?": "Sind Sie sicher, dass Sie fortfahren möchten?",
"Are you sure you want to permanently delete all these files?": "Sind Sie sicher, dass Sie all diese Dateien dauerhaft löschen möchten?",
"Are you sure you want to remove device {%name%}?": "Sind Sie sicher, dass sie das Gerät {{name}} entfernen möchten?",
"Are you sure you want to remove folder {%label%}?": "Sind Sie sicher, dass sie den Ordner {{label}} entfernen möchten?",
"Are you sure you want to restore {%count%} files?": "Sind Sie sicher, dass Sie {{count}} Dateien wiederherstellen möchten?",
"Are you sure you want to upgrade?": "Are you sure you want to upgrade?",
"Are you sure you want to upgrade?": "Sind Sie sicher, dass Sie ein Upgrade durchführen möchten?",
"Auto Accept": "Automatische Annahme",
"Automatic Crash Reporting": "Automatische Absturzmeldung",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Die automatische Aktualisierung bietet jetzt die Wahl zwischen stabilen Veröffentlichungen und Veröffentlichungskandidaten.",
@@ -41,37 +40,45 @@
"Available debug logging facilities:": "Verfügbare Debugging-Möglichkeiten:",
"Be careful!": "Vorsicht!",
"Bugs": "Fehler",
"CPU Utilization": "Prozessorauslastung",
"Changelog": "Änderungsprotokoll",
"Clean out after": "Löschen nach",
"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.": "Klicken um die volle Kennung und den QR-Code anzuzeigen.",
"Close": "Schließen",
"Command": "Befehl",
"Comment, when used at the start of a line": "Kommentar, wenn am Anfang der Zeile benutzt.",
"Compression": "Komprimierung",
"Configured": "Konfiguriert",
"Connected (Unused)": "Verbunden (Nicht genutzt)",
"Connection Error": "Verbindungsfehler",
"Connection Type": "Verbindungstyp",
"Connections": "Verbindungen",
"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.": "Kontinuierliche Änderungssuche ist jetzt in Syncthing verfügbar. Dadurch werden Änderungen auf der Festplatte erkannt und durch einen Scan nur die geänderten Pfade überprüft. Die Vorteile bestehen darin, dass Änderungen schneller festgestellt werden und weniger vollständige Scans erforderlich sind.",
"Copied from elsewhere": "Von anderer Quelle kopiert",
"Copied from original": "Vom Original kopiert",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 der folgenden Unterstützer:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 der folgenden Unterstützer:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 folgende Mitwirkende:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Erstelle Ignoriermuster, welche die existierende Datei {{path}} überschreiben.",
"Currently Shared With Devices": "Derzeit mit Geräten geteilt",
"Danger!": "Achtung!",
"Debugging Facilities": "Debugging-Möglichkeiten",
"Default Configuration": "Vorgabekonfiguration",
"Default Device": "Vorgabegerät",
"Default Folder": "Vorgabeordner",
"Default Folder Path": "Standardmäßiger Ordnerpfad",
"Defaults": "Vorgaben",
"Delete Unexpected Items": "Unerwartete Elemente löschen",
"Deleted": "Gelöscht",
"Deselect All": "Alle abwählen",
"Deselect devices to stop sharing this folder with.": "Wähle die Geräte ab, für die dieser Ordner nicht mehr freigegeben werden soll.",
"Deselect devices to stop sharing this folder with.": "Geräte abwählen, um diesen Ordner nicht mehr damit zu teilen.",
"Deselect folders to stop sharing with this device.": "Ordner abwählen, um sie nicht mehr für mit diesem Gerät zu teilen.",
"Device": "Gerät",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Gerät \"{{name}}\" ({{device}} {{address}}) möchte sich verbinden. Gerät hinzufügen?",
"Device ID": "Gerätekennung",
"Device Identification": "Geräteidentifikation",
"Device Name": "Gerätename",
"Device is untrusted, enter encryption password": "Gerät wird nicht vertraut, Verschlüsselungspasswort eingeben",
"Device rate limits": "Gerät Datenratelimit",
"Device that last modified the item": "Gerät, das das Element zuletzt geändert hat",
"Devices": "Geräte",
@@ -80,11 +87,16 @@
"Disabled periodic scanning and disabled watching for changes": "Deaktivierter periodischer Scann und deaktivierter Überwachung von Änderungen",
"Disabled periodic scanning and enabled watching for changes": "Deaktivierter periodischer Scann und aktivierter Überwachung von Änderungen",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Deaktivierter periodischer Scann, fehlgeschlagene überprüfen auf Änderungen und erneuter versuch in 1 Min:",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Deaktiviert Vergleich und Synchronisierung der Dateiberechtigungen. Dies ist hilfreich für Dateisysteme ohne konfigurierbare Berechtigungsparameter (z. B. FAT, exFAT, Synology, Android).",
"Discard": "Verwerfen",
"Disconnected": "Getrennt",
"Disconnected (Unused)": "Getrennt (Nicht genutzt)",
"Discovered": "Ermittelt",
"Discovery": "Gerätesuche",
"Discovery Failures": "Gerätesuchfehler",
"Dismiss": "Ausblenden",
"Do not add it to the ignore list, so this notification may recur.": "Nicht zur Ignorierliste hinzufügen, diese Benachrichtigung kann erneut auftauchen.",
"Do not add it to the ignore list, so this notification may recurr.": "Nicht zur Ignorierliste hinzufügen, diese Benachrichtigung kann erneut auftauchen.",
"Do not restore": "Nicht wiederherstellen",
"Do not restore all": "Nicht alle wiederherstellen",
"Do you want to enable watching for changes for all your folders?": "Möchten Sie das nach Änderungen für alle Ihre Ordner gesucht wird aktivieren?",
@@ -94,8 +106,9 @@
"Downloading": "Lädt herunter",
"Edit": "Bearbeiten",
"Edit Device": "Gerät bearbeiten",
"Edit Device Defaults": "Gerätevorgaben bearbeiten",
"Edit Folder": "Ordner bearbeiten",
"Editing": "Bearbeitet",
"Edit Folder Defaults": "Ordnervorgaben bearbeiten",
"Editing {%path%}.": "Bearbeite {{path}}.",
"Enable Crash Reporting": "Absturzmeldung aktivieren",
"Enable NAT traversal": "NAT-Durchdringung aktivieren",
@@ -103,26 +116,20 @@
"Enabled": "Aktiviert",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Geben Sie eine positive Zahl ein (z.B. \"2.35\") und wählen Sie eine Einheit. Prozentsätze sind Teil der gesamten Festplattengröße.",
"Enter a non-privileged port number (1024 - 65535).": "Geben Sie eine nichtprivilegierte Portnummer ein (1024 - 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Kommagetrennte Adressen (\"tcp://ip:port\", \"tcp://host:port\") oder \"dynamic\" eingeben, um die Adresse automatisch zu ermitteln.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Kommagetrennte Adressen (\"tcp://ip:port\", \"tcp://host:port\") oder \"dynamic\" eingeben, um die Adresse automatisch zu ermitteln.",
"Enter ignore patterns, one per line.": "Geben Sie Ignoriermuster ein, eines pro Zeile.",
"Enter up to three octal digits.": "Enter up to three octal digits.",
"Enter up to three octal digits.": "Tragen Sie bis zu drei oktale Ziffern (0-7) ein.",
"Error": "Fehler",
"External File Versioning": "Externe Dateiversionierung",
"Failed Items": "Fehlgeschlagene Elemente",
"Failed to load ignore patterns": "Fehler beim Laden der Ignoriermuster",
"Failed to setup, retrying": "Fehler beim Installieren, versuche erneut",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Ein Verbindungsfehler zu IPv6-Servern ist zu erwarten, wenn es keine IPv6-Konnektivität gibt.",
"File Pull Order": "Dateiübertragungsreihenfolge",
"File Versioning": "Dateiversionierung",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Dateizugriffsrechte beim Suchen nach Veränderungen ignorieren. Bei FAT-Dateisystemen zu verwenden.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Dateien werden in den .stversions Ordner verschoben, wenn sie von Syncthing ersetzt oder gelöscht wurden.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Dateien werden in den .stversions Ordner verschoben, wenn sie von Syncthing ersetzt oder gelöscht wurden.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Dateien werden mit Datumsstempel versioniert und in den .stversions Ordner verschoben, wenn sie von Syncthing ersetzt oder gelöscht wurden.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Dateien werden mit Datumsstempel versioniert und in den .stversions Ordner verschoben, wenn sie von Syncthing ersetzt oder gelöscht wurden.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Dateien sind auf diesem Gerät schreibgeschützt. Auf diesem Gerät durchgeführte Veränderungen werden aber auf den Rest des Verbunds übertragen.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Dateien werden vom Verbund synchronisiert, aber lokal vorgenommene Änderungen werden nicht an andere Geräte gesendet.",
"Filesystem Notifications": "Dateisystembenachrichtigungen",
"Filesystem Watcher Errors": "Fehler im Dateisystembeobachter",
"Filter by date": "Nach Datum sortieren",
"Filter by name": "Nach Name sortieren",
@@ -131,24 +138,28 @@
"Folder Label": "Ordnerbezeichnung",
"Folder Path": "Ordnerpfad",
"Folder Type": "Ordnertyp",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Ordnertyp „{{receiveEncrypted}}“ kann nur beim Hinzufügen eines neuen Ordners festgelegt werden.",
"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.": "Der Ordnertyp \"{{receiveEncrypted}}\" kann nach dem Hinzufügen nicht geändert werden. Sie müssen den Ordner entfernen, die Daten auf dem Speichermedium löschen oder entschlüsseln und anschließend den Order wieder neu hinzufügen.",
"Folders": "Ordner",
"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.": "Bei den folgenden Ordnern ist ein Fehler aufgetreten, während Sie nach Änderungen suchten. Es wird jede Minute erneut gesucht, damit die Fehler bald verschwinden. Falls die Fehler bestehen bleiben, versuchen Sie, das zugrunde liegende Problem zu beheben, und fragen Sie evtl. nach Hilfe.",
"Full Rescan Interval (s)": "Vollständiges Scanintervall (s)",
"GUI": "GUI",
"GUI Authentication Password": "Passwort für Zugang zur Benutzeroberfläche",
"GUI Authentication User": "Benutzername für Zugang zur Benutzeroberfläche",
"GUI Authentication: Set User and Password": "Authentifizierung für die Benutzeroberfläche: Geben Sie Benutzer und Passwort ein. ",
"GUI Listen Address": "Addresse der Benutzeroberfläche",
"GUI Listen Addresses": "Adressen der Benutzeroberfläche",
"GUI Theme": "GUI Design",
"General": "Allgemein",
"Generate": "Generieren",
"Global Changes": "Globale Änderungen",
"Global Discovery": "Globale Gerätesuche",
"Global Discovery Servers": "Globale Gerätesuchserver",
"Global State": "Globaler Status",
"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": "Kennung",
"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 am Zugriff auf Syncthing und somit Ihren Dateien hindern möchten, richten Sie bitte eine Authentifizierung ein.",
"Ignore": "Ignorieren",
"Ignore Patterns": "Ignoriermuster",
"Ignore Permissions": "Berechtigungen ignorieren",
@@ -161,30 +172,26 @@
"Introducer": "Verteilergerät",
"Inversion of the given condition (i.e. do not exclude)": "Umkehrung der angegebenen Bedingung (z.B. schließe nicht aus)",
"Keep Versions": "Versionen erhalten",
"LDAP": "LDAP",
"Largest First": "Größte zuerst",
"Last File Received": "Letzte Änderung",
"Last Scan": "Letzter Scan",
"Last seen": "Zuletzt online",
"Later": "Später",
"Latest Change": "Letzte Änderung",
"Learn more": "Mehr erfahren",
"Limit": "Limit",
"Listeners": "Zuhörer",
"Loading data...": "Daten werden geladen...",
"Loading...": "Wird geladen...",
"Local Additions": "Local Additions",
"Local Additions": "Lokale Hinzufügungen",
"Local Discovery": "Lokale Gerätesuche",
"Local State": "Lokaler Status",
"Local State (Total)": "Lokaler Status (Gesamt)",
"Locally Changed Items": "Lokal geänderte Elemente",
"Log": "Protokoll",
"Log tailing paused. Click here to continue.": "Protokollaufzeichnungen sind pausiert. Klicken Sie hier um fortzufahren.",
"Log tailing paused. Scroll to bottom continue.": "Protokollierung pausiert. Scrolle nach unten um fortzufahren.",
"Log tailing paused. Scroll to the bottom to continue.": "Protokolländerungsverfolgung angehalten. Zum Ende blättern, um fortzufahren.",
"Logs": "Protokolle",
"Major Upgrade": "Hauptversionsaktualisierung",
"Mass actions": "Massenaktionen",
"Master": "Master",
"Maximum Age": "Höchstalter",
"Metadata Only": "Nur Metadaten",
"Minimum Free Disk Space": "Minimal freier Festplattenspeicher",
@@ -200,7 +207,7 @@
"No File Versioning": "Keine Dateiversionierung",
"No files will be deleted as a result of this operation.": "Durch diesen Vorgang werden keine Dateien gelöscht.",
"No upgrades": "Keine Aktualisierungen",
"Normal": "Normal",
"Not shared": "Nicht geteilt",
"Notice": "Hinweis",
"OK": "OK",
"Off": "Aus",
@@ -215,14 +222,15 @@
"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": "Pfad zum Ordner auf dem lokalen Gerät. Ordner wird erzeugt, wenn er nicht existiert. Das Tilden-Zeichen (~) kann als Abkürzung benutzt werden für",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Pfad, an dem die automatisch angenommenen Ordner erstellt werden, ebenso wie der standardmäßig vorgeschlagene Pfad beim Hinzufügen neuer Ordner über die UI. Tilde-Buchstaben (~) entspricht {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Pfad in dem Versionen gespeichert werden sollen (leer lassen, wenn der Standard .stversions Ordner für den geteilten Ordner verwendet werden soll).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Pfad in dem Versionen gespeichert werden sollen (leer lassen, wenn der Standard .stversions Ordner für den geteilten Ordner verwendet werden soll).",
"Pause": "Pause",
"Pause All": "Alles pausieren",
"Paused": "Pausiert",
"Paused (Unused)": "Pausiert (Nicht genutzt)",
"Pending changes": "Ausstehende Änderungen",
"Periodic scanning at given interval and disabled watching for changes": "Periodisches Scannen bei angegebenen Intervall und deaktivierter Überwachung von Änderungen",
"Periodic scanning at given interval and enabled watching for changes": "Periodisches Scannen bei angegebenen Intervall und aktivierter Überwachung von Änderungen",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodisches Scannen bei angegebenen Intervall, fehlgeschlagene überprüfen auf Änderungen und erneuter versuch in 1 Min:",
"Permanently add it to the ignore list, suppressing further notifications.": "Permanent zur Ignorierliste hinzufügen, um weitere Benachrichtigungen zu unterdrücken.",
"Permissions": "Berechtigungen",
"Please consult the release notes before performing a major upgrade.": "Bitte lesen Sie die Veröffentlichungshinweise bevor Sie eine Hauptversionsaktualisierung installieren.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Bitte lege einen Benutzer und ein Passwort für die Benutzeroberfläche in den Einstellungen fest.",
@@ -233,21 +241,22 @@
"Preview": "Vorschau",
"Preview Usage Report": "Vorschau des Nutzungsberichts",
"Quick guide to supported patterns": "Schnellanleitung zu den unterstützten Mustern",
"RAM Utilization": "RAM-Auslastung",
"Random": "Zufall",
"Receive Encrypted": "Empfange verschlüsselt",
"Receive Only": "Nur empfangen",
"Received data is already encrypted": "Empfangene Daten sind bereits verschlüsselt",
"Recent Changes": "Letzte Änderungen",
"Reduced by ignore patterns": "Durch Ignoriermuster reduziert",
"Release Notes": "Veröffentlichungshinweise",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Veröffentlichungskandidaten enthalten die neuesten Funktionen und Verbesserungen. Sie gleichen den üblichen zweiwöchentlichen Syncthing-Veröffentlichungen.",
"Remote Devices": "Externe Geräte",
"Remote GUI": "Entfernte Oberfläche",
"Remove": "Entfernen",
"Remove Device": "Gerät entfernen",
"Remove Folder": "Ordner entfernen",
"Required identifier for the folder. Must be the same on all cluster devices.": "Erforderliche Bezeichnung für den Ordner. Muss auf allen verbundenen Geräten gleich sein.",
"Rescan": "Neu scannen",
"Rescan All": "Alle neu scannen",
"Rescan Interval": "Scanintervall",
"Rescans": "Neue Scans",
"Restart": "Neustart",
"Restart Needed": "Neustart benötigt",
@@ -258,18 +267,16 @@
"Resume All": "Alles fortsetzen",
"Reused": "Erneut benutzt",
"Revert Local Changes": "Lokale Änderungen zurücksetzen",
"Running": "Läuft gerade",
"Save": "Speichern",
"Scan Time Remaining": "Verbleibende Scanzeit",
"Scanning": "Scannen",
"See external versioner help for supported templated command line parameters.": "Siehe Hilfe des externen Versionierers für unterstützte Befehlszeilenparameter.",
"See external versioning help for supported templated command line parameters.": "Siehe Hilfe zur externen Versionierung für unterstützte Befehlszeilenparameter.",
"Select All": "Alle auswählen",
"Select a version": "Wählen Sie eine Version",
"Select additional devices to share this folder with.": "Wähle weitere Geräte aus, für die dieser Ordner geteilt werden soll.",
"Select additional devices to share this folder with.": "Weitere Geräte auswählen, um diesen Ordner damit zu teilen.",
"Select additional folders to share with this device.": "Weitere Ordner auswählen, um mit diesem Gerät zu teilen.",
"Select latest version": "Letzte Version auswählen",
"Select oldest version": "Älteste Version auswählen",
"Select the devices to share this folder with.": "Wähle die Geräte aus, mit denen Sie diesen Ordner teilen wollen.",
"Select the folders to share with this device.": "Wähle Sie die Ordner aus, die Sie mit diesem Gerät teilen möchten.",
"Send & Receive": "Senden & Empfangen",
"Send Only": "Nur senden",
@@ -277,12 +284,14 @@
"Share": "Teilen",
"Share Folder": "Ordner teilen",
"Share Folders With Device": "Ordner mit diesem Gerät teilen",
"Share With Devices": "Teile mit diesen Geräten",
"Share this folder?": "Diesen Ordner teilen?",
"Shared Folders": "Geteilte Ordner",
"Shared With": "Geteilt mit",
"Sharing": "Teilen",
"Show ID": "Eigene Kennung",
"Show QR": "Zeige QR Code",
"Show detailed discovery status": "Status der Gerätesuche anzeigen",
"Show detailed listener status": "Detaillierten Listener-Status anzeigen",
"Show diff with previous version": "Unterschied zur vorherigen Version anzeigen",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wird anstatt der Gerätekennung im Verbund-Status angezeigt. Wird als optionaler Standardname an andere Geräte bekannt gegeben.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wird auf diesem Gerät als Gerätename angezeigt und an die anderen Geräte im Geräte-Verbund weitergegeben. Wenn kein Gerätename anegegeben wird, wird der Name des entfernten Gerätes genommen.",
@@ -292,7 +301,9 @@
"Single level wildcard (matches within a directory only)": "Einzelnes Maskenzeichen (wird für einen einzelnen Ordner verwendet)",
"Size": "Größe",
"Smallest First": "Kleinstes zuerst",
"Some discovery methods could not be established for finding other devices or announcing this device:": "Zum Auffinden anderer Geräte, oder um dieses Gerät anzukündigen, konnten manche Methoden nicht eingerichtet werden:",
"Some items could not be restored:": "Einige Elemente konnten nicht wiederhergestellt werden:",
"Some listening addresses could not be enabled to accept connections:": "An manchen Netzwerkadressen kann nicht gelauscht werden, um Verbindungen anzunehmen:",
"Source Code": "Quellcode",
"Stable releases and release candidates": "Stabile Veröffentlichungen und Veröffentlichungskandidaten",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Stabile Veröffentlichungen werden ca. 2 Wochen verzögert. Während dieser Zeit durchlaufen sie eine Testphase als Veröffentlichungskandidaten.",
@@ -301,6 +312,7 @@
"Start Browser": "Browser starten",
"Statistics": "Statistiken",
"Stopped": "Gestoppt",
"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.": "Speichert und synchronisiert nur verschlüsselte Daten. Ordner auf allen verbundenen Geräten müssen mit dem selben Passwort eingerichtet werden oder vom Typ \"{{receiveEncrypted}}\" sein.",
"Support": "Support",
"Support Bundle": "Supportpaket",
"Sync Protocol Listen Addresses": "Adresse(n) für das Synchronisierungsprotokoll",
@@ -308,6 +320,8 @@
"Syncthing has been shut down.": "Syncthing wurde heruntergefahren.",
"Syncthing includes the following software or portions thereof:": "Syncthing enthält die folgende Software oder Teile von:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing ist freie und quelloffene Software, lizenziert als MPL v2.0.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "Syncthing lauscht an den folgenden Netzwerkadressen auf Verbindungsversuche von anderen Geräten:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Syncthing lauscht nicht auf Verbindungsversuche von anderen Geräten auf irgendeiner Adresse. Nur von diesem Gerät ausgehende Verbindungen können funktionieren.",
"Syncthing is restarting.": "Syncthing wird neu gestartet",
"Syncthing is upgrading.": "Syncthing wird aktualisiert",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing unterstützt jetzt automatische Absturzberichte an die Entwickler. Diese Funktion ist standardmäßig aktiviert.",
@@ -315,23 +329,29 @@
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing scheint ein Problem mit der Verarbeitung Deiner Eingabe zu haben. Bitte lade die Seite neu oder führe einen Neustart durch, falls das Problem weiterhin besteht.",
"Take me back": "Führe mich zurück",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "Die GUI-Adresse wird durch Startoptionen überschrieben. Hier vorgenommene Änderungen werden nicht wirksam, solange die Überschreibung besteht.",
"The Syncthing Authors": "Die Syncthing-Autoren",
"The Syncthing admin interface is configured to allow remote access without a password.": "Die Syncthing-Oberfläche erlaubt mit den jetzigen Einstellungen einen Zugriff ohne Passwort.",
"The aggregated statistics are publicly available at the URL below.": "Die gesammelten Statistiken sind öffentlich unter der nachfolgenden URL verfügbar.",
"The cleanup interval cannot be blank.": "Das Bereinigungsintervall darf nicht leer sein.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Die Konfiguration wurde gespeichert, aber noch nicht aktiviert. Syncthing muss neugestartet werden, um die neue Konfiguration zu übernehmen.",
"The device ID cannot be blank.": "Die Gerätekennung darf nicht leer sein.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Die hier einzutragende Gerätekennung kann im Dialog \"Aktionen > Kennung anzeigen\" auf dem anderen Gerät gefunden werden. Leerzeichen und Bindestriche sind optional (werden ignoriert).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Der verschlüsselte Nutzungsbericht wird täglich gesendet. Er wird verwendet, um Statistiken über verwendete Betriebssysteme, Ordnergrößen und Programmversionen zu erstellen. Sollte der Bericht in Zukunft weitere Daten erfassen, wird dieses Fenster erneut angezeigt.",
"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.": "Die eingegebene Gerätekennung scheint nicht gültig zu sein. Es sollte eine 52 oder 56 stellige Zeichenkette aus Buchstaben und Nummern sein. Leerzeichen und Bindestriche sind optional.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "Der erste Kommandozeilenparameter ist der Ordnerpfad und der zweite Parameter ist der relative Pfad in diesem Ordner.",
"The folder ID cannot be blank.": "Die Ordnerkennung darf nicht leer sein.",
"The folder ID must be unique.": "Die Ordnerkennung muss eindeutig sein.",
"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.": "Der Ordnerinhalt auf anderen Geräten wird überschrieben, um mit diesem Gerät identisch zu werden. Dateien, die hier nicht vorhanden sind, werden auf anderen Geräten gelöscht.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "Der Ordnerinhalt auf diesem Gerät wird überschrieben, um mit anderen Geräten identisch zu werden. Dateien, die hier neu hinzugefügt wurden, werden gelöscht.",
"The folder path cannot be blank.": "Der Ordnerpfad darf nicht leer sein.",
"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.": "Es wird in folgenden Abständen versioniert: In der ersten Stunde wird alle 30 Sekunden eine Version behalten, am ersten Tag eine jede Stunde, in den ersten 30 Tagen eine jeden Tag. Danach wird bis zum angegebenen Höchstalter eine Version pro Woche behalten.",
"The following items could not be synchronized.": "Die folgenden Elemente konnten nicht synchronisiert werden.",
"The following items were changed locally.": "Die folgenden Elemente wurden lokal geändert.",
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "Die folgenden Methoden werden verwendet, um andere Geräte im Netzwerk aufzufinden und dieses Gerät anzukündigen, damit es von anderen gefunden wird:",
"The following unexpected items were found.": "Die folgenden unerwarteten Elemente wurden gefunden.",
"The interval must be a positive number of seconds.": "Das Intervall muss eine positive Zahl von Sekunden sein.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "Das Intervall, in Sekunden, zwischen den Bereinigungen im Versionsverzeichnis. 0 um das regelmäßige Bereinigen zu deaktivieren.",
"The maximum age must be a number and cannot be blank.": "Das Höchstalter muss angegeben werden und eine Zahl sein.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Die längste Zeit, die alte Versionen vorgehalten werden (in Tagen) (0 um alte Versionen für immer zu behalten).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Der Prozentsatz des minimal freien Festplattenspeichers muss eine nichtnegative Zahl zwischen (inklusive) 0 und 100 sein. ",
"The number of days must be a number and cannot be blank.": "Die Anzahl von Versionen muss eine Ganzzahl und darf nicht leer sein.",
"The number of days to keep files in the trash can. Zero means forever.": "Dauer in Tagen für welche die Dateien aufgehoben werden sollen. 0 bedeutet für immer.",
"The number of old versions to keep, per file.": "Anzahl der alten Versionen, die von jeder Datei behalten werden sollen.",
@@ -340,9 +360,11 @@
"The rate limit must be a non-negative number (0: no limit)": "Das Datenratelimit muss eine nicht negative Zahl sein (0 = kein Limit).",
"The rescan interval must be a non-negative number of seconds.": "Das Scanintervall muss eine nicht negative Anzahl (in Sekunden) sein.",
"There are no devices to share this folder with.": "Es gibt keine Geräte, mit denen dieser Ordner geteilt werden kann.",
"There are no folders to share with this device.": "Es gibt keine Ordner, die mit diesem Gerät geteilt werden können.",
"They are retried automatically and will be synced when the error is resolved.": "Sie werden automatisch heruntergeladen und werden synchronisiert, wenn der Fehler behoben wurde.",
"This Device": "Dieses Gerät",
"This can easily give hackers access to read and change any files on your computer.": "Dies kann dazu führen, dass Unberechtigte relativ einfach auf Ihre Dateien zugreifen und diese ändern können.",
"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.": "Dieses Gerät kann nicht automatisch andere Geräte auffinden, oder seine eigene Adresse bekannt geben, um von anderen gefunden zu werden. Nur Geräte mit statisch konfigurierten Adressen können sich verbinden.",
"This is a major version upgrade.": "Dies ist eine Hauptversionsaktualisierung.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Diese Einstellung regelt den freien Speicherplatz, der für den Systemordner (d.h. Indexdatenbank) erforderlich ist.",
"Time": "Zeit",
@@ -353,11 +375,14 @@
"Unavailable": " Nicht verfügbar",
"Unavailable/Disabled by administrator or maintainer": "Nicht verfügbar/durch Administrator oder Betreuer deaktiviert",
"Undecided (will prompt)": "Unentschlossen (wird nachgefragt)",
"Unexpected Items": "Unerwartete Elemente",
"Unexpected items have been found in this folder.": "In diesem Ordner wurden unerwartete Elemente gefunden.",
"Unignore": "Beachten",
"Unknown": "Unbekannt",
"Unshared": "Ungeteilt",
"Unshared Devices": "Ungeteilte Geräte",
"Unused": "Ungenutzt",
"Unshared Devices": "Nicht geteilte Geräte",
"Unshared Folders": "Nicht geteilte Ordner",
"Untrusted": "Nicht vertraut",
"Up to Date": "Aktuell",
"Updated": "Aktualisiert",
"Upgrade": "Aktualisierung",
@@ -367,16 +392,15 @@
"Uptime": "Betriebszeit",
"Usage reporting is always enabled for candidate releases.": "Nutzungsbericht ist für Veröffentlichungskandidaten immer aktiviert.",
"Use HTTPS for GUI": "HTTPS für Benutzeroberfläche verwenden",
"Use notifications from the filesystem to detect changed items.": "Benachrichtigungen des Dateisystems nutzen, um Änderungen zu erkennen.",
"Variable Size Blocks": "Blöcke mit variabler Größe",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Blöcke mit variabler Größe (auch „große Blöcke“) sind für große Dateien effizienter.",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Benutzername und Passwort für die Benutzeroberfläche sind nicht gesetzt. Setzen Sie diese zum Schutz ihrer Daten. ",
"Version": "Version",
"Versions": "Versionen",
"Versions Path": "Versionierungspfad",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Alte Dateiversionen werden automatisch gelöscht, wenn sie älter als das angegebene Höchstalter sind oder die angegebene Höchstzahl an Dateien erreicht ist.",
"Waiting to Scan": "Waiting to Scan",
"Waiting to Clean": "Warten auf Bereinigung",
"Waiting to Scan": "Warten auf Scannen",
"Waiting to Sync": "Warten auf die Synchronisation",
"Waiting to scan": "Warten auf Scan",
"Warning": "Warnung",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Warnung, dieser Pfad ist ein übergeordneter Ordner eines existierenden Ordners \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Warnung, dieser Pfad ist ein übergeordneter Ordner eines existierenden Ordners \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Warnung, dieser Pfad ist ein Unterordner des existierenden Ordners \"{{otherFolder}}\".",
@@ -395,11 +419,14 @@
"You have no ignored folders.": "Sie haben keine ignorierten Ordner.",
"You have unsaved changes. Do you really want to discard them?": "Sie haben nicht gespeicherte Änderungen. Wollen sie diese wirklich verwerfen?",
"You must keep at least one version.": "Du musst mindestens eine Version behalten.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Sie sollten nie etwas im \"{{receiveEncrypted}}\" Ordner lokal ändern oder hinzufügen.",
"days": "Tage",
"directories": "Ordner",
"directories": "Verzeichnisse",
"files": "Dateien",
"full documentation": "Komplette Dokumentation",
"items": "Elemente",
"seconds": "Sekunden",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} möchte den Ordner \"{{folder}}\" teilen.",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} möchte den Ordner \"{{folderlabel}}\" ({{folder}}) teilen."
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} möchte den Ordner \"{{folderlabel}}\" ({{folder}}) teilen.",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} könnte dieses Gerät wieder einführen."
}

View File

@@ -17,74 +17,86 @@
"Addresses": "Διευθύνσεις",
"Advanced": "Προχωρημένες",
"Advanced Configuration": "Προχωρημένες ρυθμίσεις",
"Advanced settings": "Προχωρημένες ρυθμίσεις",
"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.",
"Allow Anonymous Usage Reporting?": "Να επιτρέπεται η αποστολή ανώνυμων στοιχείων χρήσης;",
"Allowed Networks": "Επιτρεπόμενα δίκτυα",
"Alphabetic": "Αλφαβητικά",
"An external command handles the versioning. It has to remove the file from the shared folder.": "Μια εξωτερική εντολή χειρίζεται την τήρηση εκδόσεων και αναλαμβάνει να αφαιρέσει το αρχείο από τον συγχρονισμένο φάκελο.",
"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 synced folder.": "Μια εξωτερική εντολή χειρίζεται την διαχείριση εκδόσεων. Χρειάζεται να αφαιρέσει το αρχείο από το φάκελο συγχρονισμένων.",
"Anonymous Usage Reporting": "Ανώνυμα στοιχεία χρήσης",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Η μορφή της αναφοράς ανώνυμων στοιχείων χρήσης έχει αλλάξει. Επιθυμείτε να μεταβείτε στη νέα μορφή;",
"Any devices configured on an introducer device will be added to this device as well.": "Αν δηλωθεί σαν «βασικός κόμβος», τότε όλες οι συσκευές που είναι δηλωμένες εκεί θα υπάρχουν και στον τοπικό κόμβο.",
"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 upgrade?": "Are you sure you want to upgrade?",
"Are you sure you want to upgrade?": "Σίγουρα επιθυμείτε να αναβαθμίσετε;",
"Auto Accept": "Αυτόματη αποδοχή",
"Automatic Crash Reporting": "Automatic Crash Reporting",
"Automatic Crash Reporting": "Αυτόματη αναφορά σφαλμάτων",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Για τις αυτόματες αναβαθμίσεις μπορείτε πλέον να επιλέξετε μεταξύ σταθερών εκδόσεων και υποψήφιων εκδόσεων.",
"Automatic upgrades": "Αυτόματη αναβάθμιση",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Η αυτόματη αναβάθμιση είναι πάντα ενεργοποιημένη στις υποψήφιες εκδόσεις.",
"Automatically create or share folders that this device advertises at the default path.": "Αυτόματη δημιουργία ή κοινή χρήση φακέλων τους οποίους ανακοινώνει αυτή η συσκευή στην προκαθορισμένη διαδρομή.",
"Available debug logging facilities:": "Διαθέσιμες επιλογές μηνυμάτων αποσφαλμάτωσης:",
"Be careful!": "Με προσοχή!",
"Bugs": "Bugs",
"CPU Utilization": "Επιβάρυνση του επεξεργαστή",
"Changelog": "Πληροφορίες εκδόσεων",
"Clean out after": "Εκκαθάριση μετά από",
"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": "Σχόλιο, όταν χρησιμοποιείται στην αρχή μιας γραμμής",
"Compression": "Συμπίεση",
"Configured": "Βάσει ρύθμισης",
"Connected (Unused)": "Συνδεδεμένη (εκτός χρήσης)",
"Connection Error": "Σφάλμα σύνδεσης",
"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 original": "Έχει αντιγραφεί από το πρωτότυπο",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 για τους παρακάτω συνεισφέροντες:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 για τους παρακάτω συνεισφέροντες:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 για τους παρακάτω συνεισφέροντες:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Δημιουργία προτύπων αγνόησης, αντικατάσταση του υπάρχοντος αρχείου στο {{path}}.",
"Currently Shared With Devices": "Currently Shared With Devices",
"Currently Shared With Devices": "Διαμοιράζεται με αυτές τις συσκευές",
"Danger!": "Προσοχή!",
"Debugging Facilities": "Εργαλεία αποσφαλμάτωσης",
"Default Configuration": "Default Configuration",
"Default Device": "Default Device",
"Default Folder": "Default Folder",
"Default Folder Path": "Προκαθορισμένη διαδρομή φακέλων",
"Defaults": "Defaults",
"Delete Unexpected Items": "Delete Unexpected Items",
"Deleted": "Διαγραμμένα",
"Deselect All": "Deselect All",
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
"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.",
"Device": "Συσκευή",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Η συσκευή \"{{name}}\" ({{device}} στη διεύθυνση {{address}}) επιθυμεί να συνδεθεί. Προσθήκη της νέας συσκευής;",
"Device ID": "Ταυτότητα συσκευής",
"Device Identification": "Ταυτότητα συσκευής",
"Device Name": "Όνομα συσκευής",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device rate limits": "Όρια ταχύτητας συσκευών",
"Device that last modified the item": "Συσκευή από την οποία πραγματοποιήθηκε η τελευταία τροποποίηση του στοιχείου",
"Devices": "Συσκευές",
"Disable Crash Reporting": "Disable Crash Reporting",
"Disable Crash Reporting": "Απενεργοποίηση αναφοράς σφαλμάτων",
"Disabled": "Απενεργοποιημένη",
"Disabled periodic scanning and disabled watching for changes": "Έχουν απενεργοποιηθεί η τακτική σάρωση και η επιτήρηση αλλαγών",
"Disabled periodic scanning and enabled watching for changes": "Έχει απενεργοποιηθεί η τακτική σάρωση και ενεργοποιηθεί η επιτήρηση αλλαγών",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Έχει απενεργοποιηθεί η τακτική σάρωση και απέτυχε η ενεργοποίηση επιτήρησης αλλαγών. Γίνεται νέα προσπάθεια κάθε 1m:",
"Discard": "Discard",
"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": "Απόρριψη",
"Disconnected": "Αποσυνδεδεμένη",
"Disconnected (Unused)": "Αποσυνδεδεμένη (εκτός χρήσης)",
"Discovered": "Βάσει ανεύρεσης",
"Discovery": "Ανεύρεση συσκευών",
"Discovery Failures": "Αποτυχίες ανεύρεσης συσκευών",
"Dismiss": "Dismiss",
"Do not add it to the ignore list, so this notification may recur.": "Do not add it to the ignore list, so this notification may recur.",
"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 all": "Να μη γίνει επαναφορά όλων",
"Do you want to enable watching for changes for all your folders?": "Επιθυμείτε να ενεργοποιήσετε την επιτήρηση για όλους τους φακέλους σας;",
@@ -94,35 +106,30 @@
"Downloading": "Λήψη",
"Edit": "Επεξεργασία",
"Edit Device": "Επεξεργασία συσκευής",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Folder": "Επεξεργασία φακέλου",
"Editing": "Επεξεργασία σε εξέλιξη",
"Edit Folder Defaults": "Edit Folder Defaults",
"Editing {%path%}.": "Επεξεργασία του {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable Crash Reporting": "Ενεργοποίηση αναφοράς σφαλμάτων",
"Enable NAT traversal": "Ενεργοποίηση διάσχισης NAT",
"Enable Relaying": "Ενεργοποίηση αναμετάδοσης",
"Enabled": "Ενεργοποιημένη",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Εισάγετε έναν μη αρνητικό αριθμό (π.χ. «2.35») και επιλέξτε μια μονάδα μέτρησης. Τα ποσοστά ισχύουν ως προς το συνολικό μέγεθος του δίσκου.",
"Enter a non-privileged port number (1024 - 65535).": "Εισάγετε τον αριθμό μιας μη δεσμευμένης θύρας (1024 - 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Εισάγετε τις διευθύνσεις χωρισμένες με κόμμα (\"tcp://ip:port\", \"tcp://host:port\") ή γράψτε \"dynamic\" για την αυτόματη ανεύρεση τους.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Εισάγετε τις διευθύνσεις χωρισμένες με κόμμα (\"tcp://ip:θύρα\", \"tcp://όνομα:θύρα\") ή γράψτε \"dynamic\" για την αυτόματη ανεύρεση τους.",
"Enter ignore patterns, one per line.": "Δώσε τα πρότυπα που θα αγνοηθούν, ένα σε κάθε γραμμή.",
"Enter up to three octal digits.": "Enter up to three octal digits.",
"Enter up to three octal digits.": "Εισάγετε έως τρία οκταδικά ψηφία.",
"Error": "Σφάλμα",
"External File Versioning": "Εξωτερική τήρηση εκδόσεων",
"Failed Items": "Αρχεία που απέτυχαν",
"Failed to load ignore patterns": "Απέτυχε η φόρτωση προτύπων αγνόησης",
"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": "Τήρηση εκδόσεων αρχείων",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Τα δικαιώματα των αρχείων θα αγνοούνται όταν κοιτάζω για αλλαγές. Αφορά συστήματα αρχείων FAT.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Τα αρχεία που σβήνονται ή αντικαθίστανται από το Syncthing μετακινούνται στον κατάλογο .stversions.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Τα αρχεία που σβήνονται ή αντικαθιστούνται από το Syncthing μετακινούνται σε έναν φάκελο .stversions με χρονοσφραγίδα.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Τα αρχεία που σβήνονται ή αντικαθίστανται από το Syncthing μετακινούνται στον κατάλογο .stversions με χρονοσήμανση.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Τα αρχεία που σβήνονται ή αντικαθιστούνται από το Syncthing μετακινούνται σε έναν φάκελο .stversions με χρονοσφραγίδα.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Τα αρχεία προστατεύονται από αλλαγές που γίνονται σε άλλες συσκευές, αλλά όποιες αλλαγές γίνουν σε αυτή τη συσκευή θα αποσταλούν σε όλη τη συστάδα συσκευών.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Τα αρχεία συγχρονίζονται με τη συστάδα, αλλά οποιεσδήποτε τοπικές αλλαγές δεν αποστέλλονται στις άλλες συσκευές.",
"Filesystem Notifications": "Ειδοποιήσεις συστήματος αρχείων",
"Filesystem Watcher Errors": "Σφάλματα επιτήρησης συστήματος αρχείων",
"Filter by date": "Φιλτράρισμα κατά ημερομηνία",
"Filter by name": "Φιλτράρισμα κατά όνομα",
@@ -131,60 +138,60 @@
"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.",
"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)": "Διάστημα πλήρων επανασαρώσεων (s)",
"GUI": "Γραφικό περιβάλλον",
"GUI Authentication Password": "Κωδικός για την πρόσβαση στη διεπαφή",
"GUI Authentication User": "Χρηστώνυμο για την πρόσβαση στη διεπαφή",
"GUI Authentication: Set User and Password": "GUI Authentication: Set User and Password",
"GUI Listen Address": "Διεύθυνση ακρόασης γραφικού περιβάλλοντος (GUI)",
"GUI Listen Addresses": "Διευθύνσεις από τις οποίες θα είναι προσβάσιμη η διεπαφή",
"GUI Theme": "Θέμα GUI",
"General": "Γενικά",
"Generate": "Δημιουργία",
"Global Changes": "Συνολικές αλλαγές",
"Global Discovery": "Καθολική ανεύρεση",
"Global Discovery Servers": "Διακομιστές καθολικής ανεύρεσης κόμβων",
"Global State": "Καθολική κατάσταση",
"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.",
"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 Patterns": "Πρότυπο για αγνόηση",
"Ignore Permissions": "Αγνόησε τα δικαιώματα",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored at": "Ignored at",
"Ignored Devices": "Αγνοηθείσες συσκευές",
"Ignored Folders": "Αγνοηθέντες φάκελοι",
"Ignored at": "Αγνοήθηκε στην",
"Incoming Rate Limit (KiB/s)": "Περιορισμός ταχύτητας λήψης (KiB/s)",
"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)": "Αντιστροφή της δοσμένης συνθήκης (π.χ. να μην εξαιρείς) ",
"Keep Versions": "Διατήρηση εκδόσεων",
"LDAP": "LDAP",
"Largest First": "Το μεγαλύτερο πρώτα",
"Last File Received": "Πιο πρόσφατο αρχείο",
"Last Scan": "Τελευταία Σάρωση",
"Last seen": "Τελευταία σύνδεση",
"Later": "Αργότερα",
"Latest Change": "Τελευταία αλλαγή",
"Learn more": "Μάθετε περισσότερα",
"Limit": "Limit",
"Limit": "Όριο",
"Listeners": "Ακροατές",
"Loading data...": "Φόρτωση δεδομένων...",
"Loading...": "Φόρτωση...",
"Local Additions": "Local Additions",
"Local Additions": "Τοπικές προσθήκες",
"Local Discovery": "Τοπική ανεύρεση",
"Local State": "Τοπική κατάσταση",
"Local State (Total)": "Τοπική κατάσταση (συνολικά)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "Τοπικές αλλαγές",
"Log": "Αρχείο καταγραφής",
"Log tailing paused. Click here to continue.": "Η αυτόματη κύλιση έχει διακοπεί. Πατήστε εδώ για να συνεχιστεί.",
"Log tailing paused. Scroll to bottom continue.": "Η αυτόματη ακολούθηση του αρχείου καταγραφής είναι σε παύση. Κυλίστε στο τέλος της οθόνης για να συνεχίσετε.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Η αυτόματη παρακολούθηση του αρχείου καταγραφής είναι σε παύση. Κυλίστε στο τέλος της οθόνης για να συνεχίσετε.",
"Logs": "Αρχεία καταγραφής",
"Major Upgrade": "Σημαντική αναβάθμιση",
"Mass actions": "Μαζικές ενέργειες",
"Master": "Βασικός κόμβος",
"Maximum Age": "Μέγιστη ηλικία",
"Metadata Only": "Μόνο μεταδεδομένα",
"Minimum Free Disk Space": "Ελάχιστος ελεύθερος αποθηκευτικός χώρος",
@@ -200,7 +207,7 @@
"No File Versioning": "Να μην τηρούνται εκδόσεις",
"No files will be deleted as a result of this operation.": "Δεν πρόκειται να διαγραφούν αρχεία με αυτή την ενέργεια.",
"No upgrades": "Απενεργοποιημένες",
"Normal": "Κανονικός",
"Not shared": "Not shared",
"Notice": "Σημείωση",
"OK": "OK",
"Off": "Απενεργοποιημένο",
@@ -215,39 +222,41 @@
"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": "Μονοπάτι του φακέλου σε αυτόν τον υπολογιστή. Αν δεν υπάρχει θα δημιουργηθεί. Η περισπωμένη (~) μπορεί να μπει σαν συντόμευση για το",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Διαδρομή όπου θα δημιουργούνται φάκελοι μετά από την αυτόματη αποδοχή, καθώς και προτεινόμενη διανομή κατά την προσθήκη φακέλων μέσω του UI. Ο χαρακτήρας της περισπωμένης (~) μετατρέπεται στο {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Ο κατάλογος στον οποίο θα αποθηκεύονται οι εκδόσεις των αρχείων (αν δεν οριστεί, θα αποθηκεύονται στον υποκατάλογο .stversions)",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Ο φάκελος στον οποίο θα αποθηκεύονται οι εκδόσεις των αρχείων (αν δεν οριστεί θα αποθηκεύονται στον υποφάκελο .stversions)",
"Pause": "Παύση",
"Pause All": "Παύση όλων",
"Paused": "Σε παύση",
"Pending changes": "Pending changes",
"Paused (Unused)": "Σε παύση (εκτός χρήσης)",
"Pending 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 failed setting up watching for changes, retrying every 1m:": "Τακτική σάρωση ανά καθορισμένο διάστημα και αποτυχία ενεργοποίησης επιτήρησης αλλαγών. Γίνεται νέα προσπάθεια κάθε 1m:",
"Permanently add it to the ignore list, suppressing further notifications.": "Permanently add it to the ignore list, suppressing further notifications.",
"Permissions": "Δικαιώματα",
"Please consult the release notes before performing a major upgrade.": "Παρακαλούμε, πριν από την εκτέλεση μιας σημαντικής αναβάθμισης, να συμβουλευτείς το σημείωμα που τη συνοδεύει. ",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Παρακαλώ όρισε στις ρυθμίσεις έναν χρήστη και έναν κωδικό πρόσβασης για τη διεπαφή.",
"Please wait": "Παρακαλώ περιμένετε",
"Prefix indicating that the file can be deleted if preventing directory removal": "Πρόθεμα που δείχνει ότι το αρχείο θα μπορεί να διαγραφεί αν εμποδίζει τη διαγραφή καταλόγου",
"Prefix indicating that the pattern should be matched without case sensitivity": "Πρόθεμα που δείχνει ότι η αντιστοίχιση προτύπου θα γίνεται χωρίς διάκριση πεζών και κεφαλαίων χαρακτήρων",
"Preparing to Sync": "Preparing to Sync",
"Preparing to Sync": "Προετοιμασία συγχρονισμού",
"Preview": "Προεπισκόπηση",
"Preview Usage Report": "Προεπισκόπηση αναφοράς χρήσης",
"Quick guide to supported patterns": "Σύντομη βοήθεια σχετικά με τα πρότυπα αναζήτησης που υποστηρίζονται",
"RAM Utilization": "Επιβάρυνση RAM",
"Random": "Τυχαία",
"Receive Encrypted": "Receive Encrypted",
"Receive Only": "Μόνο λήψη",
"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",
"Remove": "Αφαίρεση",
"Remove Device": "Αφαίρεση συσκευής",
"Remove Folder": "Αφαίρεση φακέλου",
"Required identifier for the folder. Must be the same on all cluster devices.": "Απαραίτητο αναγνωριστικό για τον φάκελο. Πρέπει να είναι το ίδιο σε όλες τις συσκευές με τις οποίες διαμοιράζεται ο φάκελος αυτός.",
"Rescan": "Έλεγξε για αλλαγές",
"Rescan All": "Έλεγξέ τα όλα για αλλαγές",
"Rescan Interval": "Κάθε πότε θα ελέγχεται για αλλαγές ",
"Rescans": "Επανασαρώσεις",
"Restart": "Επανεκκίνηση",
"Restart Needed": "Απαιτείται επανεκκίνηση",
@@ -258,18 +267,16 @@
"Resume All": "Συνέχιση όλων",
"Reused": "Χρησιμοποιήθηκε ξανά",
"Revert Local Changes": "Αναίρεση τοπικών αλλαγών",
"Running": "Εκτελείται",
"Save": "Αποθήκευση",
"Scan Time Remaining": "Εναπομείναντας χρόνος για τον έλεγχο ",
"Scanning": "Έλεγχος για αλλαγές",
"See external versioner help for supported templated command line parameters.": "Ανατρέξτε στην τεκμηρίωση της εξωτερικής τήρησης εκδόσεων για πληροφορίες σχετικά με τις υποστηριζόμενες παραμέτρους της γραμμής εντολών.",
"See external versioning help for supported templated command line parameters.": "Ανατρέξτε στην τεκμηρίωση της εξωτερικής τήρησης εκδόσεων για πληροφορίες σχετικά με τις υποστηριζόμενες παραμέτρους της γραμμής εντολών.",
"Select All": "Select All",
"Select All": "Επιλογή όλων",
"Select a version": "Επιλογή έκδοσης",
"Select additional devices to share this folder with.": "Select additional devices to share this folder with.",
"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 latest version": "Επιλογή τελευταίας έκδοσης",
"Select oldest version": "Επιλογή παλαιότερης έκδοσης",
"Select the devices to share this folder with.": "Διάλεξε τις συσκευές προς τις οποίες θα διαμοιράζεται αυτός ο φάκελος.",
"Select the folders to share with this device.": "Διάλεξε ποιοι φάκελοι θα διαμοιράζονται προς αυτή τη συσκευή.",
"Send & Receive": "Αποστολή και λήψη",
"Send Only": "Μόνο αποστολή",
@@ -277,12 +284,14 @@
"Share": "Διαμοίραση",
"Share Folder": "Διαμοίραση φακέλου",
"Share Folders With Device": "Διαμοίρασε τους φακέλους προς αυτή τη συσκευή",
"Share With Devices": "Διαμοίρασε με αυτές τις συσκευές",
"Share this folder?": "Να διαμοιραστεί αυτός ο φάκελος;",
"Shared Folders": "Shared Folders",
"Shared With": "Διαμοιράζεται με",
"Sharing": "Διαμοιρασμός",
"Show ID": "Εμφάνιση ταυτότητας",
"Show QR": "Δείξε τον κωδικό QR",
"Show detailed discovery status": "Show detailed discovery status",
"Show detailed listener status": "Show detailed listener status",
"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 updated to the name the device advertises if left empty.": "Θα φαίνεται αντί για την ταυτότητα της συσκευής στην προβολή της κατάστασης ολόκληρης της συστάδας. Θα ενημερώνεται αυτόματα αν αλλάξει το όνομα της συσκευής.",
@@ -292,7 +301,9 @@
"Single level wildcard (matches within a directory only)": "Τελεστής μπαλαντέρ (*) για ένα επίπεδο (χρησιμοποιείται για έναν φάκελο μόνο)",
"Size": "Μέγεθος",
"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 listening addresses could not be enabled to accept connections:": "Some listening addresses could not be enabled to accept connections:",
"Source Code": "Πηγαίος κώδικας",
"Stable releases and release candidates": "Σταθερές εκδόσεις και υποψήφιες εκδόσεις.",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Οι σταθερές εκδόσεις βγαίνουν με καθυστέρηση περίπου δύο εβδομάδων. Σε αυτό το διάστημα δοκιμάζονται ως υποψήφιες εκδόσεις.",
@@ -301,37 +312,46 @@
"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.",
"Support": "Υποστήριξη",
"Support Bundle": "Support Bundle",
"Support Bundle": "Πακέτο υποστήριξης",
"Sync Protocol Listen Addresses": "Διευθύνσεις για το πρωτόκολλο συγχρονισμού",
"Syncing": "Συγχρονίζω",
"Syncthing has been shut down.": "Το Syncthing έχει απενεργοποιηθεί.",
"Syncthing includes the following software or portions thereof:": "Το Syncthing περιλαμβάνει τα παρακάτω λογισμικά ή μέρη αυτών:",
"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 Free and Open Source Software licensed as MPL v2.0.": "Το Syncthing είναι ελεύθερο λογισμικό και ανοικτού κώδικα, με άδεια 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 επανεκκινείται.",
"Syncthing is upgrading.": "Το Syncthing αναβαθμίζεται.",
"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.",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Το Syncthing επιτρέπει την αυτόματη υποβολή αναφορών σφαλμάτων στους προγραμματιστές. Η προεπιλεγμένη ρύθμιση είναι να αποστέλλονται οι αναφορές.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Το Syncthing φαίνεται πως είναι απενεργοποιημένο ή υπάρχει πρόβλημα στη σύνδεσή σου στο διαδίκτυο. Προσπαθώ πάλι…",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Το Syncthing φαίνεται να αντιμετωπίζει ένα πρόβλημα με την επεξεργασία του αιτήματός σου. Παρακαλούμε, αν το πρόβλημα συνεχίζει, ανανέωσε την σελίδα ή επανεκκίνησε το Syncthing.",
"Take me back": "Take me back",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.",
"Take me back": "Επιστροφή",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "Η διεύθυνση του GUI έχει τροποποιηθεί μέσω παραμέτρων εκκίνησης. Οι αλλαγές εδώ δεν θα ισχύσουν όσο είναι ενεργές αυτές οι παράμετροι.",
"The Syncthing Authors": "Οι δημιουργοί του Syncthing",
"The Syncthing admin interface is configured to allow remote access without a password.": "Η διεπαφή διαχείρισης του Syncthing είναι ρυθμισμένη να επιτρέπει την πρόσβαση χωρίς κωδικό.",
"The aggregated statistics are publicly available at the URL below.": "Τα στατιστικά που έχουν συλλεγεί είναι δημόσια διαθέσιμα στη παρακάτω διεύθυνση.",
"The cleanup interval cannot be blank.": "The cleanup interval cannot be blank.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Οι ρυθμίσεις έχουν αποθηκευτεί αλλά δεν έχουν ενεργοποιηθεί. Πρέπει να επανεκκινήσεις το Syncthing για να ισχύσουν οι νέες ρυθμίσεις.",
"The device ID cannot be blank.": "Η ταυτότητα της συσκευής δεν μπορεί να είναι κενή",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Η ταυτότητα της συσκευής που θα μπει εδώ βρίσκεται στο μενού «Ενέργειες > Εμφάνιση ταυτότητας» στην άλλη συσκευή. Κενοί χαρακτήρες και παύλες είναι προαιρετικοί (θα αγνοηθούν).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Η κρυπτογραφημένη αναφορά χρήσης στέλνεται καθημερινά. Χρησιμοποιείται για να παραχθούν στατιστικές για τα λειτουργικά συστήματα που χρησιμοποιούνται, τα μεγέθη των φακέλων και τις εκδόσεις των προγραμμάτων. Αν στο μέλλον συμπεριληφθούν και άλλα δεδομένα στην αναφορά χρήσης, τότε αυτό το παράθυρο θα εμφανιστεί ξανά.",
"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.": "Η ταυτότητα συσκευής που έδωσες δε φαίνεται έγκυρη. Θα πρέπει να είναι μια σειρά από 52 ή 56 χαρακτήρες (γράμματα και αριθμοί). Τα κενά και οι παύλες είναι προαιρετικά (αδιάφορα).",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "Η πρώτη παράμετρος στη γραμμή εντολών είναι το μονοπάτι του φακέλου και η δεύτερη παράμετρος είναι το σχετικό μονοπάτι στο φάκελο.",
"The folder ID cannot be blank.": "Η ταυτότητα του φακέλου δεν μπορεί να είναι κενή.",
"The folder ID must be unique.": "Η ταυτότητα του φακέλου πρέπει να είναι μοναδική.",
"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 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.": "Δεν ήταν δυνατόν να συγχρονιστούν τα παρακάτω αρχεία.",
"The following items were changed locally.": "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.",
"The maximum age must be a number and cannot be blank.": "Η μέγιστη ηλικία πρέπει να είναι αριθμός και σίγουρα όχι κενό.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Η μέγιστη ηλικία παλιότερων εκδόσεων (σε ημέρες, αν δώσεις 0 οι παλιότερες εκδόσεις θα διατηρούνται για πάντα).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Το ποσοστό του ελάχιστου διαθέσιμου αποθηκευτικόυ χώρου πρέπει να είναι έναν μη-αρνητικός αριθμός μεταξύ του 0 και του 100 (συμπεριλαμβανομένων)",
"The number of days must be a number and cannot be blank.": "Ο αριθμός ημερών πρέπει να είναι αριθμός και σίγουρα όχι κενό.",
"The number of days to keep files in the trash can. Zero means forever.": "Ο αριθμός ημερών που θα διατηρούνται τα αρχεία στον κάδο. Μηδέν σημαίνει διατήρηση για πάντα.",
"The number of old versions to keep, per file.": "Πόσες παλιότερες εκδόσεις θα διατηρούνται, ανά αρχείο.",
@@ -339,25 +359,30 @@
"The path cannot be blank.": "Το μονοπάτι δεν μπορεί να είναι κενό.",
"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 devices to share this folder with.",
"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.",
"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.": "Αυτό μπορεί εύκολα να δώσει πρόσβαση ανάγνωσης και επεξεργασίας αρχείων του υπολογιστή σας σε χάκερς.",
"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 setting controls the free space required on the home (i.e., index database) disk.": "Αυτή η επιλογή καθορίζει τον ελεύθερο χώρο που θα παραμένει ελεύθερος στον δίσκο όπου βρίσκεται ο κατάλογος της εφαρμογής (και συνεπώς η βάση δεδομένων ευρετηρίων).",
"Time": "Χρόνος",
"Time the item was last modified": "Ώρα τελευταίας τροποποίησης του στοιχείου",
"Trash Can File Versioning": "Τήρηση εκδόσεων κάδου ανακύκλωσης",
"Type": "Τύπος",
"UNIX Permissions": "UNIX Permissions",
"UNIX Permissions": "Άδειες αρχείων UNIX",
"Unavailable": "Μη διαθέσιμο",
"Unavailable/Disabled by administrator or maintainer": "Μη διαθέσιμο/απενεργοποιημένο από τον διαχειριστή ή υπεύθυνο διανομής",
"Undecided (will prompt)": "Μη καθορισμένη (θα γίνει ερώτηση)",
"Unignore": "Unignore",
"Unexpected Items": "Unexpected Items",
"Unexpected items have been found in this folder.": "Unexpected items have been found in this folder.",
"Unignore": "Αναίρεση αγνόησης",
"Unknown": "Άγνωστο",
"Unshared": "Δε μοιράζεται",
"Unshared Devices": "Unshared Devices",
"Unused": "Δε χρησιμοποιείται",
"Unshared Devices": "Συσκευές χωρίς διαμοιρασμό",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Up to Date": "Ενημερωμένη",
"Updated": "Ενημερωμένο",
"Upgrade": "Αναβάθμιση",
@@ -367,16 +392,15 @@
"Uptime": "Χρόνος απρόσκοπτης λειτουργίας",
"Usage reporting is always enabled for candidate releases.": "Η αποστολή αναφορών χρήσης είναι πάντα ενεργοποιημένη στις υποψήφιες εκδόσεις.",
"Use HTTPS for GUI": "Χρήση HTTPS για τη διεπαφή",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Username/Password has not been set for the GUI authentication. Please consider setting it up.",
"Version": "Έκδοση",
"Versions": "Εκδόσεις",
"Versions Path": "Φάκελος τήρησης εκδόσεων",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Οι παλιές εκδόσεις θα σβήνονται αυτόματα όταν ξεπεράσουν τη μέγιστη ηλικία ή όταν ξεπεραστεί ο μέγιστος αριθμός αρχείων ανά περίοδο.",
"Waiting to Scan": "Waiting to Scan",
"Waiting to Sync": "Waiting to Sync",
"Waiting to scan": "Waiting to scan",
"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}}\".",
@@ -384,22 +408,25 @@
"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.",
"Watching for changes discovers most changes without periodic scanning.": "Με την επιτήρηση αλλαγών ανιχνεύονται οι περισσότερες αλλαγές χωρίς τακτικές σαρώσεις.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Θυμήσου πως όταν προσθέτεις μια νέα συσκευή, ετούτη η συσκευή θα πρέπει να προστεθεί και στην άλλη πλευρά.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Όταν προσθέτεις έναν νέο φάκελο, θυμήσου πως η ταυτότητα ενός φακέλου χρησιμοποιείται για να να συσχετίσει φακέλους μεταξύ συσκευών. Η ταυτότητα του φακέλου θα πρέπει να είναι η ίδια σε όλες τις συσκευές και έχουν σημασία τα πεζά ή κεφαλαία γράμματα.",
"Yes": "Ναι",
"You can also select one of these nearby devices:": "Μπορείτε επίσης να επιλέξετε μια από αυτές τις γειτονικές συσκευές:",
"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 devices.",
"You have no ignored folders.": "You have no ignored folders.",
"You have unsaved changes. Do you really want to discard them?": "You have unsaved changes. Do you really want to discard them?",
"You have no ignored devices.": "Δεν έχετε αγνοηθείσες συσκευές.",
"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.",
"days": "Μέρες",
"directories": "κατάλογοι",
"files": "αρχεία",
"full documentation": "πλήρης τεκμηρίωση",
"items": "εγγραφές",
"seconds": "δευτερόλεπτα",
"{%device%} wants to share folder \"{%folder%}\".": "Η συσκευή {{device}} θέλει να μοιράσει τον φάκελο «{{folder}}».",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "Η συσκευή {{device}} επιθυμεί να διαμοιράσει τον φάκελο \"{{folderlabel}}\" ({{folder}})."
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "Η συσκευή {{device}} επιθυμεί να διαμοιράσει τον φάκελο \"{{folderlabel}}\" ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} might reintroduce this device."
}

View File

@@ -0,0 +1,432 @@
{
"A device with that ID is already added.": "A device with that ID is already added.",
"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.": "A new major version may not be compatible with previous versions.",
"API Key": "API Key",
"About": "About",
"Action": "Action",
"Actions": "Actions",
"Add": "Add",
"Add Device": "Add Device",
"Add Folder": "Add Folder",
"Add Remote Device": "Add Remote Device",
"Add devices from the introducer to our device list, for mutually shared folders.": "Add devices from the introducer to our device list, for mutually shared folders.",
"Add new folder?": "Add new folder?",
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.",
"Address": "Address",
"Addresses": "Addresses",
"Advanced": "Advanced",
"Advanced Configuration": "Advanced Configuration",
"All Data": "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.",
"Allow Anonymous Usage Reporting?": "Allow Anonymous Usage Reporting?",
"Allowed Networks": "Allowed Networks",
"Alphabetic": "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 Reporting",
"Anonymous usage report format has changed. Would you like to move to the new format?": "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%}?": "Are you sure you want to remove device {{name}}?",
"Are you sure you want to remove folder {%label%}?": "Are you sure you want to remove folder {{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 upgrade?": "Are you sure you want to upgrade?",
"Auto Accept": "Auto Accept",
"Automatic Crash Reporting": "Automatic Crash Reporting",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Automatic upgrade now offers the choice between stable releases and release candidates.",
"Automatic upgrades": "Automatic upgrades",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatically create or share folders that this device advertises at the default path.": "Automatically create or share folders that this device advertises at the default path.",
"Available debug logging facilities:": "Available debug logging facilities:",
"Be careful!": "Be careful!",
"Bugs": "Bugs",
"Changelog": "Changelog",
"Clean out after": "Clean out after",
"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",
"Compression": "Compression",
"Configured": "Configured",
"Connected (Unused)": "Connected (Unused)",
"Connection Error": "Connection Error",
"Connection Type": "Connection Type",
"Connections": "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.": "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 fewer full scans are required.",
"Copied from elsewhere": "Copied from elsewhere",
"Copied from original": "Copied from original",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creating ignore patterns, overwriting an existing file at {{path}}.",
"Currently Shared With Devices": "Currently Shared With Devices",
"Danger!": "Danger!",
"Debugging Facilities": "Debugging Facilities",
"Default Configuration": "Default Configuration",
"Default Device": "Default Device",
"Default Folder": "Default Folder",
"Default Folder Path": "Default Folder Path",
"Defaults": "Defaults",
"Delete Unexpected Items": "Delete Unexpected Items",
"Deleted": "Deleted",
"Deselect All": "Deselect All",
"Deselect devices to stop sharing this folder with.": "Deselect devices to stop sharing this folder with.",
"Deselect folders to stop sharing with this device.": "Deselect folders to stop sharing with this device.",
"Device": "Device",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Device \"{{name}}\" ({{device}} at {{address}}) wants to connect. Add new device?",
"Device ID": "Device ID",
"Device Identification": "Device Identification",
"Device Name": "Device Name",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device rate limits": "Device rate limits",
"Device that last modified the item": "Device that last modified the item",
"Devices": "Devices",
"Disable Crash Reporting": "Disable Crash Reporting",
"Disabled": "Disabled",
"Disabled periodic scanning and disabled watching for changes": "Disabled periodic scanning and disabled watching for changes",
"Disabled periodic scanning and enabled watching for changes": "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",
"Disconnected": "Disconnected",
"Disconnected (Unused)": "Disconnected (Unused)",
"Discovered": "Discovered",
"Discovery": "Discovery",
"Discovery Failures": "Discovery Failures",
"Dismiss": "Dismiss",
"Do not add it to the ignore list, so this notification may recur.": "Do not add it to the ignore list, so this notification may recur.",
"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?",
"Documentation": "Documentation",
"Download Rate": "Download Rate",
"Downloaded": "Downloaded",
"Downloading": "Downloading",
"Edit": "Edit",
"Edit Device": "Edit Device",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Folder": "Edit Folder",
"Edit Folder Defaults": "Edit Folder Defaults",
"Editing {%path%}.": "Editing {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable NAT traversal": "Enable NAT traversal",
"Enable Relaying": "Enable Relaying",
"Enabled": "Enabled",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.",
"Enter a non-privileged port number (1024 - 65535).": "Enter a non-privileged port number (1024 - 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Enter up to three octal digits.": "Enter up to three octal digits.",
"Error": "Error",
"External File Versioning": "External File Versioning",
"Failed Items": "Failed Items",
"Failed to setup, retrying": "Failed to setup, retrying",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.",
"File Pull Order": "File Pull Order",
"File Versioning": "File Versioning",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Files are moved to .stversions directory when replaced or deleted by Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Files are synchronised from the cluster, but any changes made locally will not be sent to other devices.",
"Filesystem Watcher Errors": "Filesystem Watcher Errors",
"Filter by date": "Filter by date",
"Filter by name": "Filter by name",
"Folder": "Folder",
"Folder ID": "Folder ID",
"Folder Label": "Folder Label",
"Folder Path": "Folder Path",
"Folder Type": "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.",
"Folders": "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.": "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",
"GUI Authentication Password": "GUI Authentication Password",
"GUI Authentication User": "GUI Authentication User",
"GUI Authentication: Set User and Password": "GUI Authentication: Set User and Password",
"GUI Listen Address": "GUI Listen Address",
"GUI Theme": "GUI Theme",
"General": "General",
"Generate": "Generate",
"Global Discovery": "Global Discovery",
"Global Discovery Servers": "Global Discovery Servers",
"Global State": "Global State",
"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",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Ignore Permissions",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored at": "Ignored at",
"Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Incorrect configuration may damage your folder contents and render Syncthing inoperable.",
"Introduced By": "Introduced By",
"Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Keep Versions": "Keep Versions",
"LDAP": "LDAP",
"Largest First": "Largest First",
"Last Scan": "Last Scan",
"Last seen": "Last seen",
"Latest Change": "Latest Change",
"Learn more": "Learn more",
"Limit": "Limit",
"Listeners": "Listeners",
"Loading data...": "Loading data...",
"Loading...": "Loading...",
"Local Additions": "Local Additions",
"Local Discovery": "Local Discovery",
"Local State": "Local State",
"Local State (Total)": "Local State (Total)",
"Locally Changed Items": "Locally Changed Items",
"Log": "Log",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Logs",
"Major Upgrade": "Major Upgrade",
"Mass actions": "Mass actions",
"Maximum Age": "Maximum Age",
"Metadata Only": "Metadata Only",
"Minimum Free Disk Space": "Minimum Free Disk Space",
"Mod. Device": "Mod. Device",
"Mod. Time": "Mod. Time",
"Move to top of queue": "Move to top of queue",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Never",
"New Device": "New Device",
"New Folder": "New Folder",
"Newest First": "Newest First",
"No": "No",
"No File Versioning": "No File Versioning",
"No files will be deleted as a result of this operation.": "No files will be deleted as a result of this operation.",
"No upgrades": "No upgrades",
"Not shared": "Not shared",
"Notice": "Notice",
"OK": "OK",
"Off": "Off",
"Oldest First": "Oldest First",
"Optional descriptive label for the folder. Can be different on each device.": "Optional descriptive label for the folder. Can be different on each device.",
"Options": "Options",
"Out of Sync": "Out of Sync",
"Out of Sync Items": "Out of Sync Items",
"Outgoing Rate Limit (KiB/s)": "Outgoing Rate Limit (KiB/s)",
"Override Changes": "Override Changes",
"Path": "Path",
"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": "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",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).",
"Pause": "Pause",
"Pause All": "Pause All",
"Paused": "Paused",
"Paused (Unused)": "Paused (Unused)",
"Pending changes": "Pending changes",
"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.",
"Please wait": "Please wait",
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefix indicating that the file can be deleted if preventing directory removal",
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefix indicating that the pattern should be matched without case sensitivity",
"Preparing to Sync": "Preparing to Sync",
"Preview": "Preview",
"Preview Usage Report": "Preview Usage Report",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"Random": "Random",
"Receive Encrypted": "Receive Encrypted",
"Receive Only": "Receive Only",
"Received data is already encrypted": "Received data is already encrypted",
"Recent Changes": "Recent Changes",
"Reduced by ignore patterns": "Reduced by ignore patterns",
"Release Notes": "Release Notes",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.",
"Remote Devices": "Remote Devices",
"Remote GUI": "Remote GUI",
"Remove": "Remove",
"Remove Device": "Remove Device",
"Remove Folder": "Remove Folder",
"Required identifier for the folder. Must be the same on all cluster devices.": "Required identifier for the folder. Must be the same on all cluster devices.",
"Rescan": "Rescan",
"Rescan All": "Rescan All",
"Rescans": "Rescans",
"Restart": "Restart",
"Restart Needed": "Restart Needed",
"Restarting": "Restarting",
"Restore": "Restore",
"Restore Versions": "Restore Versions",
"Resume": "Resume",
"Resume All": "Resume All",
"Reused": "Reused",
"Revert Local Changes": "Revert Local Changes",
"Save": "Save",
"Scan Time Remaining": "Scan Time Remaining",
"Scanning": "Scanning",
"See external versioning help for supported templated command line parameters.": "See external versioning help for supported templated command line parameters.",
"Select All": "Select All",
"Select a version": "Select a version",
"Select additional devices to share this folder with.": "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 latest version": "Select latest version",
"Select oldest version": "Select oldest version",
"Select the folders to share with this device.": "Select the folders to share with this device.",
"Send & Receive": "Send & Receive",
"Send Only": "Send Only",
"Settings": "Settings",
"Share": "Share",
"Share Folder": "Share Folder",
"Share Folders With Device": "Share Folders With Device",
"Share this folder?": "Share this folder?",
"Shared Folders": "Shared Folders",
"Shared With": "Shared With",
"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.",
"Shutdown": "Shutdown",
"Shutdown Complete": "Shutdown Complete",
"Simple File Versioning": "Simple File Versioning",
"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.",
"Stable releases only": "Stable releases only",
"Staggered File Versioning": "Staggered File Versioning",
"Start Browser": "Start Browser",
"Statistics": "Statistics",
"Stopped": "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.",
"Support": "Support",
"Support Bundle": "Support Bundle",
"Sync Protocol Listen Addresses": "Sync Protocol Listen Addresses",
"Syncing": "Syncing",
"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.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.",
"Take me back": "Take me back",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.",
"The Syncthing Authors": "The Syncthing Authors",
"The Syncthing admin interface is configured to allow remote access without a password.": "The Syncthing admin interface is configured to allow remote access without a password.",
"The aggregated statistics are publicly available at the URL below.": "The aggregated statistics are publicly available at the URL below.",
"The cleanup interval cannot be blank.": "The cleanup interval cannot be blank.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.",
"The device ID cannot be blank.": "The device ID cannot be blank.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.",
"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.": "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.",
"The folder ID cannot be blank.": "The folder ID cannot be blank.",
"The folder ID must be unique.": "The folder ID must be unique.",
"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 path cannot be blank.": "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 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 synchronised.",
"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.",
"The maximum age must be a number and cannot be blank.": "The maximum age must be a number and cannot be blank.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "The maximum time to keep a version (in days, set to 0 to keep versions forever).",
"The number of days must be a number and cannot be blank.": "The number of days must be a number and cannot be blank.",
"The number of days to keep files in the trash can. Zero means forever.": "The number of days to keep files in the bin. Zero means forever.",
"The number of old versions to keep, per file.": "The number of old versions to keep, per file.",
"The number of versions must be a number and cannot be blank.": "The number of versions must be a number and cannot be blank.",
"The path cannot be blank.": "The path cannot be blank.",
"The rate limit must be a non-negative number (0: no limit)": "The rate limit must be a non-negative number (0: no limit)",
"The rescan interval must be a non-negative number of seconds.": "The rescan interval must be a non-negative number of seconds.",
"There are no devices to share this folder with.": "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.",
"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",
"Time the item was last modified": "Time the item was last modified",
"Trash Can File Versioning": "Bin File Versioning",
"Type": "Type",
"UNIX Permissions": "UNIX Permissions",
"Unavailable": "Unavailable",
"Unavailable/Disabled by administrator or maintainer": "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",
"Unknown": "Unknown",
"Unshared": "Unshared",
"Unshared Devices": "Unshared Devices",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Up to Date": "Up to Date",
"Updated": "Updated",
"Upgrade": "Upgrade",
"Upgrade To {%version%}": "Upgrade To {{version}}",
"Upgrading": "Upgrading",
"Upload Rate": "Upload Rate",
"Uptime": "Uptime",
"Usage reporting is always enabled for candidate releases.": "Usage reporting is always enabled for candidate releases.",
"Use HTTPS for GUI": "Use HTTPS for GUI",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Username/Password has not been set for the GUI authentication. Please consider setting it up.",
"Version": "Version",
"Versions": "Versions",
"Versions Path": "Versions Path",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.",
"Waiting to Clean": "Waiting to Clean",
"Waiting to Scan": "Waiting to Scan",
"Waiting to Sync": "Waiting to Sync",
"Warning": "Warning",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Warning, this path is a parent directory of an existing folder \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Warning, this path is a parent directory of an existing folder \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Warning, this path is a subdirectory of an existing folder \"{{otherFolder}}\".",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Warning, this path is a subdirectory of an existing folder \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Warning: If you are using an external watcher like {{syncthingInotify}}, you should make sure it is deactivated.",
"Watch for Changes": "Watch for Changes",
"Watching for Changes": "Watching for Changes",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "When adding a new device, keep in mind that this device must be added on the other side too.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.",
"Yes": "Yes",
"You can also select one of these nearby devices:": "You can also select one of these nearby devices:",
"You can change your choice at any time in the Settings dialog.": "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 can read more about the two release channels at the link below.",
"You have no ignored devices.": "You have no ignored devices.",
"You have no ignored folders.": "You have no ignored folders.",
"You have unsaved changes. Do you really want to discard them?": "You have unsaved changes. Do you really want to discard them?",
"You must keep at least one version.": "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.",
"days": "days",
"directories": "directories",
"files": "files",
"full documentation": "full documentation",
"items": "items",
"seconds": "seconds",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} wants to share folder \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} wants to share folder \"{{folderlabel}}\" ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} might reintroduce this device."
}

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