Compare commits

...

626 Commits

Author SHA1 Message Date
Jakob Borg
fdde05cf12 build: Build and publish Docker images for relay and discovery server (fixes #8691, fixes #8960)
This adds builds for the discovery and relay servers in the same manner
as Syncthing, so that Docker images are kept up to date with releases.

Inspired by and closes #8834.

Co-authored-by: Migelo <miha@filetki.si>
2023-07-03 11:51:12 +02:00
Syncthing Release Automation
89fc69249b gui, man, authors: Update docs, translations, and contributors 2023-06-26 03:47:58 +00:00
Jakob Borg
d421d66a3f build: Docker images should have auto upgrade disabled... 2023-06-22 14:38:34 +02:00
guangwu
27aba3567b all: Minor staticcheck fixes (#8939) 2023-06-19 06:50:53 +00:00
Syncthing Release Automation
5532532db9 gui, man, authors: Update docs, translations, and contributors 2023-06-19 03:46:01 +00:00
Felix
c369f8abb2 gui: Have static link to favicon, for bookmarks etc (fixes #7638) (#8850) 2023-06-14 09:59:56 +02:00
Jakob Borg
9e52f6cf2f build: Update some dependencies 2023-06-14 09:43:45 +02:00
Jakob Borg
d22a38d947 build: Make sure we get the latest matching Go version
Also, disable caching in setup-go when we do manual cache setup with a
better cache key. It became default-true in the latest action version.
2023-06-14 09:37:59 +02:00
Jakob Borg
439fa6c848 build: Multi arch Docker images with GitHub actions (ref #8834)
This builds and publishes our Docker images from GitHub.
2023-06-14 09:28:04 +02:00
Jakob Borg
6b475bdb78 lib/config, gui: Disallow some options in combination with "untrusted" (fixes #8920) (#8921)
This prevents combining untrusted with introducer and auto-accept, and
also verifies that folders shared with untrusted devices have passwords
at config loading time.

Co-authored-by: Simon Frei <freisim93@gmail.com>
2023-06-14 09:24:31 +02:00
Syncthing Release Automation
7d56fba321 gui, man, authors: Update docs, translations, and contributors 2023-06-12 03:45:39 +00:00
Simon Frei
bf6ffbbd67 Don't add empty device to config on init (#8933)
We usually want to ensure that our own device is present. However if the
given device ID is the empty ID, we shouldn't do that. This is a
legimate (though way too non-obvious) use-case when opening the config
without knowing/caring about the device ID.
2023-06-10 20:33:39 +00:00
Jakob Borg
a972811f54 build: Push release files to cloud storage 2023-06-06 17:53:05 +02:00
Jakob Borg
88da67d7c3 build: Generate .asc files for release packages (fixes #8897) 2023-06-06 13:58:44 +02:00
Jakob Borg
1f07e05470 build: Properly build all Debian archs (fixes #8898) 2023-06-06 12:52:30 +02:00
Jakob Borg
5cab08a36a Merge branch 'release'
* release:
  gui: Avoid code generating HTML (#8923)
  gui: Remove HTML support in tooltips
2023-06-06 09:09:30 +02:00
Jakob Borg
73c52eafb6 gui: Avoid code generating HTML (#8923) 2023-06-06 09:06:51 +02:00
Jakob Borg
be5961f59b gui: Remove HTML support in tooltips 2023-06-06 09:06:36 +02:00
Jakob Borg
4e2bb58e2d gui: Avoid code generating HTML (#8923) 2023-06-05 13:16:02 +02:00
Jakob Borg
ae176ea9cd build: Tests should run with Go 1.20 on Windows (#8924)
Tests should run with Go 1.20 on Windows
2023-06-05 10:19:47 +02:00
Syncthing Release Automation
2b17db8aa3 gui, man, authors: Update docs, translations, and contributors 2023-06-05 03:45:37 +00:00
Jakob Borg
81a4b22d43 lib/model: Improve test for unignored parent directories (#8926) 2023-06-04 15:32:03 +02:00
Jakob Borg
f7da96fb82 build: Update dependencies (#8925)
The easy ones, there is also a quic-go update but it requires API
refactoring.
2023-06-04 15:31:20 +02:00
Jakob Borg
f5e5af391a gui: Remove HTML support in tooltips 2023-06-03 09:58:08 +02:00
Jakob Borg
5a3ac86c3f cmd/syncthing: Use correct binary when restarting monitor (#8919) 2023-06-02 07:54:31 +02:00
dependabot[bot]
3d78ff9f68 build(deps): bump github.com/minio/sha256-simd from 1.0.0 to 1.0.1 (#8916)
Bumps [github.com/minio/sha256-simd](https://github.com/minio/sha256-simd) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/minio/sha256-simd/releases)
- [Commits](https://github.com/minio/sha256-simd/compare/v1.0.0...v1.0.1)

---
updated-dependencies:
- dependency-name: github.com/minio/sha256-simd
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-01 12:16:46 +02:00
Jakob Borg
f3127a66ee build: Increase concurrency, add "basic checks" gatekeeper 2023-06-01 12:15:31 +02:00
Syncthing Release Automation
90b4711ad2 gui, man, authors: Update docs, translations, and contributors 2023-05-29 03:45:27 +00:00
Syncthing Release Automation
716b42103a gui, man, authors: Update docs, translations, and contributors 2023-05-22 03:45:33 +00:00
Anthony Goeckner
405cdedcd3 lib/model: Set platform data for new folders w/ ignorePerms (ref #8883) (#8907)
* Platform data (ownership, xattrs, etc.) is now set correctly for newly-received folders, even if the received folder has the NoPermissions flag.

* Call setPlatformData on receivers that have ignorePerms set to true.
2023-05-17 09:06:50 +02:00
Syncthing Release Automation
0b3a101ccd gui, man, authors: Update docs, translations, and contributors 2023-05-15 03:45:55 +00:00
Eng Zer Jun
089320aadc lib: replace Readdir(-1) with os.ReadDir (#8901) 2023-05-11 15:35:52 +00:00
Will Rouesnel
b2fb2ef276 lib/api: Allow BindDN to exclude any username formatting (fixes #8899) (#8900)
This allows a syncthing instance to be locked to exactly 1 user without
needing search capability on the LDAP instance.
2023-05-10 07:52:02 +02:00
Jakob Borg
e136d11dce build: Attempt cross compilation for ~all targets, allow it to fail 2023-05-09 10:01:57 +00:00
Ross Smith II
3adfe2f91f lib/fs: Fix root path handling for Windows (fixes #8778)
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2023-05-09 10:01:57 +00:00
Jakob Borg
1103a27337 all: Grand test refactor (fixes #8779, fixes #8799)
This fixes various test issues with Go 1.20.

- Most tests rewritten to use fakefs where possible
- Some tests that were already skipped, or dubious (invasive,
  unmaintainable, unclear what they even tested) have been removed
- Some actual code rewritten to better support testing in fakefs

Co-authored-by: Eric P <eric@kastelo.net>
2023-05-09 10:01:57 +00:00
Alexander Seiler
ddce692f72 all: Correct various typos (#8870) 2023-05-09 08:54:02 +02:00
Syncthing Release Automation
66faea7712 gui, man, authors: Update docs, translations, and contributors 2023-05-08 03:45:35 +00:00
Anthony Goeckner
7e31ec5417 lib/model: Set platform data, incl. copying ownership, for new folders w/ NoPermissions flag (#8883)
Platform data (ownership, xattrs, etc.) is now set correctly for newly-received folders, even if the received folder has the NoPermissions flag.
2023-05-02 11:11:39 +02:00
André Colomb
a4fa764b7d gui: Add Thai (th) translation template. (#8887) 2023-05-02 06:38:29 +00:00
Jakob Borg
7226b8456b build: Produce nightly release builds 2023-05-01 09:42:44 +02:00
Syncthing Release Automation
dae5eab787 gui, man, authors: Update docs, translations, and contributors 2023-05-01 03:45:35 +00:00
K.B.Dharun Krishna
f38e9628a1 build: Bump actions version; fix Node 12 deprecation warning (#8881) 2023-04-29 15:21:46 +02:00
Jakob Borg
43e3b12e29 build: Build Debian packages 2023-04-28 13:22:25 +02:00
Jakob Borg
aa01ff5d50 build: Sign for upgrades 2023-04-28 13:03:25 +02:00
Jakob Borg
63503e0c98 build: Notarize mac builds 2023-04-28 13:03:25 +02:00
dependabot[bot]
947dd0db09 build(deps): bump github.com/quic-go/quic-go from 0.33.0 to 0.34.0 (#8877)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.33.0 to 0.34.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-24 19:04:27 +02:00
Syncthing Release Automation
218b6e5193 gui, man, authors: Update docs, translations, and contributors 2023-04-24 03:45:39 +00:00
Eric P
9f131eee6b lib/ignore: Properly handle non-existing included ignore-files (fixes #8764) (#8874)
In the sequence of loading ignores, the error File Does Not Exist is not being considered a fatal  error, since the .stignore file is allowed to not exist. However, included ignore files also tossed that same error in case those do not exist while in those cases it's considered an error and it should lead to the folder stopping. Changing the error when opening an included ignore file to something other than the regular does fix this issue, as in it now works again as described in the Documentation.
2023-04-20 15:00:55 +02:00
Jakob Borg
09efe03e1d lib/connections: Avoid using nil lanChecker
Otherwise it panics when someone calls Priority() on it...
2023-04-19 10:42:25 +02:00
Syncthing Release Automation
0f87607cd5 gui, man, authors: Update docs, translations, and contributors 2023-04-17 03:45:33 +00:00
Jakob Borg
9b660c1959 lib/config, lib/connections: Configurable protocol priority (ref #8626) (#8868)
This makes the various protocol priorities configurable among the other
options. With this, it's possible to prefer QUIC over TCP for WAN
connections, for example. Both sides need to be similarly configured for
this to work properly.

The default priority order remains the same as previously (TCP, QUIC,
Relay, with LAN better than WAN).

To make this happen I made each dialer & listener more priority aware,
and moved the check for whether a connection is LAN or not into the
dialer / listener -- this is the new "lanChecker" type that's passed
around.
2023-04-16 14:54:28 +02:00
Simon Frei
c867a5f5b3 build: Upgrade recli (fixes #8503) (#8871) 2023-04-14 18:46:50 +02:00
Jakob Borg
1886b47031 build: Update dependencies (#8869) 2023-04-11 20:01:42 +02:00
Jakob Borg
f59ffc8ddd lib/model: Improve path generation for auto accepted folders (fixes #8859) (#8860)
- Make sure we don't try to use empty last path components
- Create the directory to "reserve" it once we've decided to use it
2023-04-11 13:07:22 +02:00
Evgeny Kuznetsov
61444960bc docs: fix typo (#8857) 2023-04-10 10:30:11 +00:00
Syncthing Release Automation
30bb8f2116 gui, man, authors: Update docs, translations, and contributors 2023-04-10 03:45:37 +00:00
Jakob Borg
4a8c691aef lib/syncthing: Handle successful global migration (fixes #8851) (#8852)
lib/syncthing: Handle successfull global migration (fixes #8851)
2023-04-05 15:25:55 +02:00
Syncthing Release Automation
e8dafb979c gui, man, authors: Update docs, translations, and contributors 2023-04-03 03:45:47 +00:00
Simon Frei
3a41d4afa5 lib/model: Set enc. trailer size on pull (ref #8563, #8556) (#8839)
In the original fix in #8563 I simply forgot this. Which meant #8556
wasn't actually fixed, as the trialer size would have been 0 (default),
and thus we would have still sent the inflated size to encrypted peers.
2023-03-28 22:47:24 +02:00
Simon Frei
6a66aee489 lib/model: Fix file size inconsistency due to enc. trailer (#8840)
lib/model: Fix file size inconsisency due to enc. trailer

Fixes a regression due to PR #8563, while arguable the bug was actually
introduced in a much older PR #7155, but didn't have any bad effects so
far:
We account for the encryption trailer in the db updater routine,
calculating the file-info size there. However there's no guarantee that
the file-info at this point is still the exact same as when it was
written. It was before, but isn't anymore since introducing the new
EncryptedTrailerSize field.
Fix: Adjust the size in the info at the same place where the trailer is
written, i.e. we definitely have the actual size on disk.
2023-03-28 22:02:59 +02:00
Syncthing Release Automation
51e85d5162 gui, man, authors: Update docs, translations, and contributors 2023-03-27 03:45:37 +00:00
Jakob Borg
b49f535834 cmd/stdiscorv: Fix database test (fixes #8828)
The problem was that a statistics/cleanup run is triggered when the
database started and runs concurrently with the test. That cleanup run
removes old entries without valid addresses, and one of the test objects
matched this. The test object would thus randomly be removed in the
middle of the test, causing a failure. This fixes it so the object looks
recent when the cleaner-upper looks, and also uses a RAM database
(faster).
2023-03-24 09:15:12 +01:00
Jakob Borg
34b312b85b lib/ur: Fix custom releases URL comparison 2023-03-24 09:15:12 +01:00
André Colomb
be3751ab5f gui: Remove untranslated strings from JSON files (#8836)
* gui: Import latest state from Weblate.

Downloaded 2023-03-23 at 20:38:53.

* gui: Remove untranslated strings from JSON files.

The GUI code will fall back to the English string translation anyway,
so keeping it identical inside the other language files does not
help.  It makes the filter handling on Weblate easier though.

Current state retreived with these filter settings:

    state:>=translated OR (state:needs-editing AND NOT check:same)
2023-03-23 21:12:31 +01:00
Dimitri Papadopoulos Orfanos
526e21ae26 all: Fix typos found by codespell (#8833) 2023-03-21 08:07:28 +01:00
Jakob Borg
bc371eacf6 gui: Hide download progress legend when download progress is disabled 2023-03-20 15:34:18 +01:00
Syncthing Release Automation
5caf9bfc18 gui, man, authors: Update docs, translations, and contributors 2023-03-20 03:45:38 +00:00
Jakob Borg
f378e63147 lib/protocol: Handle encrypted requests without encrypted hash (fixes #8277) (#8827)
The layout of the request differs based on whether it comes from an
untrusted device or a trusted device with encrypted enabled. Handle
both.

Closes #8819.
2023-03-18 10:22:18 +01:00
dependabot[bot]
fb89898462 build(deps): bump github.com/hashicorp/golang-lru/v2 from 2.0.1 to 2.0.2 (#8826)
Bumps [github.com/hashicorp/golang-lru/v2](https://github.com/hashicorp/golang-lru) from 2.0.1 to 2.0.2.
- [Release notes](https://github.com/hashicorp/golang-lru/releases)
- [Commits](https://github.com/hashicorp/golang-lru/compare/v2.0.1...v2.0.2)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/golang-lru/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-18 10:17:16 +01:00
tomasz1986
358cf25cff lib/config: Allow sub-second watcher delay (fixes #7859) (#7864)
Allow the watcher delay to take fractional values, effectively allowing
for much shorter delays. The minimum value is limited at 0.01, which
effectively translates to 10ms. This is required in order to guarantee
that there is still enough time to aggregate multiple single change
events.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-03-18 08:50:38 +01:00
Syncthing Release Automation
59de7048bd gui, man, authors: Update docs, translations, and contributors 2023-03-13 03:45:45 +00:00
Jakob Borg
466b56ded1 lib/protocol: Cache expensive key operations (fixes #8599) (#8820)
This adds a cache to the expensive key generation operations. It's fixes
size LRU/MRU stuff to keep memory usage bounded under absurd conditions.

Also closes #8600.
2023-03-12 20:06:59 +01:00
André Colomb
3ffe859fe8 gui: Add Persian (fa) translation template (#8822)
gui: Add Persian (fa) translation template.

Based on user request from Weblate, user @a-kbd.
2023-03-10 16:27:48 +01:00
Simon Frei
da72df6ffc lib: Correctly handle encrypted trailer size (fixes #8556) (#8563) 2023-03-10 14:14:14 +01:00
tomasz1986
b53c1b9a04 gui: Disable Restore Versions filters when no versioned files exist (fixes #5408) (#8539)
Currently, the name and date filters in the Restore Versions modal are
always enabled, even if there are no versioned files present. With this
change, they are enabled only when there are no errors and versioned
files actually exist.

In addition to disabling the filters, also completely skip date picker
generation, as it serves no function while still displaying a non-sense
date range, which starts today and ends in the past.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-03-10 13:41:15 +01:00
dependabot[bot]
b00976781c build(deps): bump github.com/chmduquesne/rollinghash from 0.0.0-20180912150627-a60f8e7142b5 to 4.0.0+incompatible (#8804)
build(deps): bump github.com/chmduquesne/rollinghash

Bumps [github.com/chmduquesne/rollinghash](https://github.com/chmduquesne/rollinghash) from 0.0.0-20180912150627-a60f8e7142b5 to 4.0.0+incompatible.
- [Release notes](https://github.com/chmduquesne/rollinghash/releases)
- [Commits](https://github.com/chmduquesne/rollinghash/commits/v4.0.0)

---
updated-dependencies:
- dependency-name: github.com/chmduquesne/rollinghash
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-10 13:36:25 +01:00
Jakob Borg
58f9dcca31 build: Update dependencies (#8821) 2023-03-10 13:04:13 +01:00
Jakob Borg
ab8e6a82ab lib/api: Expose blocksHash in file info (#8810)
This adds the BlocksHash field from the FileInfo to our API output. It
can be useful for debugging, or for external tools. I'm intentionally
leaving it as an opaque base64 string because no meaning should be
derived from it: it's just a string.
2023-03-06 15:37:15 +01:00
Syncthing Release Automation
3cdcb7dd72 gui, man, authors: Update docs, translations, and contributors 2023-03-06 03:45:45 +00:00
entity0xfe
4558eef446 lib/discover: Don't leak relay-tokens to discovery (#8762)
Use an allowlist to send only the `id` query param to the discovery server.
2023-03-04 12:16:57 +01:00
Syncthing Release Automation
8bbf2ba9ac gui, man, authors: Update docs, translations, and contributors 2023-02-27 03:45:16 +00:00
André Colomb
49c56b8caa gui: Add Croatian (hr) translation template (#8801) 2023-02-24 17:54:30 +01:00
dependabot[bot]
0b8aa7974b build(deps): bump github.com/quic-go/quic-go from 0.32.0 to 0.33.0 (#8800)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.32.0 to 0.33.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-22 13:01:08 +01:00
Jakob Borg
cbec697e5f cmd/stupgrades: Cache should apply to HEAD as well as GET 2023-02-22 12:22:52 +01:00
Jakob Borg
8991ecf444 build: Add more GitHub Actions 2023-02-22 10:56:55 +01:00
tomasz1986
17887ce0b1 gui: Remove non-existent customicons.css file reference (fixes #8797) (#8798)
The reference comes from fd0a6225aa,
but the file itself was removed in the process of working on the pull
request, yet the reference to it was still left in the index.html.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-02-21 19:05:15 +01:00
Andreas Sommer
2f88dafa56 Only fail after chmod error if permissions differ (e.g. on config file) (#8771) 2023-02-20 15:41:10 +01:00
Syncthing Release Automation
2321d0db08 gui, man, authors: Update docs, translations, and contributors 2023-02-20 03:45:34 +00:00
Jakob Borg
7047e00d1e build: Use Go 1.19.6 for Windows 2023-02-15 13:20:47 +01:00
Jakob Borg
a8533b269d build: Update dependencies 2023-02-14 19:08:25 +01:00
Syncthing Release Automation
ee30647bf7 gui, man, authors: Update docs, translations, and contributors 2023-02-13 03:48:08 +00:00
André Colomb
750accb25f gui: Remove duplicate Spanish (Spain) translation (fixes #8781) (#8782)
gui: Remove duplicate Spanish (Spain) translation.

Currently not among the set of "valid" (sufficiently complete)
languages and no longer synced with the tranlation platform, Weblate.
2023-02-09 10:10:40 +01:00
Eric P
0530f0edbf gui: Add xattr filter editor (fixes #8660) (#8734) 2023-02-09 09:14:36 +01:00
André Colomb
784129e1cf gui: Switch to Weblate for translations (#8777)
* Normalize EOL before EOF.

* Import current Transifex state, only translated.

Skip duplicated and completely empty languages.

* Re-add untranslated strings to JSON files.

These are now treated correctly as untranslated, but present with the
original (English) translation key.

* Update valid language codes and names.

* Refer to Weblate instead of Transifex for translations.

* lang-es: Copy untranslated strings from es-ES.

* Integrate translation changes from Weblate.

Translated using Weblate (Polish)

Currently translated at 100.0% (512 of 512 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/pl/

Translated using Weblate (Danish)

Currently translated at 98.6% (505 of 512 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/da/

Translated using Weblate (Lithuanian)

Currently translated at 85.4% (441 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/lt/

Translated using Weblate (French)

Currently translated at 100.0% (516 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/fr/

Translated using Weblate (Danish)

Currently translated at 98.6% (509 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/da/

Translated using Weblate (Spanish)

Currently translated at 100.0% (516 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/es/

* translation update uses weblate

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2023-02-07 12:22:08 +01:00
greatroar
38f2b34d29 all: Use new Go 1.19 atomic types (#8772) 2023-02-07 12:07:34 +01:00
Syncthing Release Automation
882b711958 gui, man, authors: Update docs, translations, and contributors 2023-02-06 03:45:18 +00:00
Jakob Borg
99595ce3d9 build: Update quic-go and pfilter for Go 1.20 (fixes #8768) (#8769) 2023-02-02 22:00:50 +01:00
Jakob Borg
d5e4ef249f Add forgotten copyright notices 2023-02-01 22:59:41 +01:00
Jakob Borg
65cfefaa3c cmd, docker: Updates for infrastructure
These are some changes to the relay pool server, upgrade server, and
crash receiver to run under Kubernetes. It's been in production for a
while.
2023-01-31 11:17:52 +01:00
Jakob Borg
a6c2a5a0ce cmd/ursrv: The driver import is important, though 2023-01-31 09:57:16 +01:00
Jakob Borg
a5b6199507 cmd/ursrv: Remove old, unused migration code 2023-01-31 09:12:48 +01:00
Jakob Borg
966e9f9a68 cmd/ursrv: Harmonize timespan of charts 2023-01-31 09:11:15 +01:00
Jakob Borg
b10e11abb7 cmd/ursrv: Remove broken and unsustainable join/leave chart 2023-01-31 09:10:52 +01:00
Jakob Borg
5a50de1154 cmd/ursrv: Fix broken block transfer chart 2023-01-31 09:09:36 +01:00
Syncthing Release Automation
dc6d695c00 gui, man, authors: Update docs, translations, and contributors 2023-01-30 03:45:28 +00:00
Vik
b120278b3a gui: Fix broken link to Transifex in lang/README.txt (#8761)
Updated URL
2023-01-29 21:52:09 +01:00
Syncthing Release Automation
c25f5b40d9 gui, man, authors: Update docs, translations, and contributors 2023-01-23 03:45:17 +00:00
Jakob Borg
abdac2caa2 Handle relay connect timeout (fixes #8749) (#8755)
This makes sure the service manager doesn't interpret timeout errors, or any other error, as a signal to stop the service instead of restarting it.

I added it directly to our service utility function, as it may help catch other instances of the same problem... We would typically want timeouts etc to be a retryable error, unless it is the top level context that has timed out and we check for that specifically.
2023-01-19 11:15:18 +01:00
Syncthing Release Automation
5f1e27bb7f gui, man, authors: Update docs, translations, and contributors 2023-01-16 03:48:02 +00:00
André Colomb
a85b4ab263 build: Go 1.19.5 2023-01-12 07:30:17 +04:00
Syncthing Release Automation
cf962a4fe8 gui, man, authors: Update docs, translations, and contributors 2023-01-09 03:45:24 +00:00
André Colomb
39c0bfa05a script: Add weblatedl.go for downloading updated translations (#8723)
Based on the transifexdl.go script.  Map Weblate language codes to the
existing ones during import.  Do not delete incomplete languages from
repo.
2023-01-08 15:25:00 +01:00
tomasz1986
458d6cff2a gui: Allow to translate action and type in Recent Changes modal (#8548)
Currently, action and type are both displayed only in English. This
commit makes it possible to translate both of them.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-01-05 14:33:03 +01:00
Syncthing Release Automation
ded881c372 gui, man, authors: Update docs, translations, and contributors 2023-01-02 03:45:30 +00:00
tomasz1986
fb4209e382 gui: Fix undefined lastSeenDays error in disconnected-inactive status check (ref #8530) (#8730)
The current code assumes that lastSeenDays is always set which is not
the case when device reports its lastSeen as equal to the Unix epoch.
Thus, make sure that lastSeenDays is set before proceeding with the
disconnected-inactive status check to avoid JS errors in the browser.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-12-26 12:59:04 +01:00
Syncthing Release Automation
473ca68dc4 gui, man, authors: Update docs, translations, and contributors 2022-12-26 03:45:20 +00:00
Jakob Borg
c4e69cd66c gui, api: Indicate running under container (#8728)
This adds a word to the version string when running containerized. The
purpose is mostly to facilitate troubleshooting via screenshot by
"leaking" this rather important aspect of the setup. Additionally, the
version row gets "no-overflow-ellipsis" treatment so that the whole
thing is actually visible in the GUI and the (now useless) tooltip is
removed. In production releases this won't make a difference as the
whole thing will typically fit, but in odd setups it provides more info
up front.
2022-12-25 08:08:41 +01:00
Simon Frei
634a3d0e3b lib/fs: Use io/fs errors as recommended in std lib (#8726) 2022-12-21 23:42:22 +01:00
Jakob Borg
09f4d865ae build: Handle co-authors (ref #3744) (#8708)
The authorship script didn't pick up people who were only ever
"co-authors" of a commit, such as when they wrote stuff which was later
included in a PR by someone else, or added code during code review.

This modified the script to look closer in the commit bodies for
"Co-authored-by:"-lines and adds those found to the set of authors.
2022-12-21 22:02:44 +01:00
Jakob Borg
ad0044fec8 lib/fs: Watching is unsupported on android/amd64 (fixes #8709) (#8710) 2022-12-21 22:01:00 +01:00
Simon Frei
d157d12037 lib/model: Only log at info level if setting change time fails (#8725) 2022-12-21 21:58:35 +01:00
Aleksey Vasenev
f9d68474ac lib/model: Don't lower rescan interval from default on auto accepted enc folder (fixes #8572) (#8573) 2022-12-21 19:52:22 +01:00
Syncthing Release Automation
f0126fe1ab gui, man, authors: Update docs, translations, and contributors 2022-12-19 03:45:31 +00:00
André Colomb
940536a964 gui: Remove unmaintained language variant nl-BE (#8722)
gui: Remove unmaintained language variant nl-BE.

This has long been removed from Transifex and from the valid-langs.js
list, but somehow the translation file stayed in the repo.  There is
already a generic Dutch variant (nl) available as replacement.
2022-12-18 08:30:26 +01:00
André Colomb
f378c4f191 gui, script: Fix indentation in lang-en.json to match others (#8721)
* Indent lang-en.json with four spaces as all other languages.

* Regenerate lang-en.json.

Removes two no longer used strings.
2022-12-18 08:29:59 +01:00
James O'Beirne
358d2143e2 docker: Ensure entrypoint is executable (#8719)
On systems with safe umasks (`umask 077`), the entrypoint as copied from
the host may not be executable by other users. Ensure that it is set to
be within the Dockerfile.
2022-12-16 08:16:22 +01:00
Jakob Borg
622ade40ad Go 1.19.4 2022-12-13 14:03:06 +01:00
Jakob Borg
323405ea07 Update dependencies (#8717) 2022-12-12 17:20:33 +01:00
Syncthing Release Automation
88c226ef87 gui, man, authors: Update docs, translations, and contributors 2022-12-12 03:48:00 +00:00
Jakob Borg
d4b668caac docker: Update healthcheck cmd for buildx (ref #8640) (#8706) 2022-12-06 21:23:49 +01:00
Aleksey Vasenev
05738001ac lib/model: Fixed adding empty items to device list (fixes #8646) (#8647) 2022-12-06 21:22:35 +01:00
Jakob Borg
d40d9d5698 build: Update dependencies (#8704) 2022-12-06 11:39:43 +01:00
Syncthing Release Automation
648c71cbd1 gui, man, authors: Update docs, translations, and contributors 2022-12-05 03:45:25 +00:00
André Colomb
ab0eb909a2 gui, lib/connections: Let the backend decide whether connection is local (fixes #8686) (#8694)
* lib/connections: Cache isLAN decision for later external access.

The check whether a remote device's address is on a local network
currently happens when handling the Hello message, to configure the
limiters.  Save the result to the ConnectionInfo and pass it out as
part of the model's ConnectionInfo struct in ConnectionStats().

* gui: Use provided connection attribute to distinguish LAN / WAN.

Replace the dumb IP address check which didn't catch common cases and
actually could contradict what the backend decided.  That could have
been confusing if the GUI says WAN, but the limiter is not actually
applied because the backend thinks it's a LAN.

Add strings for QUIC and relay connections to also differentiate
between LAN and WAN.

* gui: Redefine reception level icons for all connection types.

Move the mapping to the JS code, as it is much easier to handle
multiple switch cases by fall-through there.

QUIC is regarded no less than TCP anymore.  LAN and WAN make the
difference between levels 4 / 3 and 2 / 1:

{TCP,QUIC} LAN --> {TCP,QUIC} WAN --> Relay LAN --> Relay WAN -->
Disconnected.
2022-11-28 09:28:33 +01:00
Syncthing Release Automation
d16c0652f7 gui, man, authors: Update docs, translations, and contributors 2022-11-28 03:48:37 +00:00
Jakob Borg
0dae06deb3 Set build metadata correctly in Windows build (#8692)
Without this, we tag the build as made by some random user account on some random host name which is not useful.

(And minor bug in the cache key which has no effect on the build itself.)
2022-11-25 13:52:48 +01:00
greatroar
663106ef6e lib/fs: Optimize WindowsInvalidFilename (#8687)
Replaced strings.Split with the new strings.Cut, which doesn't allocate.

name                           old time/op    new time/op    delta
WindowsInvalidFilenameValid-8     154ns ± 2%      89ns ± 0%   -42.09%  (p=0.000 n=10+9)
WindowsInvalidFilenameNUL-8       124ns ± 2%     124ns ± 1%      ~     (p=0.371 n=8+10)

name                           old alloc/op   new alloc/op   delta
WindowsInvalidFilenameValid-8     16.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8       19.0B ± 0%      3.0B ± 0%   -84.21%  (p=0.000 n=10+10)

name                           old allocs/op  new allocs/op  delta
WindowsInvalidFilenameValid-8      1.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8        2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.000 n=10+10)
2022-11-21 12:58:00 +01:00
Syncthing Release Automation
0b2b8baf19 gui, man, authors: Update docs, translations, and contributors 2022-11-21 03:57:01 +00:00
Jakob Borg
24275b4584 cmd/syncthing: Use main logger in generate subcommand (fixes #8682) (#8685)
We had some unholy mix of our own logger and the stdlib logger, probably
because for historical reasons we wanted the device ID to stdout and the
rest to stderr? But that's not the case any more, and the mix of formats
is weird. Ideally I think the generate command should be silent and just
print the device ID and nothing else, but that's tricky to accomplish
since we have other methods do logging on their own. Hence this just
harmonizes it so that we at least use the same logger with the same
format and target...
2022-11-20 13:48:08 +01:00
Jakob Borg
2a8362d7af build: Update all dependencies (fixes #8679) (#8680)
Minor API change for the LRU cache in casefs
2022-11-17 21:26:10 +01:00
Syncthing Release Automation
8cca9dfef5 gui, man, authors: Update docs, translations, and contributors 2022-11-14 04:02:37 +00:00
Jakob Borg
6aa04118a6 lib/model: Correctly set xattrs on temp files (fixes #8667) (#8670) 2022-11-11 11:49:15 +01:00
Boris Rybalkin
1b32e9f858 gui: Automatically dismiss authentication reminder when in LDAP mode (fixes #8661) (#8663) 2022-11-10 08:14:47 +01:00
Jakob Borg
a523fef78e lib/model: Correctly handle xattrs on directories (fixes #8657) (#8658) 2022-11-09 06:54:04 +01:00
Simon Frei
ce2a68622c lib/protocol: Ignore inode time when xattr&ownership is ignored (fixes #8654) (#8655)
lib/protocol: Ignore inode time when both xattr and ownership is ignored (fixes #8654)
2022-11-08 08:36:41 +01:00
Jakob Borg
a29605750d lib/fs: Try to remove read only Windows files (fixes #3744) (#8650)
This happens when folders contain a custom icon.

Co-authored-by: Alexandre Alves <alexandrealvesdb.contact@gmail.com>
2022-11-07 21:33:17 +01:00
tomasz1986
5e384c9185 gui: Add copy to clipboard, share by email, and share by SMS buttons to device IDs (fixes #2771, ref #3868) (#7984)
gui: Add copy to clipboard, share by email, and share by SMS buttons to device IDs (fixes #2771, ref #3868)

Add buttons to allow for simpler sharing device IDs with others. The
first one copies the ID to clipboard (trying to use three different
methods, depending on the browser). The second one triggers a mailto
link with prefilled subject and body. The third one triggers an sms link
with prefilled body. The short description of Syncthing included in the
latter part of the body is a direct copy from the description at the
official website https://syncthing.net.

Issue #3868 is referred here, because the copy to clipboard button
offers an alternative method for IE11 users to actually be able to copy
device IDs without having to select it manually (which doesn't work).

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-11-07 20:11:12 +01:00
Syncthing Release Automation
a1cc293c21 gui, man, authors: Update docs, translations, and contributors 2022-11-07 04:03:05 +00:00
Jakob Borg
452daad14b build: Add GitHub actions build for Windows (#8627)
This is sort of a proof of concept, but since our current Windows
builder is down this might solve the problem. It includes a change for
easier code signing (taking the certificate in a secret/env var rather
than existing already on disk), but otherwise mirrors precisely what we
already do in the build server.
2022-11-05 15:40:53 +01:00
tomasz1986
fbdaa265d3 gui: Fix connection type icon width (fixes #8592) (#8644)
The connection type icon comes from Bootstrap. As such, it does not
follow the same dimensions as the other GUI icons, which come from Fork
Awesome. Thus, add left and right margin to make its width roughly the
same as the other GUI icons, which fixes its alignment in relation to
text.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-11-04 21:12:18 +01:00
tomasz1986
46b375e8cc gui: Adjust connection type icon size scaling and alignment (#8645) 2022-11-04 19:41:27 +01:00
bt90
1e9bf17512 docker: Use healthcheck endpoint (#8640)
Query healthcheck endpoint
2022-11-03 20:43:32 +01:00
Jakob Borg
413c8cf4ea lib/connections: Use adaptive write size for rate limited connections (fixes #8630) (#8631) 2022-11-03 15:44:46 +01:00
tomasz1986
d8296ce111 gui: Mark devices that haven't connected for a long time (fixes #7703) (#8530)
Currently, a disconnected device is marked as "Disconnected" without any
consideration whether the state is just temporary or rather it has been
like that for a long time, potentially requiring user intervention.

This commit adds a new state called "Disconnected (Inactive)" which is
shown for devices that have been disconnected for longer than a week. It
also changes the "Last seen" information, so that "Never" is used only
when the device hasn't connected at all, and the exact date is displayed
otherwise.

Additionally, when the date is older than 1 week, a note about that is
displayed below the date. Furthermore, when the date becomes older than
1 month, the note text colour changes to orange, and when it exceeds 1
year, the colour changes again to red. This is done to provide the user
with a visual clue that something may potentially be wrong and requires
a manual fix.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
Co-authored-by: André Colomb <src@andre.colomb.de>
2022-11-03 12:09:28 +01:00
Aleksey Vasenev
06a1635d1d gui: Fix rescan interval when add encrypted folder with watch for changes enabled (fixes #8570) (#8571) 2022-11-03 12:07:36 +01:00
tomasz1986
36221b70ac gui: Always show Out of Sync Items for remote devices (#8632)
Right now, the Out of Sync Items list for a specific remote device is
available only when the device is online and currently synchronising.
However, the list itself is being created by Syncthing all the time, so
there is no need to hide it from the user even when the remote device is
offline or paused. This way they can always easily check which files
exactly have not been synchronised yet.

In addition, the Out of Sync Items entry already includes file size next
to it, so there is no need to display it again next to the Sync Status
entry. Thus, remove out-of-sync file size from Sync Status, leaving only
percentage next to it.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-11-03 12:06:31 +01:00
Jakob Borg
bf1e418e4a lib/fs: Let xattr test avoid non-test attributes (fixes #8601) (#8628)
SELinux for example adds security.* attributes by default that we are
not allowed to touch, which causes the test to fail.
2022-11-03 11:57:30 +01:00
Jakob Borg
922946683d Merge branch 'release'
* release:
  build: Add GitHub actions build for Windows
2022-11-02 09:00:35 +01:00
Jakob Borg
abb921acbc build: Add GitHub actions build for Windows
This is sort of a proof of concept, but since our current Windows
builder is down this might solve the problem. It includes a change for
easier code signing (taking the certificate in a secret/env var rather
than existing already on disk), but otherwise mirrors precisely what we
already do in the build server.
2022-11-02 07:27:53 +01:00
Syncthing Release Automation
816354e66b gui, man, authors: Update docs, translations, and contributors 2022-10-31 04:04:36 +00:00
tomasz1986
8228020ff0 gui: Display folder and device count number (#8615)
In large setups, it is currently impossible to know the exact number of
folders and remote devices without counting them manually, either in the
GUI or in config.xml. Thus, to provide this information to the user, add
a specific number right next to both Folders and Remote Devices headers
in the Web GUI. The numbers are only displayed when two or more folders
or devices are present.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-10-21 16:01:41 +02:00
Syncthing Release Automation
c96f76e1fd gui, man, authors: Update docs, translations, and contributors 2022-10-17 04:34:10 +00:00
Jakob Borg
d3f50637d2 lib/model, lib/protocol: Fix file comparisons (fixes #8594) (#8603) 2022-10-16 17:04:28 +02:00
Jakob Borg
ed588ce335 lib/scanner: More sensible debug output (#8596)
Previous debug input didn't really give enough info to show what was
happening, while it also printed full block lists which are enormously
verbose. Now it consistently prints 1. what it sees on disk, 2. what it
got from CurrentFile (without blocks), 3. the action taken on that file.
2022-10-13 19:32:58 +02:00
tomasz1986
34d91b228d gui: Allow automatic device ID selection on WebKit browsers (ref #8544) (#8597)
Some WebKit browsers select more than needed when using double click to
select device IDs, e.g. new lines and white space. This commit adds a
prefixed version of user-select in CSS in order to add support for those
browsers and allow them to select just device IDs automatically.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-10-10 23:01:37 +02:00
Syncthing Release Automation
fb6a35c98c gui, man, authors: Update docs, translations, and contributors 2022-10-10 04:24:03 +00:00
Jakob Borg
87bf09ea40 lib/protocol: Show inode change time in FileInfo debug string (#8591) 2022-10-08 19:28:10 +02:00
André Colomb
a13bb926b7 gui: Tweak whitespace (#8587) 2022-10-07 08:10:17 +02:00
Eric P
7a402409f1 lib/api: Add /rest/noauth/health health-check (fixes #8430) (#8585) 2022-10-06 21:28:49 +02:00
Eric P
c791dba392 api, gui: Prevent connection issues due to unsupported-upgrade (fixes #8569) (#8586)
There are some situations where an upgrade wouldn't be supported, even though the noUpgrade bool isn't set. So when handling the errors that are caused by this, when attempting an upgrade, it shouldn't lead to some sort of offline-message/restart/warning/etc...

I added some checks on specific errors related to this and return a 501 (Not Implemented) response instead, in case of an "UpgradeUnsupported"-error. Additionally, on the GUI-side, the 501-response is now not to be considered an error to act upon.
2022-10-06 21:27:08 +02:00
Simon Frei
a0c80e030a lib/model: Fix warning log statement (ref #8583) (#8584) 2022-10-05 18:45:37 +02:00
Jakob Borg
b6bb67b142 build: Update dependencies (#8581) 2022-10-04 11:23:41 +02:00
Jakob Borg
1306d86a62 build: Also update Dockerfile.buildx for new package dependency 2022-10-04 08:31:54 +02:00
Jakob Borg
57443804ba Merge branch 'release'
* release:
  docker: Fix handling of PCAP variable (fixes #8567) (#8568)
  lib/fs: Skip xattrs test on EOPNOTSUPP (fixes #8564) (#8565)
2022-10-04 07:57:07 +02:00
Syncthing Release Automation
2839baf0de gui, man, authors: Update docs, translations, and contributors 2022-10-03 04:04:44 +00:00
Jakob Borg
7e848a150b docker: Fix handling of PCAP variable (fixes #8567) (#8568)
This correctly handles the absense of the PCAP environment variable,
which was broken in the previous change.
2022-10-02 08:58:22 +02:00
Simon Frei
81bdde79ea lib/fs: Skip xattrs test on EOPNOTSUPP (fixes #8564) (#8565) 2022-10-02 08:58:19 +02:00
Jakob Borg
a206366d10 docker: Fix handling of PCAP variable (fixes #8567) (#8568)
This correctly handles the absense of the PCAP environment variable,
which was broken in the previous change.
2022-10-02 08:50:27 +02:00
Jakob Borg
1e652de5af cmd/stcrashreceiver: Update to more modern panicparse (#8566) 2022-10-01 21:03:14 +01:00
entity0xfe
ad986f372d cmd/strelaysrv: Add optional auth token (fixes #3987) (#8561)
* implement authentication via token for relaysrv

Make replaysrv check for a token before allowing clients to
join. The token can be set via the replay-uri.

* fix formatting

* key composite literal

* do not error out if auth material is provided but not needed

* remove unused method receiver

* clean up unused parameter in functions

* cleaner token handling, disable joining the pool if token is set.

* Keep backwards compatibility with older clients.

In prior versions of the protocol JoinRelayRequest did not have a
token field. Trying to unmarshal such a request will result in
an error. Return an empty JoinRelayRequest, that is a request
without token, instead.

Co-authored-by: entity0xfe <entity0xfe@my.domain>
2022-10-01 20:41:02 +01:00
Simon Frei
0935886045 lib/fs: Skip xattrs test on EOPNOTSUPP (fixes #8564) (#8565) 2022-10-01 08:48:00 +02:00
Eric P
fd0a6225aa gui: Add connection status icons to Remote Devices (fixes #8244) (#8553) 2022-09-30 18:15:19 +02:00
tomasz1986
b39985483d gui: Filter scope ID out of IPv6 addresses in Remote GUI (fixes #8084) (#8559)
Currently, the link to remote GUI uses device addresses as they are
advertised from the router. Because of this, they may end up having a
scope ID attached to them. The problem is that browsers do not support
such addresses, leaving the user with a non-working URL.

Because of the above, use regex to simply filter out the scope ID from
the address before using it for Remote GUI.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-27 19:57:48 +02:00
Nick Busey
f38df0dadb cmd/syncthing: Fix incorrect cli help text (#8557) 2022-09-26 22:52:33 +01:00
Jakob Borg
361f7ae564 docker: Add env var to control capabilities (#8552)
As it's not simple to run a container under Docker/Kubernetes as
non-root but with additional capabilities, add an internal hack.
2022-09-26 13:39:41 +02:00
Syncthing Release Automation
1cd2f5a91f gui, man, authors: Update docs, translations, and contributors 2022-09-26 04:33:20 +00:00
tomasz1986
dab68cf841 gui: Add size and improve alt text of device QR code image (#8545)
Currently, the QR code image has no size specified in the HTML. This
causes other elements of the modal to jump around when opening it for
the first time and waiting for the QR image to generate. The jumping is
especially noticeable when the GUI is accessed remotely and there is a
delay while loading the elements due to slow connection.

In addition, capitalise "QR" in the alt text. This is necessary for
accessibility reasons, e.g. when using a screen reader, which may read
upper- and lowercase characters differently.

Lastly, allow to translate the alt text itself.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-20 11:46:35 +02:00
dependabot[bot]
d51fe3fb3f build(deps): bump actions/setup-go from 3.2.1 to 3.3.0 (#8518)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3.2.1 to 3.3.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](84cbf80943...268d8c0ca0)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 11:46:19 +02:00
tomasz1986
5baf5fedb5 gui: Replace JS select-on-click with CSS user-select (fixes #3868) (#8544)
Currently, a custom JS script is used to select the whole device ID on
click. However, the current script isn't compatible with all browsers
(and in IE in particular), making it impossible to select the ID in them
at all. Additionally, the same functionality is already available in CSS
with no such drawbacks, as the whole selection process is handled by the
Web browser natively, which is lightweight and does not require custom
code.

Thus, remove the currently used JS script completely, replacing it with
a new CSS class that can be added to an element when required. If the
browser does not support the CSS, the user can still select the element
manually, which makes it safer than the current behaviour that can block
the user from being able to select the element at all.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-20 11:37:34 +02:00
Eric P
3f2742a275 lib/versioner: Fix error in Trashcan restore (fixes: #7965) (#8549)
The restore function of Trash Can ran a rename at the end regardless of whether there was anything to rename. In this case, when the file-to-be-restored did not exist in the destination folder, this resulted in an error. I added a simple check, keeping track of whether the file existed prior to restoring it in the destination folder and depending on this value it will now return nil after the restoration to prevent the renaming function to kick off. Added a test for this specific edge-case as well.
2022-09-20 11:34:15 +02:00
tomasz1986
0e23002414 gui: Fix missing word in sendOwnership explanation in GUI (#8547)
For consistency with syncOwnership explanation right above this one, the
sentence should talk about "sending ownership information", and not just
"sending ownership".

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-19 21:34:10 +02:00
Syncthing Release Automation
641941562f gui, man, authors: Update docs, translations, and contributors 2022-09-19 04:32:50 +00:00
André Colomb
698346edc3 script: Support single quotes in $translate.instant() parsing (#8542)
Duplicate the regular expression for single and double quotes.
Support additional arguments (string substitution) in both variants.
Simplify the translation string group matching by using a lazy
quantifier instead of excluding the quote itself.
2022-09-16 22:52:33 +02:00
Jakob Borg
39d3424e34 build: Improve update-deps command, update deps (#8540) 2022-09-14 10:29:44 +02:00
Jakob Borg
6cac308bcd all: Support syncing extended attributes (fixes #2698) (#8513)
This adds support for syncing extended attributes on supported
filesystem on Linux, macOS, FreeBSD and NetBSD. Windows is currently
excluded because the APIs seem onerous and annoying and frankly the uses
cases seem few and far between. On Unixes this also covers ACLs as those
are stored as extended attributes.

Similar to ownership syncing this will optional & opt-in, which two
settings controlling the main behavior: one to "sync" xattrs (read &
write) and another one to "scan" xattrs (only read them so other devices
can "sync" them, but not apply any locally).

Co-authored-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-14 09:50:55 +02:00
greatroar
8065cf7e97 lib: Factor out getting IP address from net.Addr (#8538)
... and add fast paths for common cases.
2022-09-14 08:44:46 +02:00
Eric P
6e768a8387 lib/versioner: Fix cleaning behaviour (fixes #7988) (#8537)
The cleaning logic in util.go was used by Simple and Trashcan but only
really suited Trashcan since it works based on mtimes which Simple does
not use. The cleaning logic in util.go was moved to trashcan.go.
Staggered and Simple seemed to be able to benefit from the same base so
util.go now has the base for those two with an added parameter which
takes a function so it can still handle versioner-specific logic to
decide which files to clean up. Simple now also correctly cleans files
based on their time-stamp in the title together with a specific maximum
amount to keep. The Archive function in Simple.go was changed to get rid
of duplicated code.

Additionally the trashcan testcase which was used by Trashcan as well as
Simple was moved from versioner_test.go to trashcan_test.go to keep it
clean, there was no need to keep it in a separate test file
2022-09-13 19:21:42 +02:00
tomasz1986
7d3c390c91 gui: Fix text wrapping on tablet-sized screens (fixes #8529) (#8533)
Currently, the code contains a "mobile phone" fix to allow wrapping of
long lines in table heading and cells. However, the fix is applied to
all screen sizes equal or below 768 px wide, which causes the layout to
break on tablet-sized screens.

The commit moves the "mobile" fix to the actual mobile media query,
which is applied to screens up to 419 px wide. It is only really needed
there, where it synergises with the existing fix that changes table cell
display to "block". There is no need to wrap the text on larger screens,
as there is more than enough space to display the lines in full on them.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-13 19:18:57 +02:00
André Colomb
3e99ddfbf0 etc/linux-systemd: Mention AmbientCapabilities for syncOwnership. (#8536)
Add a commented entry to the systemd service file templates to point
the user in the right direction when using syncOwnership and starting
via systemd.  Which is more upgrade-friendly than setting caps on the
executable directly, as mentioned in the docs.
2022-09-13 10:00:47 +02:00
tomasz1986
43f0e5c91d gui: Fix error in Restore Versions when path exists as both directory and file (fixes #7068) (#8532)
The current code checks whether the same-named item exists in the tree,
and when it does, it re-uses it when adding new children to it. However,
the code doesn't check whether the existing item is a folder or a file.
It rather assumes that it is always a folder, which is not necessarily
the case.

This commit adds a new check to the code, so that the existing element
is reused only when it is a folder, and ignored otherwise.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-12 08:19:29 +02:00
Syncthing Release Automation
c3902f9887 gui, man, authors: Update docs, translations, and contributors 2022-09-12 04:32:45 +00:00
tomasz1986
33e3643aed gui: Add tooltip to folder error message (fixes #7603) (#8531)
Currently, the error message is often quite long and thus it appears
truncated with no possibility for the user to view the full string.
Thus, add a tooltip that displays the message in full on hover. This
follows the convention used in other parts of the GUI in similar cases.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-11 22:13:04 +02:00
greatroar
78be7225fb build(deps): Bump github.com/pierrec/lz4 (#8528) 2022-09-11 10:13:27 +02:00
cui fliter
6afaa9f20c cmd/syncthing: Fix two typos (#8493)
Signed-off-by: cui fliter <imcusg@gmail.com>
2022-09-11 00:43:10 +02:00
greatroar
152388b3a3 lib/tlsutil: Use crypto.Signer interface (#8526)
*rsa.PrivateKey and *ecdsa.PrivateKey are both Signers, which have a
method to get the public key. No need for the type switch.
2022-09-09 14:22:38 +02:00
Syncthing Release Automation
053425695a gui, man, authors: Update docs, translations, and contributors 2022-09-05 04:26:01 +00:00
Syncthing Release Automation
5d917e1306 gui, man, authors: Update docs, translations, and contributors 2022-08-29 04:23:19 +00:00
luzpaz
837ffcfab5 all: Fix various user-facing and non-user-facing typos (#8509)
Found via `codespell -q 3 -S lang,./gui/default/vendor -L benchs,bu,inflight,ro`
2022-08-23 15:44:11 +02:00
Syncthing Release Automation
62d4261f62 gui, man, authors: Update docs, translations, and contributors 2022-08-22 04:16:54 +00:00
Simon Frei
6dedffe3f7 cmd/syncthing: Use os.executable in monitor, only fallback to PATH (#8502) 2022-08-17 08:57:33 +02:00
Jakob Borg
b10d106a55 all: Modernize error wrapping (#8491)
This replaces old style errors.Wrap with modern fmt.Errorf and removes
the (direct) dependency on github.com/pkg/errors. A couple of cases are
adjusted by hand as previously errors.Wrap(nil, ...) would return nil,
which is not what fmt.Errorf does.
2022-08-16 10:01:49 +02:00
Syncthing Release Automation
75eeae0ee7 gui, man, authors: Update docs, translations, and contributors 2022-08-15 04:09:30 +00:00
Simon Frei
5fd6278609 cmd/syncthing: Work around binary in current dir restriction (fixes #8499) (#8500) 2022-08-14 21:25:45 +02:00
Jakob Borg
eb81f7400c lib/fs: Cache user lookups (#8496) 2022-08-12 07:48:00 +02:00
Jakob Borg
06273875ae all: Make scanning ownership opt-in (#8497) 2022-08-12 07:47:20 +02:00
André Colomb
4d4bfe8032 lib/model: Skip paused folders in aggregated completion loop (fixes #8219) (#8220)
Locally paused folders will fail on checkFolderRunningLocked() and
therefore abort the loop.  Avoid this by skipping paused folders
directly.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2022-08-10 08:50:19 +02:00
tomasz1986
28c660e41d gui: Remove unused strings from translations (#8288)
These strings no longer exist in the GUI, hence there is no need to keep
them in the translation json files either.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2022-08-10 08:44:45 +02:00
Jakob Borg
d6a90f0022 Merge branch 'release'
* release:
  lib/ur: Properly initialize map in failure data (fixes #8479)
2022-08-10 08:30:46 +02:00
André Colomb
63de838f27 gui, api: Show internal config and state paths (fixes #8323) (#8324)
* lib/locations: Fix enum values camelCase.

* lib/locations: Remove unused FailuresFile.

* cmd/syncthing: Turn around role of locations storage.

Previously the locations package was used to provide default paths,
possibly with an overridden home directory.  Extra paths supplied on
the command line were handled and passed around in the options object.

To make the changed paths available to any other interested package,
override the location setting from the option if supplied, instead of
vice versa when not supplied.  Adapt code using this to read from the
locations package instead of passing through the options object.

* lib/locations: Refactor showPaths to locations package.

Generate a reusable string in locations.PrettyPrintPaths().
Enumerating all possible locations in different packages is error
prone, so add a new public function to generate the listing as a
string in the locations package.  Adapt cmd/syncthing --paths to use
that instead of its own console output.

* lib/locations: Include CSRF token in pretty printed paths.

* lib/api: New endpoint /rest/system/paths.

The paths should be available for troubleshooting from a running
instance.  Using the --paths CLI option is not easy in some
environments, so expose the locations mapping to a JSON endpoint.

Add utility function ListExpandedPaths() that also filters out any
entries which still contain variable placeholders.

* gui: List runtime paths in separate log viewer tab.

* Wrap paths.

* lib/syncthing: Utilize locations.Get() instead of passing an arg.

* Include base directories, move label to table caption.

* gui: Switch to hard-coded paths instead of iterating over all.

* gui: Break aboutModalView into tabs.

Use tabs to separate authors from included third-party software.

* gui: Move paths from log viewer to about modal.

* lib/locations: Adjust pretty print output order to match GUI.

* gui, authors: Remove additional bot names and fix indent.

The indentation changed because of the tabbed about dialog, fix the
authors script to respect that.

Skip Syncthing*Automation in authors list as well.

* Update AUTHORS list to remove bot names.

* Revert AUTHORS email order change.

* Do not emphasize DB and log file locations.

* Review line wrapping.

* review part 1: strings.Builder, naming

* Rename and extend locations.Set() with error handling.

Remodel the Override() function along the existing SetBaseDir() and
rename it to simply Set().  Make sure to use absolute paths when given
log file or GUI assets override options.  Add proper error reporting
if that goes wrong.

* Remove obsolete comment about empty logfile option.

* Don't filter out unexpanded baseDir placeholders, only ${timestamp}.

* Restore behavior regarding special "-" logfile argument.

If the option is given, but with empty value, assume the no log
file (same as "-").  Don't try to convert the special value to an
absolute path though and document this fact in a comment for the Set()
function.

* Use template to check for location key validity.

* Don't filter out timestamp placeholders.

* lib/api: Remove paths from /rest/system/status.

* lib/ur: Properly initialize map in failure data (fixes #8479)

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2022-08-10 08:25:13 +02:00
dependabot[bot]
20dea04aa2 build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.1 to 3.4.4 (#8475)
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.1 to 3.4.4.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.1...v3.4.4)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-10 08:15:35 +02:00
Jakob Borg
f5aa604efc Merge branch 'release'
* release:
  lib/ur: Properly initialize map in failure data (fixes #8479)
2022-08-09 18:52:51 +02:00
dependabot[bot]
4eef43c62d build: bump actions/setup-go from 2.2.0 to 3.2.1 (#8492)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.2.0 to 3.2.1.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](bfdd3570ce...84cbf80943)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-09 12:37:20 +02:00
Jauder Ho
d2f132f37f build: Let dependabot suggest updates to GitHub actions (#8490)
Configure Dependabot to update GitHub Actions in workflows.
2022-08-09 12:31:08 +02:00
Jauder Ho
ecdb970468 update: Go version in update-docs-translations action (#8489)
Bump Go minimum version to 1.18.4
2022-08-08 21:01:08 +02:00
Syncthing Release Automation
b32e43fbb3 gui, man, authors: Update docs, translations, and contributors 2022-08-08 04:01:50 +00:00
Martchus
373859be83 cmd/syncthing: Refactor CLI code to allow passing CLI arguments via function parameter (#8485)
Currently the `Run()` function of the CLI always uses `os.Args` directly.
This change adds an additional `RunWithArgs()` function that allows passing
arguments as `[]string` instead. This is useful when linking against
Syncthing as a library to be able to also expose the CLI.
2022-08-07 18:15:26 +02:00
Jakob Borg
209e68c1ba build: Update quic-go for Go 1.19 (#8483)
Also adds idle time and keepalive parameters because how this is
configured has changed in the new package version. The values are those
that seems like might already be default, if keep-alives were enabled,
which is not obvious from the doc comments.

Also, Go 1.19 gofmt reformatting of comments.
2022-08-03 15:43:26 +02:00
Jakob Borg
cc54488e55 lib/ur: Properly initialize map in failure data (fixes #8479) (#8480) 2022-08-03 10:41:26 +02:00
Jakob Borg
c7b4fd5784 lib/ur: Properly initialize map in failure data (fixes #8479) 2022-08-02 10:10:29 +02:00
Syncthing Release Automation
5c69761bc8 gui, man, authors: Update docs, translations, and contributors 2022-08-01 04:20:52 +00:00
bt90
de7d62cc1b docs: Clarify docker network mode limitations (#8472) 2022-07-31 20:46:57 +02:00
Jakob Borg
5977868165 lib/config: Use net.JoinHostPort instead of string manipulation (#8470) 2022-07-28 22:06:55 +02:00
Jakob Borg
585fb3f49b lib/api: Fix inverted logic in string comparison 2022-07-28 21:51:14 +02:00
deepsource-autofix[bot]
8e3f1190d1 lib/model: Use bytes.Equal instead of converting to string (#8469)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 20:00:07 +02:00
Jakob Borg
a3c724f2c3 all: Add build constants for runtime.GOOS comparisons (#8442)
all: Add package runtimeos for runtime.GOOS comparisons

I grew tired of hand written string comparisons. This adds generated
constants for the GOOS values, and predefined Is$OS constants that can
be iffed on. In a couple of places I rewrote trivial switch:es to if:s,
and added Illumos where we checked for Solaris (because they are
effectively the same, and if we're going to target one of them that
would be Illumos...).
2022-07-28 19:36:39 +02:00
deepsource-autofix[bot]
f13d65262a cmd/strelaysrv: Fix superfluous else statements (#8468)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 19:31:43 +02:00
deepsource-autofix[bot]
f2be9d1166 all: Fix nested if with else if (#8467)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 19:14:22 +02:00
Jakob Borg
dde275c6cc all: Unused errors 2022-07-28 19:08:51 +02:00
Jakob Borg
212258d213 lib/fs: Consolidate append in test 2022-07-28 19:05:24 +02:00
Jakob Borg
966db0d076 lib/api: Further (final?) unused parameters removal 2022-07-28 19:02:12 +02:00
Jakob Borg
6686810943 cmd/syncthing: Incorrect error handling 2022-07-28 18:51:22 +02:00
Jakob Borg
6baa93e13f lib/api: String comparisons 2022-07-28 18:49:44 +02:00
Jakob Borg
0c8b22c696 lib/api: Remove unused parameters 2022-07-28 18:48:15 +02:00
deepsource-autofix[bot]
81d8fa1cb5 all: Fix unused method receiver (further) (#8466)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:55:29 +02:00
Jakob Borg
79f8bd0f33 all: Minor deprecation updates 2022-07-28 17:54:12 +02:00
Jakob Borg
5958f42294 lib/model: Clarify normal shallow copy 2022-07-28 17:41:07 +02:00
Jakob Borg
8b4bd43306 lib/api: Missing error handling in config handler (#8463) 2022-07-28 17:35:43 +02:00
deepsource-autofix[bot]
755d21953f all: Remove unused method receivers (#8462)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:32:45 +02:00
Jakob Borg
388e4db9cd all: Combine sequential appends (#8461) 2022-07-28 17:28:24 +02:00
Jakob Borg
f3835122bb cmd/ursrv: Silence linter with correct regexps (#8460) 2022-07-28 17:26:07 +02:00
deepsource-autofix[bot]
5130c414da all: Unused parameter should be replaced by underscore (#8464)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:17:29 +02:00
Jakob Borg
7bdb5faa9c all: Remove or convert deprecated API usages (#8459) 2022-07-28 17:14:49 +02:00
deepsource-autofix[bot]
7e26f74f38 lib/config: Remove unnecessary use of fmt.Sprintf (#8458)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:00:41 +02:00
deepsource-autofix[bot]
0bdd0d595b lib/model: Replace for loop with append (#8457)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 16:57:09 +02:00
deepsource-autofix[bot]
80ec4acb53 all: Fix check for empty string (#8456)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 16:51:03 +02:00
Jakob Borg
a2c5d901f2 cmd/syncthing, lib/config: Remove restartOnWakeup option & functionality (fixes #8448) (#8449) 2022-07-26 16:53:10 +02:00
LSmithx2
1b575b4461 gui: Remove blank meta tags (#8362) 2022-07-26 10:19:12 +02:00
Evan Spensley
c6a319d98b gui: Add device sync status (fixes #7981) (#8401) 2022-07-26 10:15:19 +02:00
tomasz1986
9f4d23cacf gui: Fix detailed staggered versioning information in folder info (ref #8348) (#8433)
Currently, there are two issues with the detailed staggered versioning
information displayed in the folder info. Firstly, the maxAge value of
365d is displayed despite matching the default. Secondly, there is no
consideration for the special case of maxAge equal to 0, meaning that
versions are kept forever.

This commit fixes both of those issues, so that the default maxAge is
not displayed and its value of 0 is displayed as "forever".

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-07-26 10:12:15 +02:00
Jakob Borg
adce6fa473 all: Support syncing ownership (fixes #1329) (#8434)
This adds support for syncing ownership on Unixes and on Windows. The
scanner always picks up ownership information, but it is not applied
unless the new folder option "Sync Ownership" is set.

Ownership data is stored in a new FileInfo field called "platform data". This
is intended to hold further platform-specific data in the future
(specifically, extended attributes), which is why the whole design is a
bit overkill for just ownership.
2022-07-26 08:24:58 +02:00
Syncthing Release Automation
34a5f087c8 gui, man, authors: Update docs, translations, and contributors 2022-07-25 04:05:44 +00:00
André Colomb
a6dba7c6d6 lib/model, lib/config: Apply sensible defaults for auto-accepted encrypted folder (fixes #8296) (#8427)
* lib/model: Override scan config for auto-accepted encrypted folders.

Encrypted folders should not have the fs watcher enabled and rarely
benefit from a scheduled rescan.  The GUI adjusts the suggested
settings (watcher disabled, one day rescan interval) when accepting a
receive-encrypted folder.  Mirror that behavior to the auto-accept
case where the GUI is not involved.

Versioning also does not work well for encrypted folders, same
treatment.
2022-07-22 11:27:58 +02:00
tomasz1986
2eabc79d4c gui: Move filesystem watcher explanation from tooltip to help block (#8432)
Currently, the filesystem watcher explanation in the Advanced tab in the
Edit Folder modal window is split into two parts. The first is location
in a tooltip that is visible only when hovering the mouse over the small
checkbox, which makes it not easily accessible, e.g. for new or touch
screen users.

No other settings in the Edit Folder window have their explanation
presentend like that. When needed, it is always displayed in their
respective help blocks, which are always visible on the screen. Thus,
move the filesystem watcher explanation from the tooltip to the help
block, merging it with the other part of the explanation in the process.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-07-22 11:25:14 +02:00
André Colomb
9c2428c2ee gui: Use discovered IDs from cache when adding a new remote device (#8382)
* gui: Use discovered IDs from cache when adding a new remote device.

The GUI already does refreshDiscoveryCache() when it comes online and
on every 10 second refresh cycle.  Querying the same information
freshly in addDevice() seems unnecessary and adds some more round-trip
delay on a possibly slow network link.  Instead use the IDs from the
existing discoveryCache property to populate the suggested ID list.

* Increase maximum suggested device ID count to 100.

For the auto-completion list, which is hidden by default and filtered
by the browser, we can offer more discovered device IDs without
causing much confusion.  The list of suggested "nearby" devices is
still limited to the first five.

* Rename $scope.discoveryUnknown.

The old name "discovery" was pretty ambiguous..
2022-07-22 11:09:26 +02:00
Jakob Borg
9b390f1264 build: Update goleveldb (#8440) 2022-07-21 18:39:14 +02:00
Syncthing Release Automation
c06a169f5f gui, man, authors: Update docs, translations, and contributors 2022-07-18 04:04:58 +00:00
sec65
4335285a64 cmd/syncthing/cli: Add show discovery command (fixes #8007) (#8378) 2022-07-13 23:11:17 +02:00
Syncthing Release Automation
34c05bee6d gui, man, authors: Update docs, translations, and contributors 2022-07-11 04:01:52 +00:00
Aroun
7cb8af9029 lib/osutil: Only announce address of interfaces which are up (fixes #7458) (#8422) 2022-07-07 19:19:29 +02:00
tomasz1986
8facaf5a6a gui: Fix missing span end tag and missing nbsp semicolon in HTML (#8419)
Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-07-05 23:04:30 +02:00
Jakob Borg
abea3d7552 cmd/syncthing: Apply file permissions and modtimes when decrypting (#8412)
Directories are not represented in the encrypted storagage so they get
to keep default permissions...
2022-07-04 10:57:45 +02:00
Syncthing Release Automation
13d545c9f2 gui, man, authors: Update docs, translations, and contributors 2022-06-27 04:05:49 +00:00
Simon Frei
3a6ebb8482 lib/config, lib/model: Warn about two-way introducer (fixes #8393) (#8395) 2022-06-20 18:36:45 +01:00
dependabot[bot]
e071f16531 build(deps): bump github.com/prometheus/client_golang from 1.11.0 to 1.12.2 (#8345)
build(deps): bump github.com/prometheus/client_golang

Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.11.0 to 1.12.2.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.11.0...v1.12.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-20 19:26:22 +02:00
dependabot[bot]
920f2ce1e6 build(deps): bump github.com/alecthomas/kong from 0.3.0 to 0.6.1 (#8398)
Bumps [github.com/alecthomas/kong](https://github.com/alecthomas/kong) from 0.3.0 to 0.6.1.
- [Release notes](https://github.com/alecthomas/kong/releases)
- [Commits](https://github.com/alecthomas/kong/compare/v0.3.0...v0.6.1)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/kong
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-20 19:25:14 +02:00
dependabot[bot]
2e135d0c65 build(deps): bump github.com/pierrec/lz4/v4 from 4.1.13 to 4.1.15 (#8397)
Bumps [github.com/pierrec/lz4/v4](https://github.com/pierrec/lz4) from 4.1.13 to 4.1.15.
- [Release notes](https://github.com/pierrec/lz4/releases)
- [Commits](https://github.com/pierrec/lz4/compare/v4.1.13...v4.1.15)

---
updated-dependencies:
- dependency-name: github.com/pierrec/lz4/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-20 18:43:05 +02:00
Jakob Borg
0e79b532cf build: Update to patched github.com/gobwas/glob (fixes #8386) (#8387)
The glob package has seen very little activity the last few years so I'm
not holding my breath on getting this merged.
2022-06-15 21:49:15 +02:00
André Colomb
f7e30a9f10 gui: Fix missing folder names in Edit Device > Sharing tab (fixes #8369) (#8388) 2022-06-15 19:31:54 +02:00
Syncthing Release Automation
b140b4a994 gui, man, authors: Update docs, translations, and contributors 2022-06-13 04:02:19 +00:00
Devon G. Redekopp
6fd7cd808c gui: Disable autocomplete for user/password fields in settings (fixes #8376) (#8377)
Disable Chrome autofill username/password in GUI settings modal dialog.
2022-06-07 06:59:11 +02:00
Syncthing Release Automation
02224be83f gui, man, authors: Update docs, translations, and contributors 2022-06-06 03:58:32 +00:00
tomasz1986
ebe45b3965 gui: Display "days" next to "maximum age" in Staggered Versioning (#8374) 2022-06-04 14:24:06 +02:00
落心
486bb2da0e cmd/strelaysrv: Trivial cleanup in test utility (#8373) 2022-06-02 15:15:42 +02:00
André Colomb
68aa00539e gui: Fix use of old, renamed function in edit folder sharing tab (fixes #8369) (#8371)
Fix use of old, renamed function in edit folder sharing tab.
2022-05-31 22:19:44 +02:00
Syncthing Release Automation
52a883d34e gui, man, authors: Update docs, translations, and contributors 2022-05-30 04:01:43 +00:00
Simon Frei
5ac122b85f lib/model: Don't include deleted items in kqueue warning threshold (ref #7855) (#8365) 2022-05-28 20:15:38 +02:00
tomasz1986
de2d7c33a3 gui: Add detailed file versioning information to folder info (ref #963) (#8348) 2022-05-28 13:46:15 +02:00
greatroar
2ca8a5ac61 lib/assets: MIME types, time formats (#8351)
.eot and .woff2 weren't listed, but are present in vendored fontawesome.

.ttf and .woff are font/* according to IANA,
https://www.iana.org/assignments/media-types/media-types.xhtml#font.
This matches what mime.TypeByExtension returns.

.eot is from https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types.
mime.TypeByExtension doesn't recognize this extension.

* lib/assets: Use http.ParseTime

This understands the three time formats allowed in HTTP.
2022-05-22 22:10:18 +02:00
Simon Frei
e3078cc531 lib/model: Don't fail on temporary chmod (fixes #8355, ref #8235) (#8356) 2022-05-22 13:52:40 +02:00
tomasz1986
5495d0f8ab gui: Update Fork Awesome from v1.1.2 to v1.2.0 (#8349)
This commit updates Fork Awesome from version 1.1.2 from 2018 to version
1.2.0 from 2021. The changes are few and non-breaking, consisting mainly
of new icon additions.

It is worth to note that the new version includes also a Syncthing icon,
which was not present before.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-05-18 14:08:45 +02:00
Syncthing Release Automation
388b21d9db gui, man, authors: Update docs, translations, and contributors 2022-05-16 03:52:16 +00:00
Syncthing Release Automation
a162e8d9f9 gui, man, authors: Update docs, translations, and contributors 2022-05-09 03:58:03 +00:00
André Colomb
235422c26d gui, authors: Remove additional bot names (#8333)
Skip Syncthing*Automation in authors list as well.
2022-05-08 22:42:05 +02:00
André Colomb
2bcaa17fc3 gui: Add default ignores to the advanced configuration editor modal (fixes #8264) (#8265) 2022-05-08 21:34:03 +02:00
greatroar
97291c9184 lib/api: Fix and optimize csrfManager (#8329)
An off-by-one error could cause tokens to be forgotten. Suppose

	tokens := []string{"foo", "bar", "baz", "quux"}
	i := 2
	token := tokens[i] // token == "baz"

Then, after

	copy(tokens[1:], tokens[:i+1])
	tokens[0] = token

we have

	tokens == []string{"baz", "foo", "bar", "baz"}

The short test actually relied on this bug.
2022-05-07 12:30:13 +02:00
Jakob Borg
520ca4bcb0 script, gui: Exclude bots from the in-GUI authors list 2022-05-06 08:00:22 +02:00
Simon Frei
f35fb974d0 build: Add concise build instructions to readme (#8327) 2022-05-06 07:56:26 +02:00
Jakob Borg
f8c51d801a lib/discover: Filter locally announced addresses (fixes #7289) (#8302) 2022-05-04 18:43:00 +02:00
Jakob Borg
16c0c2f7a7 Merge branch 'release'
* release:
  lib/connections: Correct race on loop variable (fixes #8320) (#8321)
2022-05-04 18:25:58 +02:00
Jakob Borg
2145b3701d lib/connections: Correct race on loop variable (fixes #8320) (#8321) 2022-05-04 18:17:03 +02:00
Jakob Borg
ce0ded7c78 lib/connections: Correct race on loop variable (fixes #8320) (#8321) 2022-05-04 18:16:36 +02:00
André Colomb
31a78592e8 gui: Mark folders paused on remote device. (#8286)
Similar to the "remote has not accepted sharing" message, add a
footnote number 2 to indicate a folder which will not sync with a
certain device because the remote has paused it.  Applies to the edit
folder / device modals' sharing tab, as well as the "shared with"
listing and tooltips under device and folder details.
2022-05-03 21:51:09 +02:00
Jakob Borg
334a78f185 cmd/strelaysrv, cmd/strelaypoolsrv: Sanitize query strings (fixes #8314) (#8315)
Use the proper encoding function in the relay server when constructing
the URL. In the pool server, parse and re-encode the query values to
sanitize whatever the client sent.
2022-05-02 10:38:49 +02:00
greatroar
233d3e7f7b lib/events: Remove unused method noopLogger.Stop (#8312)
This was needed for the old suture API, abandoned in
9524b51708.
2022-05-02 08:00:55 +02:00
Syncthing Release Automation
41a429b52c gui, man, authors: Update docs, translations, and contributors 2022-05-02 04:07:12 +00:00
greatroar
d00a30069a lib/db: Constant/unused args and return values, double it.Release (#8259) 2022-04-27 20:32:44 +02:00
greatroar
49488c0e71 all: Clean up fmt.Errorf usage (#8309) 2022-04-27 20:30:13 +02:00
Simon Frei
4031568cdf gui: Bandaid for null http errors (fixes #8261) (#8305) 2022-04-25 19:15:14 +02:00
Syncthing Release Automation
fff9bf98eb gui, man, authors: Update docs, translations, and contributors 2022-04-25 03:54:44 +00:00
Simon Frei
6a7fc49c6b lib/discover: Increase global discovery timeout (#8303) 2022-04-23 16:12:25 +02:00
red_led
89f5d0d400 gui: Always show vertical scroll bar (#8301)
This stops interface from jumping left and right when page content no longer fits into screen.
2022-04-22 21:39:30 +02:00
André Colomb
1eda82b95f lib/model: Improve remoteFolderState reporting (fixes #8266) (#8283) 2022-04-22 08:42:20 +02:00
Jakob Borg
623ec03dad lib/model: Correct type of event data (fixes #8294) (#8295)
These things are fragile, every event should use an ${eventType}Data struct or something instead.
2022-04-21 15:45:31 +02:00
Jakob Borg
c0de42e3df gui: Use neutral color for zero out of zero listeners (#8281) 2022-04-20 14:43:11 +02:00
tomasz1986
4893513800 gui: Improve Latest Change translation string for better multilanguage support (#8290)
Currently, the "Latest Change" translation string is hard-coded to use
the English-like word order of V ("deleted") + N ("file"). As such, it
is incompatible with languages that require to use a different word
order, e.g. Korean or Japanese. In other words, a proper translation of
the string to those languages is currently impossible.

This commit changes the translation string, so that it includes the file
variable, and thanks to this, it can be easily adopted to languages with
different word order than English.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-04-18 06:41:26 +02:00
Syncthing Release Automation
100142067d gui, man, authors: Update docs, translations, and contributors 2022-04-18 03:54:08 +00:00
Simon Frei
3907cb0693 lib/model: Subscribe to correct event for fs watching (ref #8249) (#8287) 2022-04-17 12:41:25 +04:00
Jakob Borg
61dffabf97 cmd/syncthing, lib/logger: Add date to default log format (fixes #8272) (#8273)
This changes the default log format to include the date.
2022-04-15 07:46:14 +04:00
Eng Zer Jun
bc27aa12cd all: use T.TempDir to create temporary test directory (#8280)
This commit replaces `os.MkdirTemp` with `t.TempDir` in tests. The
directory created by `t.TempDir` is automatically removed when the test
and all its subtests complete.

Prior to this commit, temporary directory created using `os.MkdirTemp`
needs to be removed manually by calling `os.RemoveAll`, which is omitted
in some tests. The error handling boilerplate e.g.
	defer func() {
		if err := os.RemoveAll(dir); err != nil {
			t.Fatal(err)
		}
	}
is also tedious, but `t.TempDir` handles this for us nicely.

Reference: https://pkg.go.dev/testing#T.TempDir
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2022-04-15 07:44:06 +04:00
André Colomb
0537b9546f lib/model: Switch the remoteFolderState default value to valid (#8275)
Showing all folders from disconnected or paused remote devices as
unaccepted would be a lot of false positives.  As we cannot know
whether the remote has accepted while it doesn't have an active
connection, let's better report false negatives, as in assuming the
folders are accepted.
2022-04-13 18:15:58 +02:00
Simon Frei
0525c755f4 build: Bump quic-go to 0.26.0 for go1.18 update (#8231)
Merging because I want this in the RC, when we do the RC...
2022-04-12 16:27:29 +04:00
Simon Frei
bcd91f536e lib/connections: Create the forgotten channel (ref #8263) (#8267) 2022-04-11 17:32:22 +04:00
Syncthing Release Automation
f9c6c69fa8 gui, man, authors: Update docs, translations, and contributors 2022-04-11 03:52:11 +00:00
André Colomb
0c46e0a9cc gui, lib/model: Mark folders unaccepted by remote device (fixes #8202) (#8201) 2022-04-10 22:47:57 +02:00
Greg
bca6d31b95 Correct comment typo in build.go (#8234) 2022-04-10 22:24:57 +02:00
Simon Frei
db72579f0e lib: Get rid of buggy filesystem wrapping (#8257) 2022-04-10 20:55:05 +02:00
Jakob Borg
9b09bcc5f1 lib/connections: Always run a simple connection test (#7866) 2022-04-10 20:54:42 +02:00
Simon Frei
22e12904c9 lib/connections: Make request tests sequential (#8263) 2022-04-10 20:54:16 +02:00
Simon Frei
b947056e62 lib: Removal global connection registry (#8254) 2022-04-09 16:04:56 +02:00
Jeffery To
e30898ddb3 build: Update go directive to 1.17 (fixes #8258) (#8260)
This should fix compiling from the source tarball with Go 1.18.
2022-04-09 16:01:24 +02:00
Simon Frei
072fa46bfd lib/connections, lib/model: Improve new conn handling (#8253) 2022-04-07 17:35:33 +02:00
Simon Frei
edc3a77b98 lib/fs, lib/model: Add warning about kqueue resource usage (fixes #7855) (#8249) 2022-04-05 21:32:06 +02:00
Syncthing Release Automation
2b80848341 gui, man, authors: Update docs, translations, and contributors 2022-04-04 03:50:52 +00:00
André Colomb
30fa462e33 all: Comments and cosmetics (#8218)
* lib/api: Note ItemStarted and ItemFinished for default filtering.

The reasoning why LocalChangeDetected and RemoteChangeDetected events
are not included in the event stream by default (without explicit
filter mask requested) also holds for the ItemStarted and ItemFinished
events.  They should be excluded as well when we start to break the
API compatibility for some reason.

* gui: Enumerate unused event types in the eventService.

Define constants for the unused event types as well, for completeness'
sake.  They are intentionally not handled in the GUI currently.

* cmd/syncthing: Harmonize uppercase CLI argument placeholders.

Use ALL-UPPERCASE and connecting dashes to distinguish argument
placeholders from literal argument options (e.g. "cpu" or "heap" for
profiling).  The dash makes it clear which words form a single
argument and where a new argument starts.

This style is already used for the "syncthing cli debug file" command.

* lib/model: Simplify event data structure.

Using map[string]interface{} is not necessary when all values are
known to be strings.
2022-04-02 20:36:19 +02:00
Syncthing Release Automation
11ac945b87 gui, man, authors: Update docs, translations, and contributors 2022-03-28 03:50:34 +00:00
Simon Frei
55c513b827 lib/model: Clear folder error after loading ignores (fixes #8232) (#8238) 2022-03-27 21:29:40 +02:00
greatroar
0eca0ac45a lib/model: Chmod to mode|0700, not 755 (#8235) 2022-03-26 12:07:07 +02:00
greatroar
4be867c560 all: Replace errors.Cause with errors.Is (#8236) 2022-03-26 12:05:57 +02:00
Naveen
44b11ec257 Pin actions to a full length commit SHA (#8224) 2022-03-24 16:46:06 +01:00
Greg
53926a1ae6 lib/fs: Do not follow symlinks in watcher on solaris (fixes #8020) (#8223) 2022-03-24 08:36:43 +01:00
Syncthing Release Automation
5f383923df gui, man, authors: Update docs, translations, and contributors 2022-03-21 03:47:47 +00:00
greatroar
26eaedc491 lib/db, lib/discover: Minor cleanup (#8217) 2022-03-14 22:48:10 +01:00
Syncthing Release Automation
7b63254a35 gui, man, authors: Update docs, translations, and contributors 2022-03-14 03:47:23 +00:00
greatroar
d0fd6c6c82 lib/db: Make err(Closed|NotFound) values (#8215) 2022-03-13 20:53:34 +01:00
tomasz1986
6862dd04ab gui: Allow to translate calendar buttons in Restore Versions modal (#8213) 2022-03-12 22:44:56 +01:00
tomasz1986
e1b1631c65 gui: Allow to translate Twitter footer link (#8212) 2022-03-12 22:44:10 +01:00
Andrew Meyer
1d74b547dd Add port for local discovery broadcasts to Docker documentation (#8197)
* Docs: Add descriptive comments to Docker ports

* Docs: Add Docker port for local discovery broadcasts

See https://docs.syncthing.net/specs/localdisco-v4.html
2022-03-08 08:06:45 +01:00
Jakob Borg
a3a4da6e3e gui: Use versioned link to documentation in bottom bar (#8204) 2022-03-08 07:56:42 +01:00
Syncthing Release Automation
e974c13c7a gui, man, authors: Update docs, translations, and contributors 2022-03-07 03:45:51 +00:00
André Colomb
1999383443 Rename environment variable STCPUPROFILE for consistency. (#8200) 2022-03-03 15:27:17 +01:00
greatroar
bd0acd04b1 lib/protocol: Use one mutex for rawConnect.awaiting and nextID (#8198)
Having a separate mutex for the three or four instructions needed to
fetch and increment nextID means the overhead exceeds the cost of this
operation.  nextID is now handled inside the critical section for
awaiting instead, while the more expensive channel creation has been
moved outside it.

This is mostly a simplification, though it may have minor performance
benefits in some situations. The single-threaded sender benchmark shows
no significant difference:

name               old speed      new speed      delta
RequestsRawTCP-8   55.3MB/s ± 7%  56.6MB/s ± 6%   ~     (p=0.190 n=10+10)
RequestsTLSoTCP-8  20.5MB/s ±20%  20.8MB/s ± 8%   ~     (p=0.604 n=10+9)
2022-02-28 09:13:30 +01:00
Syncthing Release Automation
f25947e5eb gui, man, authors: Update docs, translations, and contributors 2022-02-28 03:46:00 +00:00
Jakob Borg
f890fe6fd3 lib/config: Improve clarity of free space errors (fixes #8180) (#8191) 2022-02-24 17:07:51 +01:00
dependabot[bot]
10f9d95cd2 build(deps): bump github.com/thejerf/suture/v4 from 4.0.1 to 4.0.2 (#8190)
Bumps [github.com/thejerf/suture/v4](https://github.com/thejerf/suture) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/thejerf/suture/releases)
- [Commits](https://github.com/thejerf/suture/compare/v4.0.1...v4.0.2)

---
updated-dependencies:
- dependency-name: github.com/thejerf/suture/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-23 21:07:15 +01:00
Jakob Borg
013c757a84 github: Provide Git history when checking out for actions 2022-02-21 14:57:21 +01:00
Syncthing Release Automation
ffa46c2461 gui, man, authors: Update docs, translations, and contributors 2022-02-21 03:45:27 +00:00
Syncthing Release Automation
48fd9d05b5 gui, man, authors: Update docs, translations, and contributors 2022-02-14 03:45:24 +00:00
tomasz1986
0b1f792290 gui: Add Docs help links to each setting in Advanced Configuration (#7358)
Add a link next to each setting's label to its explanation in the Docs.
This way, it is easy to quickly check what the setting is about without
going to the Docs site separately and searching for it manually.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-09 00:05:26 +01:00
tomasz1986
c25fcf0001 gui: Remove superfluous Trash Can info text from Simple Versioning (#8177)
Right now, the Trash Can versioning info text is displayed for both the
Trash Can and Simple versioning. However, the Simple versioning has its
own info text that is also displayed, which results in two very similar
sentences being shown on the screen.

This commit limits the Trash Can info text to be displayed only when the
Trash Can versioning is selected, and moves the Simple versioning info
text up to the same location as the other one.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-08 20:10:03 +01:00
dependabot[bot]
ba2c79f310 build(deps): bump github.com/pierrec/lz4/v4 from 4.1.12 to 4.1.13 (#8170)
Bumps [github.com/pierrec/lz4/v4](https://github.com/pierrec/lz4) from 4.1.12 to 4.1.13.
- [Release notes](https://github.com/pierrec/lz4/releases)
- [Commits](https://github.com/pierrec/lz4/compare/v4.1.12...v4.1.13)

---
updated-dependencies:
- dependency-name: github.com/pierrec/lz4/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 07:15:50 +01:00
tomasz1986
c396124bc9 gui: Don't use italic text for CJK languages (#8172)
Even though technically possible, CJK languages normally don't use
italic text at all, as not only does it make the characters/letters look
unnatural, but also, in the case of complex characters, unreadable too.
For these reasons, it is usually recommended not to use the italic font
style at all [1][2].

This commit changes the default font-style of the i element for Chinese,
Japanese, and Korean langauge to "normal" instead of "italic". In order
to do so, the HTML lang attribute is also changed following each change
of the GUI language.

[1] https://bobtung.medium.com/best-practice-in-chinese-layout-f933aff1728f
[2] https://devblogs.microsoft.com/oldnewthing/20060914-02/?p=29743

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-08 07:07:22 +01:00
tomasz1986
d35d7d2360 lib, gui: Removed unused cleanInterval from Staggered Versioning (ref #541) (#8161)
Staggered File Versioning used to have its own cleanInterval that
controlled how often file versions were cleaned. Nowadays, there is a
seperate setting called cleanupIntervalS responsible for the cleanup,
which applies to all File Versioning (except External). Thus, remove the
unneeded code and don't set the param up on new folders anymore.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-08 07:06:14 +01:00
tomasz1986
2738735321 gui: Allow to translate and fix incorrect Versions date filter ranges (#8162)
* gui: Allow to translate and fix incorrect Versions date filter ranges

Translate the previously English-only ranges used in Versions date
filter. In the process, fix the currently incorrect range calculation.

For instance, let us say it is 08:05. Selecting "today" should set the
range to start at 00:00 and end at 08:05. However, what really happens
is that both start and end are set to 08:05, and as a result "today" is
never shown to the user. The case is the same for "yesterday", which in
contrary to "today" is shown, but its range is fixed at 08:05 on the
previous day.

This commit fixes the above by always calculating "today" starting at
00:00 up to the current moment, and calculating "yesterday" from 00:00
on the previous to 00:00 on the current day.

When it comes to "last x days", the commit fixes the calculation so that
it actually covers the whole day, which is done by moving the start date
to 00:00 on the first day.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-07 21:41:05 +01:00
André Colomb
1c74944cca lib/api: Fix comments for endpoint parameters (#8163) 2022-02-07 08:51:09 +01:00
Syncthing Release Automation
412616bb96 gui, man, authors: Update docs, translations, and contributors 2022-02-07 03:45:33 +00:00
Simon Frei
518d5174e6 lib/model: Print device when a block request fails (#8159) 2022-02-01 20:20:55 +01:00
Simon Frei
2656c1b8e1 gui: Fix mistake (fixes #8152, ref #8147) (#8157) 2022-01-31 17:54:19 +01:00
Simon Frei
635085d139 lib/db, lib/model: Remove filesystem state from FileSet (fixes #7850) (#8151) 2022-01-31 10:12:52 +01:00
Syncthing Release Automation
d1e81a0acf gui, man, authors: Update docs, translations, and contributors 2022-01-31 03:45:29 +00:00
Simon Frei
6094b95784 gui: Fix and align folder editing states (fixes #8145) (#8147) 2022-01-30 17:43:39 +01:00
Jonathan
d37a5b03f1 lib/fs: Handle permission change events on macos (fixes #7924) (#8150) 2022-01-30 17:21:21 +01:00
tomasz1986
1794d45ff3 gui: Fix ignoreDelete warning formatting (ref #8054) (#8138)
The ignoreDelete warning code originally comprised of two sentences,
which in total were much longer than the current one. Because of that,
some additional fixes were added to make it present itself better, e.g.
white-space was set to normal to allow for text wrap on narrow screens,
and the help link was moved to a new line to make sure both the anchor
and the question mark always stayed together.

However, the code fixes remained despite the final text being much
shorter than the original. Therefore, remove the unnecessary white-space
formatting, and also move the help link right next to the warning. This
makes it clear that the link is related to this particular warning when
both it and the ignore patterns warning are displayed at the same time.

Ref: https://github.com/syncthing/syncthing/pull/8054#issuecomment-978148117

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-30 13:03:46 +01:00
Daniel Barczyk
7b0fbb6fef cmd/syncthing/cli: Add showing pending folders for given device (fixes #8130) (#8131)
Add --device flag to filter pending folders.
2022-01-30 08:09:37 +01:00
tomasz1986
80d4bc1cea gui: Translate fancytree messages in Versions modal (#8149)
* gui: Translate fancytree messages in Versions modal

Currently, the default fancytree info/error messages are used. This
means that a) they are English-only, and b) they are very generic. With
this commit, the messages are added to the translatable strings, and
they are also more specifically related to file versioning.

On a side note, the "moreData" string has been left out on purpose, as
it is not used in the current code. It can be added later if needed.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-30 07:56:36 +01:00
Simon Frei
8763fb05ec lib/fs: Improve error messages checking file paths (fixes #7942) (#8148) 2022-01-29 18:47:55 +01:00
tomasz1986
73e2e2a794 gui: Make device ID read-only and hide "nearby devices" when adding a new pending device (fixes #8083) (#8091)
* gui: Make ID read-only and hide nearby devices when adding pending devices (fixes #8083)

Currently, there is no distinction between adding "new" and "pending"
devices. For this reason, the user is always presented with a list of
"nearby devices" to choose from. This commit adds such distinction to
the code, and in the case of "pending" device, both the device ID is
made read-only and the nearby devices list is hidden.

As a by-product of the function rename and clean-up, this commit also
hides the non-functional "remove" button that is shown when editing
device defaults.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-28 09:15:56 +01:00
Jakob Borg
479712cdc5 cmd/stdiscosrv: Don't start replication listener without peers (fixes #8143) (#8144)
The intention was that if no peers are given, we shouldn't start the
listener. We did that anyway, because:

- splitting an empty string on comma returns a slice with one empty
  string in it
- parsing the empty string as a device ID returns the empty device ID

so we end up with a valid replication peer which is the empty device ID.
2022-01-27 09:36:54 +01:00
tomasz1986
9efac0f067 gui: Tweak the Restore Versions modal for better usability (#7972) 2022-01-25 23:08:27 +01:00
greatroar
a0fd619df3 lib/protocol: Require at least 3.125% savings from compression (#8133)
* lib/protocol: Require at least 3.125% savings from compression

The new lz4 library doesn't need its output buffer to be the maximum
size, unlike the old one (which would allocate if it weren't). It can
take a buffer that is of a smaller size and will report if compressed
data can fit inside the buffer (with a small chance of reporting a false
negative). Use that property to our advantage by requiring compressed
data to be at most n-n/32 = .96875*n bytes long for n input bytes.

* lib/protocol: Remove unused receivers

To make DeepSource happy.

* lib/protocol: Micro-optimize lz4Compress

Only write the length if compression was successful. This is a memory
write, so the compiler can't reorder it.

Only check the return value of lz4.CompressBlock.  Length-zero inputs
are always expanded by LZ4 compression (the library documents this),
so the check on len(src) isn't needed.
2022-01-24 19:36:58 +01:00
André Colomb
1af87577e1 gui: Generate version-specific documentation link URLs (#8108)
Replace all HTML references to https://docs.syncthing.net with a
function call to return a version-specific URL.
2022-01-24 19:36:11 +01:00
Syncthing Release Automation
99f96c5cb7 gui, man, authors: Update docs, translations, and contributors 2022-01-24 03:45:54 +00:00
dependabot[bot]
4329ba316f build(deps): bump github.com/shirou/gopsutil/v3 from 3.21.8 to 3.21.12 (#8123)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.21.8 to 3.21.12.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.21.8...v3.21.12)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-22 08:46:03 +01:00
dependabot[bot]
a78aedec7e build(deps): bump github.com/alecthomas/kong from 0.2.17 to 0.3.0 (#8126)
Bumps [github.com/alecthomas/kong](https://github.com/alecthomas/kong) from 0.2.17 to 0.3.0.
- [Release notes](https://github.com/alecthomas/kong/releases)
- [Commits](https://github.com/alecthomas/kong/compare/v0.2.17...v0.3.0)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/kong
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-22 08:32:03 +01:00
Simon Frei
f0d5dc5696 gui: Fix loading default ignores (#8135) 2022-01-21 17:24:11 +01:00
Simon Frei
e40289ce7a build: Bump quic to v0.25.0 for Go1.18 support (#8134) 2022-01-21 14:54:42 +01:00
Jakob Borg
b6d1e16b4e lib/protocol: Switch to a newer lz4 package (#8122) 2022-01-17 18:52:43 +01:00
Syncthing Release Automation
e700ef3208 gui, man, authors: Update docs, translations, and contributors 2022-01-17 03:47:43 +00:00
Simon Frei
45d145a281 gui: Fix bug saving settings (fixes #8116) (#8117) 2022-01-16 19:06:50 +01:00
Simon Frei
b2996eee87 gui: Handle folder missing in model on error event (#8120) 2022-01-16 18:07:33 +01:00
Simon Frei
21d04b895a lib, gui: Default ignores for new folders (fixes #7428) (#7530) 2022-01-13 23:38:21 +01:00
Ryan Qian
40bb52fdd8 build: Add an option to specify output dir for crosscompiling all (#8109)
When GOBIN is set, 'go install' cannot install cross-compilied binaries.
To satisfy cross-compilation, it's necessary to add the '-o' to build
target, otherwise 'go build' will discarding the resulting objects when
compiling multiple packages.

Signed-off-by: bekcpear <i@bitbili.net>
2022-01-13 09:57:23 +01:00
Jakob Borg
1242ac74ab github: Make docs commits as release bot 2022-01-12 21:56:21 +01:00
Syncthing Automation
3bfd41c48b gui, man, authors: Update docs, translations, and contributors 2022-01-10 13:48:17 +00:00
Jakob Borg
4fb7e04686 github: Use specific token to override branch protection 2022-01-10 14:45:47 +01:00
Jakob Borg
dc0dbed96e github: Add docs update workflow (#8105) 2022-01-10 14:28:39 +01:00
André Colomb
0cba3154f0 lib/model: Remove bogus fields from connections API endpoint (fixes #8103) (#8104)
* lib/model: Remove bogus fields from connections API endpoint.

Switch the returned data type for the /rest/system/connections element
"total" to use only the Statistics struct.  The other fields of the
ConnectionInfo struct are not populated and misleading.

* Lowercase JSON field names.

* lib/model: Get rid of ConnectionInfo.MarshalJSON().

It was missing the StartedAt field from the embedded Statistics
struct.  Just lowercasing the JSON attribute names can be done just as
easily with annotations.

* lib/model: Remove bogus startedAt field from totals.

Instead of using the Statistics type with one field empty, just switch
to a free-form map with the three needed fields.
2022-01-10 10:26:45 +01:00
tomasz1986
fec476cc80 gui: Sort language names vertically and don't truncate on small screens (#8101) 2022-01-08 16:51:29 +01:00
Jakob Borg
bc3d306dd7 cmd/syncthing: Error capitalization 2022-01-07 11:50:19 +01:00
André Colomb
5237337626 cmd/syncthing: Add --skip-port-probing (fixes #8090) (#8099)
* cmd/syncthing: Remove unnecessary function arguments.

The openGUI() function does not need a device ID to work, and there is
only one caller anyway which uses EmptyDeviceID.

The loadOrDefaultConfig() function is always called with the same
dummy values.

* cmd/syncthing: Avoid misleading info messages from monitor process.

In order to check whether panic reporting is enabled, the monitor
process utilizes the loadOrDefaultConfig() function.  In case there is
no config file yet, info messages may be logged during creation if the
config Wrapper, which is discarded immediately after.

Stop using the DefaultConfig() utility function from lib/syncthing and
directly generate a minimal config instead to avoid these.

Add comments to loadOrDefaultConfig() explaining its limited purpose.

* cmd/syncthing/generate: Always write updated config file.

Previously, an existing config file was left untouched unless either
of the --gui-user or --gui-password options was given.  Remove that
condition and simplify the checking code.

* lib/config: Factor out ProbeFreePorts().

* cmd/syncthing: Add option --skip-port-probing.

Applies to both the "generate" and "serve" subcommands, as well as the
deprecated --generate option, just as the --no-default-folder flag.
2022-01-07 11:19:17 +01:00
André Colomb
368094e15d cmd/syncthing: Always update config.xml with generate subcommand (ref #8090) (#8098)
* cmd/syncthing: Remove unnecessary function arguments.

The openGUI() function does not need a device ID to work, and there is
only one caller anyway which uses EmptyDeviceID.

The loadOrDefaultConfig() function is always called with the same
dummy values.

* cmd/syncthing: Avoid misleading info messages from monitor process.

In order to check whether panic reporting is enabled, the monitor
process utilizes the loadOrDefaultConfig() function.  In case there is
no config file yet, info messages may be logged during creation if the
config Wrapper, which is discarded immediately after.

Stop using the DefaultConfig() utility function from lib/syncthing and
directly generate a minimal config instead to avoid these.

Add comments to loadOrDefaultConfig() explaining its limited purpose.

* cmd/syncthing/generate: Always write updated config file.

Previously, an existing config file was left untouched unless either
of the --gui-user or --gui-password options was given.  Remove that
condition and simplify the checking code.
2022-01-07 11:02:12 +01:00
tomasz1986
0f93e76e80 gui: Use indexOf instead of startsWith for IE11 compatibility (ref #6940) (#8097)
Use indexOf instead of startsWith to make the now translatable theme
names appear correctly in IE11. This also prevents console log error
spam in the browser. The same problem was previously reported in #6940.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-06 12:46:15 +01:00
Kebin Liu
083fa1803a cmd/stdiscosrv: Support deploying behind Caddyserver (#8092) 2022-01-05 15:17:13 +01:00
Simon Frei
c00c6b3957 build: Bump quic-go to 0.24.0 2021-12-30 13:07:01 +01:00
Gahl Saraf
cc39341eb9 lib: Fix panic due to closed event subscriptions on shutdown (#8079) 2021-12-22 20:16:21 +01:00
ignacy123
bf7f82f7b2 cmd/syncthing/cli: Add command to show pending devices/folders (fixes #8068) (#8069) 2021-12-09 21:18:47 +01:00
greatroar
eb857dbc45 lib/osutil: Use x/sys/windows for SetLowPriority 2021-11-27 15:35:07 +01:00
greatroar
e7620e951d cmd/stdiscosrv: use strconv.Itoa 2021-11-27 15:35:07 +01:00
greatroar
286a25ae49 lib/upgrade: Use strings.Reader instead of bytes.Buffer 2021-11-27 15:35:07 +01:00
greatroar
ae70046b49 lib/protocol: Remove unused sorting boilerplate 2021-11-27 15:35:07 +01:00
greatroar
c366933416 lib/sync: Make the clock a function pointer 2021-11-27 15:35:07 +01:00
greatroar
6a9716e8a1 lib/model: Return index from deviceActivity.leastBusy
This way, we don't need a second loop over the Availabilities to remove
the selected item.
2021-11-26 12:07:43 +01:00
villekalliomaki
b84ee4d240 gui: Notice on folders with ignoreDelete enabled (fixes #8050) (#8054) 2021-11-25 14:04:59 +01:00
greatroar
8a1e54d58a lib/fs: Optimize Canonicalize
When pathSep is a constant, the compiler precomputes pathSep+pathSep and
".."+pathSep instead of emitting function calls to compute "//" and
"../". Benchmark results in lib/osutil:

name                old time/op    new time/op    delta
TraversesSymlink-8    8.86µs ± 3%    8.53µs ± 4%  -3.79%  (p=0.000 n=18+20)

name                old alloc/op   new alloc/op   delta
TraversesSymlink-8    1.06kB ± 0%    1.06kB ± 0%    ~     (all equal)

name                old allocs/op  new allocs/op  delta
TraversesSymlink-8      15.0 ± 0%      15.0 ± 0%    ~     (all equal)
2021-11-23 21:25:29 +01:00
greatroar
3e032c4da6 lib/fs: optimize Windows path checking/sanitizing
name                          old time/op    new time/op    delta
WindowsInvalidFilenameValid-8     875ns ± 1%     150ns ± 1%  -82.84%  (p=0.000 n=9+9)
WindowsInvalidFilenameNUL-8       276ns ± 4%     121ns ± 3%  -56.26%  (p=0.000 n=10+10)

name                          old alloc/op   new alloc/op   delta
WindowsInvalidFilenameValid-8     32.0B ± 0%     16.0B ± 0%  -50.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8       32.0B ± 0%     19.0B ± 0%  -40.62%  (p=0.000 n=10+10)

name                          old allocs/op  new allocs/op  delta
WindowsInvalidFilenameValid-8      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8        2.00 ± 0%      2.00 ± 0%     ~     (all equal)
2021-11-23 21:25:29 +01:00
Jakob Borg
7c3b267645 meta: Add test for deprecated package ioutil (#8053) 2021-11-22 10:11:00 +01:00
tomasz1986
7161a99b04 gui: Allow text wrapping in remove folder/device modals (#7976)
Remove the embedded CSS that prevents the lines from wrapping, resulting
in device and folder names being hidden on small screens.
2021-11-22 09:41:43 +01:00
Jakob Borg
1754c93370 lib/config, lib/ignore: Write Windows line endings (fixes #7115) (#8052) 2021-11-22 09:38:24 +01:00
Jakob Borg
4b750b6dc3 all: Remove usage of deprecated io/ioutil (#7971)
As of Go 1.16 io/ioutil is deprecated. This replaces usage with the
corresponding functions in package os and package io.
2021-11-22 08:59:47 +01:00
greatroar
bf89bffb0b lib/config: Decouple VerifyConfiguration from Committer (#7939)
... and remove 8/10 implementations, which were no-ops. This saves code
and time copying configurations.
2021-11-22 08:45:29 +01:00
Jakob Borg
e2288fe441 lib/relay: Send SNI when the address is a host name (fixes #8014) (#8015) 2021-11-22 08:31:03 +01:00
greatroar
8265dac127 lib/nat: Fix race condition in Mapping (#8042)
The locking protocol in nat.Mapping was racy:

* Mapping.addressMap RLock'd, but then returned a map shared between
  caller and Mapping, so the lock didn't do anything.

* Operations inside Service.{verifyExistingMappings,acquireNewMappings}
  would lock the map for every update, but that means callers to
  Mapping.ExternalAddresses can be looping over the map while the
  Service methods are concurrently modifying it. When the Go runtime
  detects that happening, it panics.

* Mapping.expires was read and updated without locking.

The Service methods now lock the map once and release the lock only when
done.

Also, subscribers no longer get the added and removed addresses, because
none of them were using the information. This was changed for a previous
attempt to retain the fine-grained locking and not reverted because it
simplifies the code.
2021-11-22 08:29:44 +01:00
André Colomb
100870e142 cmd/syncthing: Implement generate as a subcommand with optional API credential setting (fixes #8021) (#8043)
Accept a subcommand as an alternative to the --generate option.  It
accepts a custom config directory through either the --home or
--config options, using the default location if neither is given.

Add the options --gui-user and --gui-password to "generate", but not
the "serve --generate" option form.  If either is given, an existing
config will not abort the command, but rather load, modify and save it
with the new credentials.  The password can be read from standard
input by passing only a single dash as argument.

Config modification is skipped if the value matches what's already in
the config.

* cmd/syncthing: Utilize lib/locations package in generate().
Instead of manually joining paths with "magic" file names, get them
from the centralized locations helper lib.

* cmd/syncthing: Simplify logging for --generate option.
Visible change: No more timestamp prefixes.
2021-11-18 22:57:59 +01:00
Jakob Borg
12fb7f2a0a lib/model: Correct "reverting folder" log entry 2021-11-17 12:52:10 +01:00
Jakob Borg
f1bf4d899a lib/model: Correct handling of fakefs cache
We looked under one cache key, then stored under another...
2021-11-17 12:52:10 +01:00
Simon Frei
591e4d8af1 gui, lib: Fix tracking deleted locally-changed on encrypted (fixes #7715) (#7726) 2021-11-10 09:46:21 +01:00
André Colomb
dec6f80d2b lib/config: Move the bcrypt password hashing to GUIConfiguration (#8028)
What hash is used to store the password should ideally be an
implementation detail, so that every user of the GUIConfiguration
object automatically agrees on how to handle it.  That is currently
distribututed over the confighandler.go and api_auth.go files, plus
tests.

Add the SetHasedPassword() / CompareHashedPassword() API to keep the
hashing method encapsulated.  Add a separate test for it and adjust
other users and tests.  Remove all deprecated imports of the bcrypt
package.
2021-11-08 13:32:04 +01:00
André Colomb
ec8a748514 lib/syncthing: Clean up / refactor LoadOrGenerateCertificate() utility function. (#8025)
LoadOrGenerateCertificate() takes two file path arguments, but then
uses the locations package to determine the actual path.  Fix that
with a minimally invasive change, by using the arguments instead.
Factor out GenerateCertificate().

The only caller of this function is cmd/syncthing, which passes the
same values, so this is technically a no-op.

* lib/tlsutil: Make storing generated certificate optional.  Avoid
  temporary cert and key files in tests, keep cert in memory.
2021-11-07 23:59:48 +01:00
greatroar
db15e52743 lib/api: http.Request.BasicAuth instead of custom code (#8039) 2021-11-06 12:38:08 +01:00
André Colomb
41bfb7a330 Normalize CLI options to always use two dashes. (#8037)
Consistently use double dashes and fix typos -conf, -data-dir and
-verify.

Applies also to tests running the syncthing binary for consistency.

* Fix mismatched option name --conf in cli subcommand.

According to the source code comments, the cli option flags should
mirror those from the serve subcommand where applicable.  That one is
actually called --config though.

* cli: Fix help text option placeholders.

The urfave/cli package uses the Value field of StringFlag to provide a
default value, not to name the placeholder.  That is instead done with
backticks around some part of the Usage field.

* cli: Add missing --data flag in subcommand help text.

The urfave/cli based option parsing uses a fake flags collection to
generate help texts matching the used global options.  But the --data
option was omitted from it, although it is definitely required when
using --config as well.  Note that it cannot just be ignored, as some
debug stuff actually uses the DB:

syncthing cli --data=/bar --config=/foo debug index dump
2021-11-04 08:42:55 +01:00
André Colomb
1c2e96a5ca gui: Display identicons for discovered device IDs. (#8022) 2021-10-29 20:23:41 +02:00
greatroar
28ff033da6 cmd/syncthing/cli: indexDumpSize doesn't need a heap (#8024) 2021-10-29 20:21:50 +02:00
greatroar
807a6b1022 lib/model: Optimize jobQueue performance and memory use (#8023)
By truncating time.Time to an int64 nanosecond count, we lose the
ability to precisely order timestamps before 1678 or after 2262, but we
gain (linux/amd64, Go 1.17.1):

name                      old time/op    new time/op    delta
JobQueuePushPopDone10k-8    2.85ms ± 5%    2.29ms ± 2%  -19.80%  (p=0.000 n=20+18)
JobQueueBump-8              34.0µs ± 1%    29.8µs ± 1%  -12.35%  (p=0.000 n=19+19)

name                      old alloc/op   new alloc/op   delta
JobQueuePushPopDone10k-8    2.56MB ± 0%    1.76MB ± 0%  -31.31%  (p=0.000 n=18+13)

name                      old allocs/op  new allocs/op  delta
JobQueuePushPopDone10k-8      23.0 ± 0%      23.0 ± 0%     ~     (all equal)

Results for BenchmarkJobQueueBump are with the fixed version, which no
longer depends on b.N for the amount of work performed. rand.Rand.Intn
is cheap at ~10ns per iteration.
2021-10-29 20:20:46 +02:00
Tomasz Wilczyński
296cc1bca2 lib/model: Limit the number of default hashers on Android (ref #2220)
Like Windows and Mac, Android is also an interactive operating system.
On top of that, it usually runs on much slower hardware than the other
two. Because of that, it makes sense to limit the number of hashes used
by default there too.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-10-29 10:06:52 +02:00
Simon Frei
951b058952 lib/model: Set mod. time after writing trailer in shortcut (ref #7992) 2021-10-24 16:50:30 +02:00
greatroar
8f8e8a9285 lib/protocol: Simplify codeToError, errorToCode
Also be explicit about the fact that ErrNoError is nil. That name isn't
used anywhere outside this file.
2021-10-22 18:40:40 +02:00
greatroar
46082f194c lib/protocol: Eliminate nativeModel on Unix 2021-10-22 18:40:40 +02:00
tomasz1986
cb607e8551 gui: Add direct link to Ignore Patterns from folder panel (fixes #4293) (#7993) 2021-10-20 23:06:03 +02:00
André Colomb
3e3954eb38 gui: Translate theme names in settings (#8006)
Add each subdirectory of the guiDir as a translation candidate string.
The key is prefixed with "theme-name-" and the default English
translation corresponds to the directory name turned to title case.
Disable the automatic name mangling in the GUI JS code in favor of
just looking up the translation.
2021-10-20 19:44:38 +02:00
Simon Frei
517667c590 lib/model: Pull when a new connection is established (fixes #8012) (#8013) 2021-10-20 18:55:22 +02:00
Jakob Borg
36c044562c gui, man, authors: Update docs, translations, and contributors 2021-10-20 07:45:29 +02:00
Jakob Borg
f760ef15b0 gui, man, authors: Update docs, translations, and contributors 2021-10-13 07:45:24 +02:00
Max
e557ba82e7 build: Fix error in Debian install scripts preventing restarts for stdiscosrv + strelaysrv (#8001) 2021-10-09 20:33:14 +02:00
greatroar
7c292cc812 lib/connections: Fix and optimize registry (#7996)
Registry.Get used a full sort to get the minimum of a list, and the sort
was broken because util.AddressUnspecifiedLess assumed it could find out
whether an address is IPv4 or IPv6 from its Network method. However,
net.(TCP|UDP)Addr.Network always returns "tcp"/"udp".
2021-10-06 10:52:51 +02:00
Simon Frei
c94b797f00 lib/protocol: Preserve sequence decrypting fileinfos (fixes #7994) (#7995) 2021-10-06 10:26:54 +02:00
Jakob Borg
4e513b8393 gui, man, authors: Update docs, translations, and contributors 2021-10-06 07:45:42 +02:00
Simon Frei
708a5c2070 lib/model: Write trailer when shortcutting on recv-enc (fixes #7991) (#7992) 2021-10-05 11:23:27 +02:00
Jakob Borg
92eaf52c21 lib/protocol: Test to lock down encryption key derivation
So that we don't inadvertently change how these things work.
2021-10-04 14:36:28 +02:00
tomasz1986
b75d083035 gui: Use case insensitive sort with folders on top in Restore Versions (#7980)
Currently, the default sorting of the file list in the Restore Versions
modal in both case sensitive, and it also does not distinguish between
files and folders. With this change, which uses a slightly modified code
from the fancytree itself (with added folder prioritisation), the sort
becomes case insensitive and also always places folders on top. This is
to make it behave more similar to what file managers do in the commonly
used operating systems (including popular Linux desktop environments).

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-29 08:05:01 +02:00
Jakob Borg
b0460079c1 gui, man, authors: Update docs, translations, and contributors 2021-09-29 07:45:32 +02:00
tomasz1986
e20d4e192d Revert "gui: Allow to resize command in External Versioning (#7410)" (#7978)
This reverts commit cca17f5306.

Using textarea instead of input makes it possible to enter new lines,
which then are added to config.xml as "&#xA;". This breaks the whole
script, because these characters are passed to the command line as "\n".
Therefore, the script should rather remain a single-lined input field.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-28 08:05:18 +02:00
tomasz1986
8d8f331a4a lib/config: Always set mtime window to 2 on Android unless ext detected (ref #7963) (#7966)
The current detection is flawed, because it looks for a few specific
file systems like "msdos" or "fat" to set the mtime window, while in
reality Android seems to report names like "fuseblk", which can stand
for fat, ext4, or even f2fs.

At the moment, we set the mtime window only for a few known names used
for the fat filesystem. With this change, we take a safer approach of
always setting the time window unless we explicitly detect file systems
like ext2/ext3/ex4, which are known not to experience issues with moving
timestamps on Android.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-27 21:29:51 +02:00
tomasz1986
793035de61 gui: Fix jumping nav tabs in black and dark themes (#7977) 2021-09-27 21:28:14 +02:00
greatroar
198028d627 lib/rand: Optimizations (#7964)
rand.secureSource.Uint64 no longer allocates. rand.String uses a
strings.Builder. Benchmark results on linux/amd64:

name            old time/op    new time/op    delta
SecureSource-8    69.1ns ± 3%    51.7ns ± 3%   -25.21%  (p=0.000 n=20+10)
String-8          2.66µs ± 2%    1.95µs ± 1%   -26.61%  (p=0.000 n=10+10)

name            old alloc/op   new alloc/op   delta
SecureSource-8     8.00B ± 0%     0.00B       -100.00%  (p=0.000 n=20+10)
String-8            288B ± 0%       32B ± 0%   -88.89%  (p=0.000 n=10+10)

name            old allocs/op  new allocs/op  delta
SecureSource-8      1.00 ± 0%      0.00       -100.00%  (p=0.000 n=20+10)
String-8            33.0 ± 0%       1.0 ± 0%   -96.97%  (p=0.000 n=10+10)
2021-09-26 12:15:39 +02:00
Jakob Borg
c5ec6cd7ef build: Fix deepsource test & exclude patterns (#7969) 2021-09-26 12:08:59 +02:00
Jakob Borg
73c5184518 build: Update all dependencies (#7968)
Also add a script step for how to do this, as frankly I forget each time
what the canonical way is.

`go run build.go update-deps`
2021-09-26 12:08:23 +02:00
greatroar
f96c211198 lib/db: Replace SipHash with hash/maphash (#7962) 2021-09-24 21:26:07 +02:00
Jayachithra
6d2489a562 gui: Removed superfluous quotes (fixes #7853) (#7961)
Co-authored-by: Jaya Kumar <jaya.kumar@ict.nl>
2021-09-23 23:38:06 +02:00
Jakob Borg
fa05a1ba8c gui, man, authors: Update docs, translations, and contributors 2021-09-22 07:45:31 +02:00
greatroar
a4489dec30 lib/tlsutil: Allocate UnionedConnection in one go (#7912) 2021-09-21 08:40:34 +02:00
Jakob Borg
30e5243f5e build: Update go-ole for Windows/arm 2021-09-17 17:10:32 +02:00
Ross Smith II
06998b3484 build: Add -arm flag to goversioninfo (#7947) 2021-09-17 17:07:32 +02:00
Jakob Borg
3c66d93aba gui, man, authors: Update docs, translations, and contributors 2021-09-15 07:45:29 +02:00
André Colomb
a5792f3c42 gui: Sort already shared devices in edit folder modal (fixes #7940) (#7945)
The list of unshared devices is built from deviceList(), which sorts
the result.  But the shared devices are listed in undefined order from
the unsorted currentFolder.devices array.  Apply the same sorting
after building the array used in the dialog.
2021-09-13 20:41:15 +02:00
Simon Frei
721cd740d8 lib/model: Don't reset db while folder is running (fixes #7935) (#7936) 2021-09-11 17:14:47 +02:00
greatroar
de719ac409 lib/db: Inline sync.Once in releaser (#7938)
Having a pointer to a Once suggests that it is shared with other
objects, but it never is.
2021-09-10 09:58:17 +02:00
jtagcat
0ffa7f3f57 all: Clarify 'Cleaning data for folder' log message (#7937)
Instead of data (could be read as user data), use metadata.
2021-09-10 09:56:44 +02:00
Jakob Borg
4868d347db gui, man, authors: Update docs, translations, and contributors 2021-09-08 07:45:36 +02:00
greatroar
7fa141ea39 all: Unused args, retvals, assignments (#7926) 2021-09-08 00:11:16 +02:00
greatroar
13196ddd92 lib/relay/protocol: Merge two Sprintf calls 2021-09-06 15:30:56 +02:00
greatroar
eafb40460d lib/discover, lib/protocol: Buffer allocation 2021-09-06 15:30:56 +02:00
Simon Frei
4e2a9bb139 lib/model: Remove encryption pw on folder stop (#7925) 2021-09-03 09:54:47 +02:00
greatroar
3b2239357f lib/model: Add missing error assignment + Remove unused argument (#7922) 2021-09-01 22:03:06 +02:00
tomasz1986
7be1f0a71c gui: Move dismiss button after add/ignore buttons (#7848)
Currently, the dismiss button is displayed as the first of the three
buttons. However, the most common action that the user wants to do when
sharing a new folder is to add it on a different device. Because of
this, the add button should be displayed first as the most prominent of
the three. The ignore button is the opposite of the add button, and also
results in a parmenent action, hence it makes sense to lump the two
together. Thus, the dismiss button should be moved to the last place as
an alternative to the two main actions, when the user is yet unsure what
they want to do with the notification.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-01 21:59:47 +02:00
Jakob Borg
96f5a11fd5 gui, man, authors: Update docs, translations, and contributors 2021-09-01 07:45:32 +02:00
Ross Smith II
7501bee430 lib/model: Typo in folder_recvonly.go (#7919) 2021-09-01 07:41:18 +02:00
jtagcat
445c5f13c3 readme: Add a link to docs source (#7909) 2021-08-29 22:32:46 +02:00
greatroar
ed98039aa5 lib/fs: Optimize TempName + some cosmetic changes (#7911) 2021-08-29 10:47:53 +02:00
Jakob Borg
2816780b52 lib/api: Set "Secure" on session cookies served over HTTPS (ref #7399) (#7907)
So that it does not unnecessarily leak over clear text connections.
2021-08-27 17:56:54 +02:00
Jakob Borg
c76bd7dcc4 gui, man, authors: Update docs, translations, and contributors 2021-08-25 07:45:41 +02:00
xjtdy888
48796a1b60 lib/ur: Fix panic build goroutines for failures (#7903) 2021-08-25 07:16:55 +02:00
Simon Frei
5711bacd83 build: Readd systemd files to deb releases (ref #7564) (#7899) 2021-08-22 20:04:47 +02:00
Simon Frei
70a840d3d5 lib/connections: Remove future go build constraints on quic (#7898) 2021-08-19 21:05:28 +02:00
Benjamin Nater
37df662325 build: Update x/sys to fix new issue in go 1.17 2021-08-19 20:38:14 +02:00
Jakob Borg
ca908270ec gui, man, authors: Update docs, translations, and contributors 2021-08-18 07:45:38 +02:00
Jakob Borg
d47745a86b all: Update build constraints to Go 1.17 style (#7894) 2021-08-17 10:10:41 +02:00
Jakob Borg
8c94ce8d14 build: Simplify gem command in Debian Docker image 2021-08-17 09:38:42 +02:00
Simon Frei
0fe72e6fc5 lib/model: Schedule pull after revert on recv-enc (#7892) 2021-08-17 09:24:10 +02:00
Simon Frei
c025e76f30 lib/model: Do not wait for scan when setting ignores (fixes #7893) (#7891) 2021-08-17 09:23:33 +02:00
Simon Frei
e1bf1e672e lib/ur: Fix panic getting goroutines for failures (ref #7785) (#7890) 2021-08-16 22:47:05 +02:00
tomasz1986
a5bbb500e6 gui: Use large modals for Listeners and Discovery (#7884) 2021-08-13 20:09:10 +02:00
Jakob Borg
a615f868a5 gui, man, authors: Update docs, translations, and contributors 2021-08-11 07:45:33 +02:00
Simon Frei
db302b15ea lib/syncthing: Set system timezone on android (#7878) 2021-08-09 09:27:14 +02:00
Simon Frei
952f3ffb0c lib/db/backend: Prevent panic in errors.As (#7873) 2021-08-05 11:25:20 +01:00
Audrius Butkevicius
fe77fac23f Update quic to 0.22.0 to support RFC9000, enable batch reads (#7862)
* Update quic to 0.22.0 to support RFC9000, enable batch reads
* Remove wrappers that are not needed anymore
2021-08-05 05:44:22 +02:00
Simon Frei
e61091d240 lib/stun: Prevent nil deref when naming service (#7872) 2021-08-05 00:04:22 +01:00
Simon Frei
50aacdf1f0 lib/protocol: Ensure correct blocksize on enc. fileinfo (ref #7861) (#7870) 2021-08-04 23:12:01 +02:00
Simon Frei
e56e8b7aa1 lib/model: Don't consider hashes pulling on recv-enc (#7869) 2021-08-04 11:10:10 +02:00
Jakob Borg
6d0816e85a gui, man, authors: Update docs, translations, and contributors 2021-08-04 07:45:31 +02:00
tomasz1986
abdf024517 gui: Improve revert/override/delete warning modals (#7847)
1. Change each modal title text to match the action that is being
   executed (i.e. "Revert" to "Revert Local Additions", "Override" to
   "Override Changes", "Delete" to "Delete Unexpected Items").
2. Change the icons to match the icons used by each action (i.e. arrow-
   circle-down for Revert, arrow-circle-up for Override). Replace the
   broken lock icon for Delete with minus-circle.
3. Rearrange the order in the modal HTML code to simplify it a little.
2021-08-03 10:46:20 +01:00
tomasz1986
5a1f6cb813 lib/fs: Improve case conflict error message (fixes #7827) (#7829) 2021-08-01 22:44:49 +02:00
greatroar
37d0ba1660 lib/watchaggregator: Replace counter map by two integers (#7856) 2021-08-01 12:30:20 +02:00
Simon Frei
734c2fc870 Merge branch 'release' 2021-07-30 14:46:20 +02:00
Jonathan
490ec4350c lib/model: Fix config deadlock when deleting a paused folder (#7854) 2021-07-30 14:41:57 +02:00
Jonathan
0836439256 lib/model: Fix config deadlock when deleting a paused folder (#7854) 2021-07-30 14:41:00 +02:00
Jakob Borg
b197b698a4 gui, man, authors: Update docs, translations, and contributors 2021-07-28 07:45:33 +02:00
Simon Frei
67b18569cf all: Send deadlocks as failures, crash only as a last resort (#7785) 2021-07-27 21:27:52 +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
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
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
577 changed files with 45321 additions and 25251 deletions

View File

@@ -1,7 +1,7 @@
version = 1
exclude_patterns = ["*.pb.go"]
test_patterns = ["*_test.go"]
exclude_patterns = ["**/*.pb.go"]
test_patterns = ["**/*_test.go"]
[[analyzers]]
name = "go"

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

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

725
.github/workflows/build-syncthing.yaml vendored Normal file
View File

@@ -0,0 +1,725 @@
name: Build Syncthing
on:
pull_request:
push:
env:
# The go version to use for builds. We set check-latest to true when
# installing, so we get the latest patch version that matches the
# expression.
GO_VERSION: "^1.20.3"
# Optimize compatibility on the slow archictures.
GO386: softfloat
GOARM: "5"
GOMIPS: softfloat
# Avoid hilarious amounts of obscuring log output when running tests.
LOGGER_DISCARD: "1"
# Our build metadata
BUILD_USER: builder
BUILD_HOST: github.syncthing.net
# A note on actions and third party code... The actions under actions/ (like
# `uses: actions/checkout`) are maintained by GitHub, and we need to trust
# GitHub to maintain their code and infrastructure or we're in deep shit in
# general. The same doesn't necessarily apply to other actions authors, so
# some care needs to be taken when adding steps, especially in the paths
# that lead up to code being packaged and signed.
jobs:
#
# Tests for all platforms. Runs a matrix build on Windows, Linux and Mac,
# with the list of expected supported Go versions (current, previous).
#
build-test:
name: Build and test
strategy:
fail-fast: false
matrix:
runner: ["windows-latest", "ubuntu-latest", "macos-latest"]
# The oldest version in this list should match what we have in our go.mod.
# Variables don't seem to be supported here, or we could have done something nice.
go: ["1.19", "1.20"]
runs-on: ${{ matrix.runner }}
steps:
- name: Set git to use LF
if: matrix.runner == 'windows-latest'
# Without this, the Windows checkout will happen with CRLF line
# endings, which is fine for the source code but messes up tests
# that depend on data on disk being as expected. Ideally, those
# tests should be fixed, but not today.
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
cache: true
check-latest: true
- name: Build
run: |
go run build.go
- name: Test
run: |
go run build.go test
#
# Meta checks for formatting, copyright, etc
#
correctness:
name: Check correctness
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Check correctness
run: |
go test -v ./meta
#
# The basic checks job is a virtual one that depends on the matrix tests,
# the correctness checks, and various builds that we always do. This makes
# it easy to have the PR process have a single test as a gatekeeper for
# merging, instead of having to add all the matrix tests and update them
# each time the version changes. (The top level test is not available for
# choosing there, only the matrix "children".)
#
basics:
name: Basic checks passed
runs-on: ubuntu-latest
needs:
- build-test
- correctness
- package-linux
- package-cross
- package-source
- package-debian
steps:
- uses: actions/checkout@v3
#
# Windows
#
package-windows:
name: Package for Windows
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
runs-on: windows-latest
steps:
- name: Set git to use LF
# Without this, the checkout will happen with CRLF line endings,
# which is fine for the source code but messes up tests that depend
# on data on disk being as expected. Ideally, those tests should be
# fixed, but not today.
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
- name: Install dependencies
run: |
go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.4.0
- name: Create packages
run: |
go run build.go -goarch amd64 zip
go run build.go -goarch arm zip
go run build.go -goarch arm64 zip
go run build.go -goarch 386 zip
env:
CGO_ENABLED: "0"
CODESIGN_SIGNTOOL: ${{ secrets.CODESIGN_SIGNTOOL }}
CODESIGN_CERTIFICATE_BASE64: ${{ secrets.CODESIGN_CERTIFICATE_BASE64 }}
CODESIGN_CERTIFICATE_PASSWORD: ${{ secrets.CODESIGN_CERTIFICATE_PASSWORD }}
CODESIGN_TIMESTAMP_SERVER: ${{ secrets.CODESIGN_TIMESTAMP_SERVER }}
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-windows
path: syncthing-windows-*.zip
#
# Linux
#
package-linux:
name: Package for Linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
- name: Create packages
run: |
archs=$(go tool dist list | grep linux | sed 's#linux/##')
for goarch in $archs ; do
go run build.go -goarch "$goarch" tar
done
env:
CGO_ENABLED: "0"
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-linux
path: syncthing-linux-*.tar.gz
#
# macOS
#
package-macos:
name: Package for macOS
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
- name: Import signing certificate
run: |
# Set up a run-specific keychain, making it available for the
# `codesign` tool.
umask 066
KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain
KEYCHAIN_PASSWORD=$(uuidgen)
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security default-keychain -s "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
# Import the certificate
CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12
echo "$DEVELOPER_ID_CERTIFICATE_BASE64" | base64 -d -o "$CERTIFICATE_PATH"
security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_PATH" -P "$DEVELOPER_ID_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign
security set-key-partition-list -S apple-tool:,apple: -s -k actions "$KEYCHAIN_PATH"
# Set the codesign identity for following steps
echo "CODESIGN_IDENTITY=$CODESIGN_IDENTITY" >> $GITHUB_ENV
env:
DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.DEVELOPER_ID_CERTIFICATE_BASE64 }}
DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.DEVELOPER_ID_CERTIFICATE_PASSWORD }}
CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}
- name: Create package (amd64)
run: |
go run build.go -goarch amd64 zip
env:
CGO_ENABLED: "1"
- name: Create package (arm64 cross)
run: |
cat <<EOT > xgo.sh
#!/bin/bash
CGO_ENABLED=1 \
CGO_CFLAGS="-target arm64-apple-macos10.15" \
CGO_LDFLAGS="-target arm64-apple-macos10.15" \
go "\$@"
EOT
chmod 755 xgo.sh
go run build.go -gocmd ./xgo.sh -goarch arm64 zip
env:
CGO_ENABLED: "1"
- name: Create package (universal)
run: |
rm -rf _tmp
mkdir _tmp
pushd _tmp
unzip ../syncthing-macos-amd64-*.zip
unzip ../syncthing-macos-arm64-*.zip
lipo -create syncthing-macos-amd64-*/syncthing syncthing-macos-arm64-*/syncthing -o syncthing
amd64=(syncthing-macos-amd64-*)
universal="${amd64/amd64/universal}"
mv "$amd64" "$universal"
mv syncthing "$universal"
zip -r "../$universal.zip" "$universal"
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-macos
path: syncthing-*.zip
notarize-macos:
name: Notarize for macOS
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
needs:
- package-macos
- basics
runs-on: macos-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: packages-macos
- name: Notarize binaries
run: |
APPSTORECONNECT_API_KEY_PATH="$RUNNER_TEMP/apikey.p8"
echo "$APPSTORECONNECT_API_KEY" | base64 -d -o "$APPSTORECONNECT_API_KEY_PATH"
for file in syncthing-macos-*.zip ; do
xcrun notarytool submit \
-k "$APPSTORECONNECT_API_KEY_PATH" \
-d "$APPSTORECONNECT_API_KEY_ID" \
-i "$APPSTORECONNECT_API_KEY_ISSUER" \
$file
done
env:
APPSTORECONNECT_API_KEY: ${{ secrets.APPSTORECONNECT_API_KEY }}
APPSTORECONNECT_API_KEY_ID: ${{ secrets.APPSTORECONNECT_API_KEY_ID }}
APPSTORECONNECT_API_KEY_ISSUER: ${{ secrets.APPSTORECONNECT_API_KEY_ISSUER }}
#
# Cross compile other unixes
#
package-cross:
name: Package cross compiled
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-cross-${{ hashFiles('**/go.sum') }}
- name: Create packages
run: |
platforms=$(go tool dist list \
| grep -v aix/ppc64 \
| grep -v android/ \
| grep -v darwin/ \
| grep -v ios/ \
| grep -v js/ \
| grep -v linux/ \
| grep -v nacl/ \
| grep -v plan9/ \
| grep -v windows/ \
)
for plat in $platforms; do
goos="${plat%/*}"
goarch="${plat#*/}"
if ! go run build.go -goos "$goos" -goarch "$goarch" tar ; then
echo "*** $plat failed ***"
fi
done
env:
CGO_ENABLED: "0"
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-other
path: syncthing-*.tar.gz
#
# Source
#
package-source:
name: Package source code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Package source
run: |
version=$(go run build.go version)
echo "$version" > RELEASE
go mod vendor
go run build.go assets
cd ..
tar c -z -f "syncthing-source-$version.tar.gz" \
--exclude .git \
syncthing
mv "syncthing-source-$version.tar.gz" syncthing
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-source
path: syncthing-source-*.tar.gz
#
# Sign binaries for auto upgrade, generate ASC signature files
#
sign-for-upgrade:
name: Sign for upgrade
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
needs:
- basics
- package-windows
- package-linux
- package-macos
- package-cross
- package-source
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/checkout@v3
with:
repository: syncthing/release-tools
path: tools
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Install signing tool
run: |
go install ./cmd/stsigtool
- name: Sign archives
run: |
export PRIVATE_KEY="$RUNNER_TEMP/privkey.pem"
export PATH="$PATH:$(go env GOPATH)/bin"
echo "$STSIGTOOL_PRIVATE_KEY" | base64 -d > "$PRIVATE_KEY"
mkdir packages
mv packages-*/* packages
pushd packages
"$GITHUB_WORKSPACE/tools/sign-only"
rm -f "$PRIVATE_KEY"
env:
STSIGTOOL_PRIVATE_KEY: ${{ secrets.STSIGTOOL_PRIVATE_KEY }}
- name: Create and sign .asc files
run: |
sudo apt update
sudo apt -y install gnupg
export SIGNING_KEY="$RUNNER_TEMP/gpg-secret.asc"
echo "$GNUPG_SIGNING_KEY_BASE64" | base64 -d > "$SIGNING_KEY"
gpg --import < "$SIGNING_KEY"
pushd packages
files=(*.tar.gz *.zip)
sha1sum "${files[@]}" | gpg --clearsign > sha1sum.txt.asc
sha256sum "${files[@]}" | gpg --clearsign > sha256sum.txt.asc
gpg --sign --armour --detach syncthing-source-*.tar.gz
popd
rm -f "$SIGNING_KEY" .gnupg
env:
GNUPG_SIGNING_KEY_BASE64: ${{ secrets.GNUPG_SIGNING_KEY_BASE64 }}
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-signed
path: packages/*
#
# Debian
#
package-debian:
name: Package for Debian
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
- name: Install fpm
run: |
gem install fpm
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-debian-${{ hashFiles('**/go.sum') }}
- name: Package for Debian
run: |
for arch in amd64 i386 armhf armel arm64 ; do
go run build.go -no-upgrade -installsuffix=no-upgrade -goarch "$arch" deb
done
env:
BUILD_USER: debian
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: debian-packages
path: "*.deb"
#
# Nightlies
#
publish-nightly:
name: Publish nightly build
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-nightly')
environment: signing
needs:
- sign-for-upgrade
- notarize-macos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
repository: syncthing/release-tools
path: tools
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: packages-signed
path: packages
- name: Create release json
run: |
cd packages
"$GITHUB_WORKSPACE/tools/generate-release-json" "$BASE_URL" > nightly.json
env:
BASE_URL: https://syncthing.ams3.digitaloceanspaces.com/nightly/
- name: Push artifacts
uses: docker://docker.io/rclone/rclone:latest
env:
RCLONE_CONFIG_SPACES_TYPE: s3
RCLONE_CONFIG_SPACES_PROVIDER: DigitalOcean
RCLONE_CONFIG_SPACES_ACCESS_KEY_ID: ${{ secrets.SPACES_KEY }}
RCLONE_CONFIG_SPACES_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET }}
RCLONE_CONFIG_SPACES_ENDPOINT: ams3.digitaloceanspaces.com
RCLONE_CONFIG_SPACES_ACL: public-read
with:
args: sync packages spaces:syncthing/nightly
#
# Push release artifacts to Spaces
#
publish-release-files:
name: Publish release files
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release')
environment: signing
needs:
- sign-for-upgrade
- package-debian
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Download signed packages
uses: actions/download-artifact@v3
with:
name: packages-signed
path: packages
- name: Download debian packages
uses: actions/download-artifact@v3
with:
name: debian-packages
path: packages
- name: Set version
run: |
version=$(go run build.go version)
echo "VERSION=$version" >> $GITHUB_ENV
- name: Push to Spaces
uses: docker://docker.io/rclone/rclone:latest
env:
RCLONE_CONFIG_SPACES_TYPE: s3
RCLONE_CONFIG_SPACES_PROVIDER: DigitalOcean
RCLONE_CONFIG_SPACES_ACCESS_KEY_ID: ${{ secrets.SPACES_KEY }}
RCLONE_CONFIG_SPACES_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET }}
RCLONE_CONFIG_SPACES_ENDPOINT: ams3.digitaloceanspaces.com
RCLONE_CONFIG_SPACES_ACL: public-read
with:
args: sync packages spaces:syncthing/release/${{ env.VERSION }}
docker-syncthing:
name: Build and push Docker images
runs-on: ubuntu-latest
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-'))
environment: docker
strategy:
matrix:
pkg:
- syncthing
- strelaysrv
- stdiscosrv
include:
- pkg: syncthing
dockerfile: Dockerfile
- pkg: strelaysrv
dockerfile: Dockerfile.strelaysrv
- pkg: stdiscosrv
dockerfile: Dockerfile.stdiscosrv
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }}
- name: Build binaries
run: |
for arch in arm64 amd64; do
go run build.go -goos linux -goarch "$arch" -no-upgrade build ${{ matrix.pkg }}
mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-"$arch"
done
env:
CGO_ENABLED: "0"
BUILD_USER: docker
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Set version tags
run: |
version=$(go run build.go version)
version=${version#v}
if [[ $version == @([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]) ]] ; then
echo Release version, pushing to :latest and version tags
major=${version%.*.*}
minor=${version%.*}
tags=syncthing/${{ matrix.pkg }}:$version,syncthing/${{ matrix.pkg }}:$major,syncthing/${{ matrix.pkg }}:$minor,syncthing/${{ matrix.pkg }}:latest
elif [[ $version == *-rc.@([0-9]|[0-9][0-9]) ]] ; then
echo Release candidate, pushing to :rc
tags=syncthing/${{ matrix.pkg }}:rc
else
echo Development version, pushing to :edge
tags=syncthing/${{ matrix.pkg }}:edge
fi
echo "DOCKER_TAGS=$tags" >> $GITHUB_ENV
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.DOCKER_TAGS }}

21
.github/workflows/trigger-nightly.yaml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Trigger nightly build & release
on:
workflow_dispatch:
schedule:
# Run nightly build at 01:00 UTC
- cron: '00 01 * * *'
jobs:
trigger-nightly:
runs-on: ubuntu-latest
name: Push to release-nightly to trigger build
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
fetch-depth: 0
- run: |
git push origin main:release-nightly

View File

@@ -0,0 +1,28 @@
name: Update translations and documentation
on:
workflow_dispatch:
schedule:
- cron: '42 3 * * 1'
jobs:
update_transifex_docs:
runs-on: ubuntu-latest
name: Update translations and documentation
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
- uses: actions/setup-go@v4
with:
go-version: ^1.19.6
- run: |
set -euo pipefail
git config --global user.name 'Syncthing Release Automation'
git config --global user.email 'release@syncthing.net'
bash build.sh translate
bash build.sh prerelease
git push
env:
WEBLATE_TOKEN: ${{ secrets.WEBLATE_TOKEN }}

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@ deb
/repos
/proto/scripts/protoc-gen-gosyncthing
/gui/next-gen-gui
.idea

4
.yamlfmt Normal file
View File

@@ -0,0 +1,4 @@
line_ending: lf
formatter:
type: basic
retain_line_breaks: true

55
AUTHORS
View File

@@ -18,24 +18,32 @@ Adam Piggott (ProactiveServices) <aD@simplypeachy.co.uk> <simplypeachy@users.nor
Adel Qalieh (adelq) <aqalieh95@gmail.com> <adelq@users.noreply.github.com>
Alan Pope <alan@popey.com>
Alberto Donato <albertodonato@users.noreply.github.com>
Aleksey Vasenev <margtu-fivt@ya.ru>
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>
Alexander Seiler <seileralex@gmail.com>
Alexandre Alves <alexandrealvesdb.contact@gmail.com>
Alexandre Viau (aviau) <alexandre@alexandreviau.net> <aviau@debian.org>
Aman Gupta <aman@tmm1.net>
Anderson Mesquita (andersonvom) <andersonvom@gmail.com>
Andreas Sommer <andreas.sommer87@googlemail.com>
andresvia <andres.via@gmail.com>
Andrew Dunham (andrew-d) <andrew@du.nham.ca>
Andrew Meyer <andrewm.bpi@gmail.com>
Andrew Rabert (nvllsvm) <ar@nullsum.net> <6550543+nvllsvm@users.noreply.github.com>
Andrey D (scienmind) <scintertech@cryptolab.net> <scienmind@users.noreply.github.com>
André Colomb (acolomb) <src@andre.colomb.de> <github.com@andre.colomb.de>
andyleap <andyleap@gmail.com>
Anjan Momi <anjan@momi.ca>
Anthony Goeckner <agoeckner@users.noreply.github.com>
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>
Aroun <login@b-vo.fr>
Arthur Axel fREW Schmidt (frioux) <frew@afoolishmanifesto.com> <frioux@gmail.com>
Artur Zubilewicz <AkaZecik@users.noreply.github.com>
Audrius Butkevicius (AudriusButkevicius) <audrius.butkevicius@gmail.com> <github@audrius.rocks>
@@ -48,6 +56,7 @@ Ben Shepherd (benshep) <bjashepherd@gmail.com>
Ben Sidhom (bsidhom) <bsidhom@gmail.com>
Benedikt Heine (bebehei) <bebe@bebehei.de>
Benedikt Morbach <benedikt.morbach@googlemail.com>
Benjamin Nater <17193640+bn4t@users.noreply.github.com>
Benno Fünfstück <benno.fuenfstueck@gmail.com>
Benny Ng (tpng) <benny.tpng@gmail.com>
boomsquared <54829195+boomsquared@users.noreply.github.com>
@@ -62,6 +71,7 @@ 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>
@@ -70,9 +80,11 @@ 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>
cui fliter <imcusg@gmail.com>
Cyprien Devillez <cypx@users.noreply.github.com>
Dale Visser <dale.visser@live.com>
Dan <benda.daniel@gmail.com>
Daniel Barczyk <46358936+DanielBarczyk@users.noreply.github.com>
Daniel Bergmann (brgmnn) <dan.arne.bergmann@gmail.com> <brgmnn@users.noreply.github.com>
Daniel Harte (norgeous) <daniel@harte.me> <daniel@danielharte.co.uk> <norgeous@users.noreply.github.com>
Daniel Martí (mvdan) <mvdan@mvdan.cc>
@@ -82,30 +94,40 @@ deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.c
Denis A. (dva) <denisva@gmail.com>
Dennis Wilson (snnd) <dw@risu.io>
dependabot-preview[bot] <dependabot-preview[bot]@users.noreply.github.com> <27856297+dependabot-preview[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <49699333+dependabot[bot]@users.noreply.github.com>
derekriemer <derek.riemer@colorado.edu>
desbma <desbma@users.noreply.github.com>
Devon G. Redekopp <devon@redekopp.com>
Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com>
Dmitry Saveliev (dsaveliev) <d.e.saveliev@gmail.com>
Domenic Horner <domenic@tgxn.net>
Dominik Heidler (asdil12) <dominik@heidler.eu>
Elias Jarlebring (jarlebring) <jarlebring@gmail.com>
Elliot Huffman <thelich2@gmail.com>
Emil Hessman (ceh) <emil@hessman.se>
Eng Zer Jun <engzerjun@gmail.com>
entity0xfe <109791748+entity0xfe@users.noreply.github.com> <entity0xfe@my.domain>
Eric Lesiuta <elesiuta@gmail.com>
Eric P <eric@kastelo.net>
Erik Meitner (WSGCSysadmin) <e.meitner@willystreet.coop>
Evan Spensley <94762716+0evan@users.noreply.github.com>
Evgeny Kuznetsov <evgeny@kuznetsov.md>
Federico Castagnini (facastagnini) <federico.castagnini@gmail.com>
Felix <53702818+f-eliks@users.noreply.github.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> <gahl@raftt.io>
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>
Greg <gco@jazzhaiku.com>
guangwu <guoguangwu@magic-shield.com>
Han Boetes <han@boetes.org>
HansK-p <42314815+HansK-p@users.noreply.github.com>
Harrison Jones (harrisonhjones) <harrisonhjones@users.noreply.github.com>
@@ -113,6 +135,8 @@ 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>
ignacy123 <ignacy.buczek@onet.pl>
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>
@@ -121,12 +145,16 @@ 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 O'Beirne <wild-github@au92.org>
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>
Jauder Ho <jauderho@users.noreply.github.com>
Jaya Chithra (jayachithra) <s.k.jayachithra@gmail.com>
Jaya Kumar <jaya.kumar@ict.nl>
Jeffery To <jeffery.to@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>
@@ -136,14 +164,17 @@ 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 <artback@protonmail.com> <jonagn@gmail.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> <git-12dbd862@jtag.cat>
Jörg Thalheim <Mic92@users.noreply.github.com>
Jędrzej Kula <kula.jedrek@gmail.com>
K.B.Dharun Krishna <kbdharunkrishna@gmail.com>
Kalle Laine <pahakalle@protonmail.com>
Karol Różycki (krozycki) <rozycki.karol@gmail.com>
Kebin Liu <lkebin@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>
@@ -160,7 +191,9 @@ Leo Arias (elopio) <yo@elopio.net>
Liu Siyuan (liusy182) <liusy182@gmail.com> <liusy182@hotmail.com>
Lode Hoste (Zillode) <zillode@zillode.be>
Lord Landon Agahnim (LordLandon) <lordlandon@gmail.com>
LSmithx2 <42276854+lsmithx2@users.noreply.github.com>
Lukas Lihotzki <lukas@lihotzki.de>
luzpaz <luzpaz@users.noreply.github.com>
Majed Abdulaziz (majedev) <majed.alhajry@gmail.com>
Marc Laporte (marclaporte) <marc@marclaporte.com> <marc@laporte.name>
Marc Pujol (kilburn) <kilburn@la3.org>
@@ -169,6 +202,7 @@ marco-m <marco.molteni@laposte.net>
Marcus Legendre <marcus.legendre@gmail.com>
Mario Majila <mariustshipichik@gmail.com>
Mark Pulford (mpx) <mark@kyne.com.au>
Martchus <martchus@gmx.net>
Mateusz Naściszewski (mateon1) <matin1111@wp.pl>
Mateusz Ż <thedead4fun@live.com>
Matic Potočnik <hairyfotr@gmail.com>
@@ -176,6 +210,7 @@ Matt Burke (burkemw3) <mburke@amplify.com> <burkemw3@gmail.com>
Matt Robenolt <matt@ydekproductions.com>
Matteo Ruina <matteo.ruina@gmail.com>
Maurizio Tomasi <ziotom78@gmail.com>
Max <github@germancoding.com>
Max Schulze (kralo) <max.schulze@online.de> <kralo@users.noreply.github.com>
MaximAL <almaximal@ya.ru>
Maxime Thirouin <m@moox.io>
@@ -191,7 +226,9 @@ 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>
Naveen <172697+naveensrinivasan@users.noreply.github.com>
Nicholas Rishel (PrototypeNM1) <rishel.nick@gmail.com> <PrototypeNM1@users.noreply.github.com>
Nick Busey <NickBusey@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>
@@ -203,6 +240,7 @@ NoLooseEnds <jon.koslung@gmail.com>
Oliver Freyermuth <o.freyermuth@googlemail.com>
otbutz <tbutz@optitool.de>
Otiel <Otiel@users.noreply.github.com>
overkill <22098433+0verk1ll@users.noreply.github.com>
Oyebanji Jacob Mayowa <oyebanji05@gmail.com>
Pablo <pbaeyens31+github@gmail.com>
Pascal Jungblut (pascalj) <github@pascalj.com> <mail@pascal-jungblut.com>
@@ -223,6 +261,7 @@ 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>
red_led <red-led@users.noreply.github.com>
Richard Hartmann <RichiH@users.noreply.github.com>
Robert Carosi (nov1n) <robert@carosi.nl>
Roberto Santalla <roobre@users.noreply.github.com>
@@ -231,11 +270,13 @@ Roman Zaynetdinov (zaynetro) <romanznet@gmail.com>
Ross Smith II (rasa) <ross@smithii.com>
rubenbe <github-com-00ff86@vandamme.email>
Ruslan Yevdokymov <38809160+ruslanye@users.noreply.github.com>
Ryan Qian <i@bitbili.net>
Ryan Sullivan (KayoticSully) <kayoticsully@gmail.com>
Sacheendra Talluri (sacheendra) <sacheendra.t@gmail.com>
Scott Klupfel (kluppy) <kluppy@going2blue.com>
sec65 <106604020+sec65@users.noreply.github.com>
Sergey Mishin (ralder) <ralder@yandex.ru>
Shaarad Dalvi <60266155+shaaraddalvi@users.noreply.github.com>
Shaarad Dalvi <60266155+shaaraddalvi@users.noreply.github.com> <shdalv@microsoft.com>
Simon Frei (imsodin) <freisim93@gmail.com>
Simon Mwepu <simonmwepu@gmail.com>
Sly_tom_cat <slytomcat@mail.ru>
@@ -243,6 +284,8 @@ 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>
Syncthing Automation <automation@syncthing.net>
Syncthing Release Automation <release@syncthing.net>
Taylor Khan (nelsonkhan) <nelsonkhan@gmail.com>
Thomas Hipp <thomashipp@gmail.com>
Tim Abell (timabell) <tim@timwise.co.uk>
@@ -259,9 +302,12 @@ Tyler Kropp <kropptyler@gmail.com>
Unrud (Unrud) <unrud@openaliasbox.org> <Unrud@users.noreply.github.com>
Veeti Paananen (veeti) <veeti.paananen@rojekti.fi>
Victor Buinsky (buinsky) <vix_booja@tut.by>
Vik <63919734+ViktorOn@users.noreply.github.com>
Vil Brekin (Vilbrekin) <vilbrekin@gmail.com>
Vladimir Rusinov <vrusinov@google.com>
villekalliomaki <53118179+villekalliomaki@users.noreply.github.com>
Vladimir Rusinov <vrusinov@google.com> <vladimir.rusinov@gmail.com>
wangguoliang <liangcszzu@163.com>
Will Rouesnel <wrouesnel@wrouesnel.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>
@@ -270,3 +316,4 @@ Xavier O. (damajor) <damajor@gmail.com>
xjtdy888 (xjtdy888) <xjtdy888@163.com>
Yannic A. (eipiminus1) <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>
佛跳墙 <daoquan@qq.com>
落心 <luoxin.ttt@gmail.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:
@@ -24,10 +24,15 @@ too much information will never get you yelled at. :)
## Contributing Translations
All translations are done via
[Transifex](https://www.transifex.com/projects/p/syncthing/). If you
wish to contribute to a translation, just head over there and sign up.
[Weblate](https://hosted.weblate.org/projects/syncthing/). If you wish
to contribute to a translation, just head over there and sign up.
Before every release, the language resources are updated from the
latest info on Transifex.
latest info on Weblate.
Note that the previously used service at
[Transifex](https://www.transifex.com/projects/p/syncthing/) is being
retired and we kindly ask you to sign up on Weblate for continued
involvement.
## Contributing Code

View File

@@ -1,29 +1,48 @@
ARG GOVERSION=latest
#
# Maybe build Syncthing. This is a bit ugly as we can't make an entire
# section of the Dockerfile conditional, so we end up always pulling the
# golang image as builder. Then we check if the executable we need already
# exists (pre-built) otherwise we build it.
#
FROM golang:$GOVERSION AS builder
ARG BUILD_USER
ARG BUILD_HOST
ARG TARGETARCH
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f syncthing && go run build.go -no-upgrade build syncthing
RUN if [ ! -f syncthing-linux-$TARGETARCH ] ; then \
go run build.go -no-upgrade build syncthing ; \
mv syncthing syncthing-linux-$TARGETARCH ; \
fi
#
# The rest of the Dockerfile uses the binary from the builder, prebuilt or
# not.
#
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
RUN apk add --no-cache ca-certificates curl libcap su-exec tzdata
COPY --from=builder /src/syncthing /bin/syncthing
COPY --from=builder /src/syncthing-linux-$TARGETARCH /bin/syncthing
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 127.0.0.1 8384 || exit 1
CMD curl -fkLsS -m 2 127.0.0.1:8384/rest/noauth/health | grep -o --color=never OK || exit 1
ENV STGUIADDRESS=0.0.0.0:8384
RUN chmod 755 /bin/entrypoint.sh
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/syncthing", "-home", "/var/syncthing/config"]

View File

@@ -6,4 +6,4 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
locales rubygems ruby-dev build-essential git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& gem install --no-ri --no-rdoc fpm
&& gem install fpm

View File

@@ -1,19 +0,0 @@
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

@@ -0,0 +1,18 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f stcrashreceiver && go run build.go build stcrashreceiver
FROM alpine
EXPOSE 8080
COPY --from=builder /src/stcrashreceiver /bin/stcrashreceiver
ENTRYPOINT [ "/bin/stcrashreceiver" ]

View File

@@ -1,15 +1,20 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
ARG BUILD_USER
ARG BUILD_HOST
ARG TARGETARCH
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f stdiscosrv && go run build.go -no-upgrade build stdiscosrv
RUN if [ ! -f stdiscosrv-linux-$TARGETARCH ] ; then \
go run build.go -no-upgrade build stdiscosrv ; \
mv stdiscosrv stdiscosrv-linux-$TARGETARCH ; \
fi
FROM alpine
ARG TARGETARCH
EXPOSE 19200 8443
@@ -17,7 +22,7 @@ VOLUME ["/var/stdiscosrv"]
RUN apk add --no-cache ca-certificates su-exec
COPY --from=builder /src/stdiscosrv /bin/stdiscosrv
COPY --from=builder /src/stdiscosrv-linux-$TARGETARCH /bin/stdiscosrv
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/stdiscosrv

26
Dockerfile.strelaypoolsrv Normal file
View File

@@ -0,0 +1,26 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f strelaysrv && go run build.go -no-upgrade build strelaypoolsrv
FROM alpine
EXPOSE 8080
RUN apk add --no-cache ca-certificates su-exec curl
ENV PUID=1000 PGID=1000 MAXMIND_KEY=
RUN mkdir /var/strelaypoolsrv && chown 1000 /var/strelaypoolsrv
USER 1000
COPY --from=builder /src/strelaypoolsrv /bin/strelaypoolsrv
COPY --from=builder /src/script/strelaypoolsrv-entrypoint.sh /bin/entrypoint.sh
WORKDIR /var/strelaypoolsrv
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/strelaypoolsrv", "-listen", ":8080"]

View File

@@ -1,15 +1,20 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
ARG BUILD_USER
ARG BUILD_HOST
ARG TARGETARCH
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f strelaysrv && go run build.go -no-upgrade build strelaysrv
RUN if [ ! -f strelaysrv-linux-$TARGETARCH ] ; then \
go run build.go -no-upgrade build strelaysrv ; \
mv strelaysrv strelaysrv-linux-$TARGETARCH ; \
fi
FROM alpine
ARG TARGETARCH
EXPOSE 22067 22070
@@ -17,7 +22,7 @@ VOLUME ["/var/strelaysrv"]
RUN apk add --no-cache ca-certificates su-exec
COPY --from=builder /src/strelaysrv /bin/strelaysrv
COPY --from=builder /src/strelaysrv-linux-$TARGETARCH /bin/strelaysrv
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/strelaysrv

18
Dockerfile.stupgrades Normal file
View File

@@ -0,0 +1,18 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f stupgrades && go run build.go build stupgrades
FROM alpine
EXPOSE 8080
COPY --from=builder /src/stupgrades /bin/stupgrades
ENTRYPOINT [ "/bin/stupgrades" ]

View File

@@ -57,7 +57,7 @@ latest technology is not always available to any given individual.
> Computers include desktops, laptops, servers, virtual machines, small
> general purpose computers such as Raspberry Pis and, *where possible*,
> tablets and phones. NAS appliances, toasters, cars, firearms, thermostats
> and so on may include computing capabitilies but it is not our goal for
> and so on may include computing capabilities but it is not our goal for
> Syncthing to run smoothly on these devices.
### 6. For Individuals

View File

@@ -7,24 +7,27 @@ 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. In addition
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.
`--hostname=syncthing` parameter.
To grant Syncthing additional capabilities without running as root, use the
`PCAP` environment variable with the same syntax as that for `setcap(8)`.
For example, `PCAP=cap_chown,cap_fowner+ep`.
## Example Usage
**Docker cli**
```
$ docker pull syncthing/syncthing
$ docker run --sysctl net.core.rmem_max=2097152 \
-p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp \
$ docker run -p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp -p 21027:21027/udp \
-v /wherever/st-sync:/var/syncthing \
--hostname=my-syncthing \
syncthing/syncthing:latest
```
**Docker compose**
```
```yml
---
version: "3"
services:
@@ -38,22 +41,23 @@ services:
volumes:
- /wherever/st-sync:/var/syncthing
ports:
- 8384:8384
- 22000:22000/tcp
- 22000:22000/udp
sysctls:
- net.core.rmem_max=2097152
- 8384:8384 # Web UI
- 22000:22000/tcp # TCP file transfers
- 22000:22000/udp # QUIC file transfers
- 21027:21027/udp # Receive local discovery broadcasts
restart: unless-stopped
```
## Discovery
Note that local device discovery will not work with the above command,
resulting in poor local transfer rates if local device addresses are not
manually configured.
Note that Docker's default network mode prevents local IP addresses from
being discovered, as Syncthing is only able to see the internal IP of the
container on the `172.17.0.0/16` subnet. This will result in poor transfer rates
if local device addresses are not manually configured.
To allow local discovery, the docker host network can be used instead:
It is therefore advisable to use the [host network mode](https://docs.docker.com/network/host/) instead:
**Docker cli**
```
$ docker pull syncthing/syncthing
$ docker run --network=host \
@@ -61,6 +65,24 @@ $ docker run --network=host \
syncthing/syncthing:latest
```
**Docker compose**
```yml
---
version: "3"
services:
syncthing:
image: syncthing/syncthing
container_name: syncthing
hostname: my-syncthing
environment:
- PUID=1000
- PGID=1000
volumes:
- /wherever/st-sync:/var/syncthing
network_mode: host
restart: unless-stopped
```
Be aware that syncthing alone is now in control of what interfaces and ports it
listens on. You can edit the syncthing configuration to change the defaults if
there are conflicts.

View File

@@ -73,15 +73,16 @@ 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]
that describes it for both Unix and Windows systems.
Building Syncthing from source is easy. After extracting the source bundle from
a release or checking out git, you just need to run `go run build.go` and the
binaries are created in `./bin`. There's [a guide][5] with more details on the
build process.
## Signed Releases
@@ -95,19 +96,17 @@ binaries are also properly code signed.
## Documentation
Please see the [Syncthing documentation site][6].
Please see the Syncthing [documentation site][6] [[source]][17].
All code is licensed under the [MPLv2 License][7].
[1]: https://docs.syncthing.net/specs/bep-v1.html
[2]: https://docs.syncthing.net/intro/getting-started.html
[3]: https://github.com/syncthing/syncthing/blob/main/etc
[4]: https://www.freenode.net/
[5]: https://docs.syncthing.net/dev/building.html
[6]: https://docs.syncthing.net/
[7]: https://github.com/syncthing/syncthing/blob/main/LICENSE
[8]: https://forum.syncthing.net/
[9]: https://kiwiirc.com/client/irc.freenode.net/#syncthing
[10]: https://github.com/syncthing/syncthing/issues
[11]: https://docs.syncthing.net/users/contrib.html#gui-wrappers
[12]: https://www.bountysource.com/teams/syncthing/issues
@@ -115,4 +114,4 @@ All code is licensed under the [MPLv2 License][7].
[14]: assets/logo-text-128.png
[15]: https://syncthing.net/
[16]: https://github.com/syncthing/syncthing/blob/main/README-Docker.md
[17]: https://github.com/syncthing/docs

194
build.go
View File

@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build ignore
// +build ignore
package main
@@ -14,13 +15,12 @@ import (
"bytes"
"compress/flate"
"compress/gzip"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
@@ -32,6 +32,8 @@ import (
"strings"
"text/template"
"time"
buildpkg "github.com/syncthing/syncthing/lib/build"
)
var (
@@ -48,9 +50,12 @@ var (
cc string
run string
benchRun string
buildOut string
debugBinary bool
coverage bool
long bool
timeout = "120s"
longTimeout = "600s"
numVersions = 5
withNextGenGUI = os.Getenv("BUILD_NEXT_GEN_GUI") != ""
)
@@ -141,13 +146,14 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdService: "cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service",
systemdService: "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},
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-discosrv/LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-discosrv/AUTHORS.txt", perm: 0644},
{src: "man/stdiscosrv.1", dst: "deb/usr/share/man/man1/stdiscosrv.1", perm: 0644},
{src: "cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service", dst: "deb/lib/systemd/system/stdiscosrv.service", perm: 0644},
{src: "cmd/stdiscosrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-discosrv", perm: 0644},
{src: "cmd/stdiscosrv/etc/firewall-ufw/stdiscosrv", dst: "deb/etc/ufw/applications.d/stdiscosrv", perm: 0644},
},
@@ -168,7 +174,7 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdService: "cmd/strelaysrv/etc/linux-systemd/strelaysrv.service",
systemdService: "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},
@@ -176,6 +182,7 @@ var targets = map[string]target{
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-relaysrv/LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaysrv/AUTHORS.txt", perm: 0644},
{src: "man/strelaysrv.1", dst: "deb/usr/share/man/man1/strelaysrv.1", perm: 0644},
{src: "cmd/strelaysrv/etc/linux-systemd/strelaysrv.service", dst: "deb/lib/systemd/system/strelaysrv.service", perm: 0644},
{src: "cmd/strelaysrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-relaysrv", perm: 0644},
{src: "cmd/strelaysrv/etc/firewall-ufw/strelaysrv", dst: "deb/etc/ufw/applications.d/strelaysrv", perm: 0644},
},
@@ -200,18 +207,18 @@ var targets = map[string]target{
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/AUTHORS.txt", perm: 0644},
},
},
}
// 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"},
"stupgrades": {
name: "stupgrades",
description: "Syncthing Upgrade Check Server",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/stupgrades"},
binaryName: "stupgrades",
},
"stcrashreceiver": {
name: "stupgrastcrashreceiverdes",
description: "Syncthing Crash Server",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/stcrashreceiver"},
binaryName: "stcrashreceiver",
},
}
func initTargets() {
@@ -310,6 +317,9 @@ func runCommand(cmd string, target target) {
case "assets":
rebuildAssets()
case "update-deps":
updateDependencies()
case "proto":
proto()
@@ -322,6 +332,9 @@ func runCommand(cmd string, target target) {
case "transifex":
transifex()
case "weblate":
weblate()
case "tar":
buildTar(target, tags)
@@ -375,10 +388,12 @@ 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.StringVar(&buildOut, "build-out", "", "Set the '-o' value for 'go build'")
flag.Parse()
}
@@ -386,11 +401,17 @@ func test(tags []string, pkgs ...string) {
lazyRebuildAssets()
tags = append(tags, "purego")
args := []string{"test", "-short", "-timeout", timeout, "-tags", strings.Join(tags, " ")}
args := []string{"test", "-tags", strings.Join(tags, " ")}
if long {
timeout = longTimeout
} else {
args = append(args, "-short")
}
args = append(args, "-timeout", timeout)
if runtime.GOARCH == "amd64" {
switch runtime.GOOS {
case "darwin", "linux", "freebsd": // , "windows": # See https://github.com/golang/go/issues/27089
case buildpkg.Darwin, buildpkg.Linux, buildpkg.FreeBSD: // , "windows": # See https://github.com/golang/go/issues/27089
args = append(args, "-race")
}
}
@@ -505,6 +526,9 @@ func build(target target, tags []string) {
}
args := []string{"build", "-v"}
if buildOut != "" {
args = append(args, "-o", buildOut)
}
args = appendParameters(args, tags, target.buildPkgs...)
runPrint(goCmd, args...)
}
@@ -721,7 +745,7 @@ func shouldBuildSyso(dir string) (string, error) {
}
jsonPath := filepath.Join(dir, "versioninfo.json")
err = ioutil.WriteFile(jsonPath, bs, 0644)
err = os.WriteFile(jsonPath, bs, 0644)
if err != nil {
return "", errors.New("failed to create " + jsonPath + ": " + err.Error())
}
@@ -734,7 +758,13 @@ func shouldBuildSyso(dir string) (string, error) {
sysoPath := filepath.Join(dir, "cmd", "syncthing", "resource.syso")
if _, err := runError("goversioninfo", "-o", sysoPath); err != nil {
// See https://github.com/josephspurrier/goversioninfo#command-line-flags
armOption := ""
if strings.Contains(goarch, "arm") {
armOption = "-arm=true"
}
if _, err := runError("goversioninfo", "-o", sysoPath, armOption); err != nil {
return "", errors.New("failed to create " + sysoPath + ": " + err.Error())
}
@@ -754,12 +784,12 @@ func shouldCleanupSyso(sysoFilePath string) {
// exists. The permission bits are copied as well. If dst already exists and
// the contents are identical to src the modification time is not updated.
func copyFile(src, dst string, perm os.FileMode) error {
in, err := ioutil.ReadFile(src)
in, err := os.ReadFile(src)
if err != nil {
return err
}
out, err := ioutil.ReadFile(dst)
out, err := os.ReadFile(dst)
if err != nil {
// The destination probably doesn't exist, we should create
// it.
@@ -775,7 +805,7 @@ func copyFile(src, dst string, perm os.FileMode) error {
copy:
os.MkdirAll(filepath.Dir(dst), 0777)
if err := ioutil.WriteFile(dst, in, perm); err != nil {
if err := os.WriteFile(dst, in, perm); err != nil {
return err
}
@@ -869,30 +899,46 @@ func shouldRebuildAssets(target, srcdir string) bool {
return assetsAreNewer
}
func updateDependencies() {
// Figure out desired Go version
bs, err := os.ReadFile("go.mod")
if err != nil {
log.Fatal(err)
}
re := regexp.MustCompile(`(?m)^go\s+([0-9.]+)`)
matches := re.FindSubmatch(bs)
if len(matches) != 2 {
log.Fatal("failed to parse go.mod")
}
goVersion := string(matches[1])
runPrint(goCmd, "get", "-u", "./...")
runPrint(goCmd, "mod", "tidy", "-go="+goVersion, "-compat="+goVersion)
// We might have updated the protobuf package and should regenerate to match.
proto()
}
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))
runPrint(goCmd, "install", fmt.Sprintf("github.com/gogo/protobuf/protoc-gen-gogofast@%v", pv))
os.MkdirAll("repos", 0755)
for _, dep := range dependencyRepos {
path := filepath.Join("repos", dep.path)
if _, err := os.Stat(path); err != nil {
runPrintInDir("repos", "git", "clone", dep.repo, dep.path)
} else {
runPrintInDir(path, "git", "fetch")
}
runPrintInDir(path, "git", "checkout", dep.commit)
if _, err := os.Stat(path); err != nil {
runPrint("git", "clone", repo, path)
} else {
runPrintInDir(path, "git", "fetch")
}
runPrintInDir(path, "git", "checkout", pv)
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/cmd/stdiscosrv")
runPrint(goCmd, "generate", "proto/generate.go")
}
func testmocks() {
runPrint(goCmd, "get", "golang.org/x/tools/cmd/goimports")
runPrint(goCmd, "get", "github.com/maxbrunsfeld/counterfeiter/v6")
args := []string{
"generate",
"github.com/syncthing/syncthing/lib/config",
@@ -922,6 +968,11 @@ func transifex() {
runPrint(goCmd, "run", "../../../../script/transifexdl.go")
}
func weblate() {
os.Chdir("gui/default/assets/lang")
runPrint(goCmd, "run", "../../../../script/weblatedl.go")
}
func ldflags(tags []string) string {
b := new(strings.Builder)
b.WriteString("-w")
@@ -946,7 +997,7 @@ func rmr(paths ...string) {
}
func getReleaseVersion() (string, error) {
bs, err := ioutil.ReadFile("RELEASE")
bs, err := os.ReadFile("RELEASE")
if err != nil {
return "", err
}
@@ -969,7 +1020,7 @@ func getGitVersion() (string, error) {
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.
// upgrade process, we make sure there's only one hyphen 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 {
@@ -1057,10 +1108,14 @@ func getBranchSuffix() string {
branch = parts[len(parts)-1]
switch branch {
case "master", "release", "main":
case "release", "main":
// these are not special
return ""
}
if strings.HasPrefix(branch, "release-") {
// release branches are not special
return ""
}
validBranchRe := regexp.MustCompile(`^[a-zA-Z0-9_.-]+$`)
if !validBranchRe.MatchString(branch) {
@@ -1278,11 +1333,11 @@ func zipFile(out string, files []archiveFile) {
if strings.HasSuffix(f.dst, ".txt") {
// Text file. Read it and convert line endings.
bs, err := ioutil.ReadAll(sf)
bs, err := io.ReadAll(sf)
if err != nil {
log.Fatal(err)
}
bs = bytes.Replace(bs, []byte{'\n'}, []byte{'\n', '\r'}, -1)
bs = bytes.Replace(bs, []byte{'\n'}, []byte{'\r', '\n'}, -1)
fh.UncompressedSize = uint32(len(bs))
fh.UncompressedSize64 = uint64(len(bs))
@@ -1353,6 +1408,33 @@ func windowsCodesign(file string) {
args := []string{"sign", "/fd", algo}
if f := os.Getenv("CODESIGN_CERTIFICATE_FILE"); f != "" {
args = append(args, "/f", f)
} else if b := os.Getenv("CODESIGN_CERTIFICATE_BASE64"); b != "" {
// Decode the PFX certificate from base64.
bs, err := base64.RawStdEncoding.DecodeString(b)
if err != nil {
log.Println("Codesign: signing failed: decoding base64:", err)
return
}
// Write it to a temporary file
f, err := os.CreateTemp("", "codesign-*.pfx")
if err != nil {
log.Println("Codesign: signing failed: creating temp file:", err)
return
}
_ = f.Chmod(0600) // best effort remove other users' access
defer os.Remove(f.Name())
if _, err := f.Write(bs); err != nil {
log.Println("Codesign: signing failed: writing temp file:", err)
return
}
if err := f.Close(); err != nil {
log.Println("Codesign: signing failed: closing temp file:", err)
return
}
// Use that when signing
args = append(args, "/f", f.Name())
}
if p := os.Getenv("CODESIGN_CERTIFICATE_PASSWORD"); p != "" {
args = append(args, "/p", p)
@@ -1372,7 +1454,7 @@ func windowsCodesign(file string) {
bs, err := runError(st, args...)
if err != nil {
log.Println("Codesign: signing failed:", string(bs))
log.Printf("Codesign: signing failed: %v: %s", err, string(bs))
return
}
log.Println("Codesign: successfully signed", file, "using", algo)
@@ -1389,32 +1471,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"

View File

@@ -23,7 +23,7 @@ case "${1:-default}" in
prerelease)
script authors
build transifex
build weblate
pushd man ; ./refresh.sh ; popd
git add -A gui man AUTHORS
git commit -m 'gui, man, authors: Update docs, translations, and contributors'

View File

@@ -0,0 +1,187 @@
// Copyright (C) 2023 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"
"compress/gzip"
"context"
"io"
"log"
"os"
"path/filepath"
"sort"
"time"
)
type diskStore struct {
dir string
inbox chan diskEntry
maxBytes int64
maxFiles int
currentFiles []currentFile
currentSize int64
}
type diskEntry struct {
path string
data []byte
}
type currentFile struct {
path string
size int64
mtime int64
}
func (d *diskStore) Serve(ctx context.Context) {
if err := os.MkdirAll(d.dir, 0750); err != nil {
log.Println("Creating directory:", err)
return
}
if err := d.inventory(); err != nil {
log.Println("Failed to inventory disk store:", err)
}
d.clean()
cleanTimer := time.NewTicker(time.Minute)
inventoryTimer := time.NewTicker(24 * time.Hour)
buf := new(bytes.Buffer)
gw := gzip.NewWriter(buf)
for {
select {
case entry := <-d.inbox:
path := d.fullPath(entry.path)
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
log.Println("Creating directory:", err)
continue
}
buf.Reset()
gw.Reset(buf)
if _, err := gw.Write(entry.data); err != nil {
log.Println("Failed to compress crash report:", err)
continue
}
if err := gw.Close(); err != nil {
log.Println("Failed to compress crash report:", err)
continue
}
if err := os.WriteFile(path, buf.Bytes(), 0644); err != nil {
log.Printf("Failed to write %s: %v", entry.path, err)
_ = os.Remove(path)
continue
}
d.currentSize += int64(buf.Len())
d.currentFiles = append(d.currentFiles, currentFile{
size: int64(len(entry.data)),
path: path,
})
case <-cleanTimer.C:
d.clean()
case <-inventoryTimer.C:
if err := d.inventory(); err != nil {
log.Println("Failed to inventory disk store:", err)
}
case <-ctx.Done():
return
}
}
}
func (d *diskStore) Put(path string, data []byte) bool {
select {
case d.inbox <- diskEntry{
path: path,
data: data,
}:
return true
default:
return false
}
}
func (d *diskStore) Get(path string) ([]byte, error) {
path = d.fullPath(path)
bs, err := os.ReadFile(path)
if err != nil {
return nil, err
}
gr, err := gzip.NewReader(bytes.NewReader(bs))
if err != nil {
return nil, err
}
defer gr.Close()
return io.ReadAll(gr)
}
func (d *diskStore) Exists(path string) bool {
path = d.fullPath(path)
_, err := os.Lstat(path)
return err == nil
}
func (d *diskStore) clean() {
for len(d.currentFiles) > 0 && (len(d.currentFiles) > d.maxFiles || d.currentSize > d.maxBytes) {
f := d.currentFiles[0]
log.Println("Removing", f.path)
if err := os.Remove(f.path); err != nil {
log.Println("Failed to remove file:", err)
}
d.currentFiles = d.currentFiles[1:]
d.currentSize -= f.size
}
var oldest time.Duration
if len(d.currentFiles) > 0 {
oldest = time.Since(time.Unix(d.currentFiles[0].mtime, 0)).Truncate(time.Minute)
}
log.Printf("Clean complete: %d files, %d MB, oldest is %v ago", len(d.currentFiles), d.currentSize>>20, oldest)
}
func (d *diskStore) inventory() error {
d.currentFiles = nil
d.currentSize = 0
err := filepath.Walk(d.dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if filepath.Ext(path) != ".gz" {
return nil
}
d.currentSize += info.Size()
d.currentFiles = append(d.currentFiles, currentFile{
path: path,
size: info.Size(),
mtime: info.ModTime().Unix(),
})
return nil
})
sort.Slice(d.currentFiles, func(i, j int) bool {
return d.currentFiles[i].mtime < d.currentFiles[j].mtime
})
var oldest time.Duration
if len(d.currentFiles) > 0 {
oldest = time.Since(time.Unix(d.currentFiles[0].mtime, 0)).Truncate(time.Minute)
}
log.Printf("Inventory complete: %d files, %d MB, oldest is %v ago", len(d.currentFiles), d.currentSize>>20, oldest)
return err
}
func (d *diskStore) fullPath(path string) string {
return filepath.Join(d.dir, path[0:2], path[2:]) + ".gz"
}

View File

@@ -13,17 +13,17 @@
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"path/filepath"
"time"
"github.com/alecthomas/kong"
"github.com/syncthing/syncthing/lib/sha256"
"github.com/syncthing/syncthing/lib/ur"
@@ -32,34 +32,58 @@ import (
const maxRequestSize = 1 << 20 // 1 MiB
type cli struct {
Dir string `help:"Parent directory to store crash and failure reports in" env:"REPORTS_DIR" default:"."`
DSN string `help:"Sentry DSN" env:"SENTRY_DSN"`
Listen string `help:"HTTP listen address" default:":8080" env:"LISTEN_ADDRESS"`
MaxDiskFiles int `help:"Maximum number of reports on disk" default:"100000" env:"MAX_DISK_FILES"`
MaxDiskSizeMB int64 `help:"Maximum disk space to use for reports" default:"1024" env:"MAX_DISK_SIZE_MB"`
CleanInterval time.Duration `help:"Interval between cleaning up old reports" default:"12h" env:"CLEAN_INTERVAL"`
SentryQueue int `help:"Maximum number of reports to queue for sending to Sentry" default:"64" env:"SENTRY_QUEUE"`
DiskQueue int `help:"Maximum number of reports to queue for writing to disk" default:"64" env:"DISK_QUEUE"`
}
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()
var params cli
kong.Parse(&params)
mux := http.NewServeMux()
cr := &crashReceiver{
dir: *dir,
dsn: *dsn,
ds := &diskStore{
dir: filepath.Join(params.Dir, "crash_reports"),
inbox: make(chan diskEntry, params.DiskQueue),
maxFiles: params.MaxDiskFiles,
maxBytes: params.MaxDiskSizeMB << 20,
}
go ds.Serve(context.Background())
ss := &sentryService{
dsn: params.DSN,
inbox: make(chan sentryRequest, params.SentryQueue),
}
go ss.Serve(context.Background())
cr := &crashReceiver{
store: ds,
sentry: ss,
}
mux.Handle("/", cr)
if *dsn != "" {
mux.HandleFunc("/newcrash/failure", handleFailureFn(*dsn))
if params.DSN != "" {
mux.HandleFunc("/newcrash/failure", handleFailureFn(params.DSN, filepath.Join(params.Dir, "failure_reports")))
}
log.SetOutput(os.Stdout)
if err := http.ListenAndServe(*listen, mux); err != nil {
if err := http.ListenAndServe(params.Listen, mux); err != nil {
log.Fatalln("HTTP serve:", err)
}
}
func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request) {
func handleFailureFn(dsn, failureDir 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)
bs, err := io.ReadAll(lr)
req.Body.Close()
if err != nil {
http.Error(w, err.Error(), 500)
@@ -89,7 +113,20 @@ func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request)
pkt.Extra = raven.Extra{
"count": r.Count,
}
pkt.Fingerprint = []string{r.Description}
for k, v := range r.Extra {
pkt.Extra[k] = v
}
if r.Goroutines != "" {
url, err := saveFailureWithGoroutines(r.FailureData, failureDir)
if err != nil {
log.Println("Saving failure report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
pkt.Extra["goroutinesURL"] = url
}
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)
@@ -100,19 +137,15 @@ func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request)
}
}
// 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
func saveFailureWithGoroutines(data ur.FailureData, failureDir string) (string, error) {
bs := make([]byte, len(data.Description)+len(data.Goroutines))
copy(bs, data.Description)
copy(bs[len(data.Description):], data.Goroutines)
id := fmt.Sprintf("%x", sha256.Sum256(bs))
path := fullPathCompressed(failureDir, id)
err := compressAndWrite(bs, path)
if err != nil {
return "", err
}
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])
return reportServer + path, nil
}

View File

@@ -8,14 +8,16 @@ package main
import (
"bytes"
"context"
"errors"
"io/ioutil"
"io"
"log"
"regexp"
"strings"
"sync"
raven "github.com/getsentry/raven-go"
"github.com/maruel/panicparse/stack"
"github.com/maruel/panicparse/v2/stack"
)
const reportServer = "https://crash.syncthing.net/report/"
@@ -31,6 +33,44 @@ var (
clientsMut sync.Mutex
)
type sentryService struct {
dsn string
inbox chan sentryRequest
}
type sentryRequest struct {
reportID string
data []byte
}
func (s *sentryService) Serve(ctx context.Context) {
for {
select {
case req := <-s.inbox:
pkt, err := parseCrashReport(req.reportID, req.data)
if err != nil {
log.Println("Failed to parse crash report:", err)
continue
}
if err := sendReport(s.dsn, pkt, req.reportID); err != nil {
log.Println("Failed to send crash report:", err)
}
case <-ctx.Done():
return
}
}
}
func (s *sentryService) Send(reportID string, data []byte) bool {
select {
case s.inbox <- sentryRequest{reportID, data}:
return true
default:
return false
}
}
func sendReport(dsn string, pkt *raven.Packet, userID string) error {
pkt.Interfaces = append(pkt.Interfaces, &raven.User{ID: userID})
@@ -93,10 +133,13 @@ func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
}
r := bytes.NewReader(report)
ctx, err := stack.ParseDump(r, ioutil.Discard, false)
if err != nil {
ctx, _, err := stack.ScanSnapshot(r, io.Discard, stack.DefaultOpts())
if err != nil && err != io.EOF {
return nil, err
}
if ctx == nil || len(ctx.Goroutines) == 0 {
return nil, errors.New("no goroutines found")
}
// Lock the source code loader to the version we are processing here.
if version.commit != "" {
@@ -116,7 +159,7 @@ func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
if gr.First {
trace.Frames = make([]*raven.StacktraceFrame, len(gr.Stack.Calls))
for i, sc := range gr.Stack.Calls {
trace.Frames[len(trace.Frames)-1-i] = raven.NewStacktraceFrame(0, sc.Func.Name(), sc.SrcPath, sc.Line, 3, nil)
trace.Frames[len(trace.Frames)-1-i] = raven.NewStacktraceFrame(0, sc.Func.Name, sc.RemoteSrcPath, sc.Line, 3, nil)
}
break
}
@@ -143,15 +186,20 @@ var (
ldbPathRe = regexp.MustCompile(`(open|write|read) .+[\\/].+[\\/]index[^\\/]+[\\/][^\\/]+: `)
)
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
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}
}

View File

@@ -8,7 +8,7 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"testing"
)
@@ -59,7 +59,7 @@ func TestParseVersion(t *testing.T) {
}
func TestParseReport(t *testing.T) {
bs, err := ioutil.ReadFile("_testdata/panic.log")
bs, err := os.ReadFile("_testdata/panic.log")
if err != nil {
t.Fatal(err)
}

View File

@@ -9,7 +9,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"net/http"
"path/filepath"
"strings"
@@ -80,7 +80,7 @@ func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]b
fmt.Println("Loading source:", resp.Status)
return nil, 0
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
_ = resp.Body.Close()
if err != nil {
fmt.Println("Loading source:", err.Error())

View File

@@ -7,21 +7,16 @@
package main
import (
"bytes"
"compress/gzip"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
type crashReceiver struct {
dir string
dsn string
store *diskStore
sentry *sentryService
}
func (r *crashReceiver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
@@ -44,99 +39,55 @@ func (r *crashReceiver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
// The location of the report on disk, compressed
fullPath := filepath.Join(r.dir, r.dirFor(reportID), reportID) + ".gz"
switch req.Method {
case http.MethodGet:
r.serveGet(fullPath, w, req)
r.serveGet(reportID, w, req)
case http.MethodHead:
r.serveHead(fullPath, w, req)
r.serveHead(reportID, w, req)
case http.MethodPut:
r.servePut(reportID, fullPath, w, req)
r.servePut(reportID, w, req)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
// serveGet responds to GET requests by serving the uncompressed report.
func (r *crashReceiver) serveGet(fullPath string, w http.ResponseWriter, _ *http.Request) {
fd, err := os.Open(fullPath)
func (r *crashReceiver) serveGet(reportID string, w http.ResponseWriter, _ *http.Request) {
bs, err := r.store.Get(reportID)
if err != nil {
http.Error(w, "Not found", http.StatusNotFound)
return
}
defer fd.Close()
gr, err := gzip.NewReader(fd)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
_, _ = io.Copy(w, gr) // best effort
w.Write(bs)
}
// serveHead responds to HEAD requests by checking if the named report
// already exists in the system.
func (r *crashReceiver) serveHead(fullPath string, w http.ResponseWriter, _ *http.Request) {
if _, err := os.Lstat(fullPath); err != nil {
func (r *crashReceiver) serveHead(reportID string, w http.ResponseWriter, _ *http.Request) {
if !r.store.Exists(reportID) {
http.Error(w, "Not found", http.StatusNotFound)
}
}
// servePut accepts and stores the given report.
func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWriter, req *http.Request) {
// Ensure the destination directory exists
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
log.Println("Creating directory:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
func (r *crashReceiver) servePut(reportID string, w http.ResponseWriter, req *http.Request) {
// Read at most maxRequestSize of report data.
log.Println("Receiving report", reportID)
lr := io.LimitReader(req.Body, maxRequestSize)
bs, err := ioutil.ReadAll(lr)
bs, err := io.ReadAll(lr)
if err != nil {
log.Println("Reading report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// Compress the report for storage
buf := new(bytes.Buffer)
gw := gzip.NewWriter(buf)
_, _ = gw.Write(bs) // can't fail
gw.Close()
// Create an output file with the compressed report
err = ioutil.WriteFile(fullPath, buf.Bytes(), 0644)
if err != nil {
log.Println("Saving report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
// Store the report
if !r.store.Put(reportID, bs) {
log.Println("Failed to store report (queue full):", reportID)
}
// 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.
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)
}
}()
if !r.sentry.Send(reportID, bs) {
log.Println("Failed to send report to sentry (queue full):", reportID)
}
}
// 01234567890abcdef... => 01/23
func (r *crashReceiver) dirFor(base string) string {
return filepath.Join(base[0:2], base[2:4])
}

View File

@@ -0,0 +1,57 @@
// 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
import (
"bytes"
"compress/gzip"
"fmt"
"net"
"net/http"
"os"
"path/filepath"
"time"
"github.com/syncthing/syncthing/lib/sha256"
)
// 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])
}
// 01234567890abcdef... => 01/23
func dirFor(base string) string {
return filepath.Join(base[0:2], base[2:4])
}
func fullPathCompressed(root, reportID string) string {
return filepath.Join(root, dirFor(reportID), reportID) + ".gz"
}
func compressAndWrite(bs []byte, fullPath string) error {
// Compress the report for storage
buf := new(bytes.Buffer)
gw := gzip.NewWriter(buf)
_, _ = gw.Write(bs) // can't fail
gw.Close()
// Create an output file with the compressed report
return os.WriteFile(fullPath, buf.Bytes(), 0644)
}

View File

@@ -10,8 +10,10 @@ import (
"bytes"
"context"
"crypto/tls"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"log"
"math/rand"
@@ -66,7 +68,7 @@ func newAPISrv(addr string, cert tls.Certificate, db database, repl replicator,
}
}
func (s *apiSrv) Serve(ctx context.Context) error {
func (s *apiSrv) Serve(_ context.Context) error {
if s.useHTTP {
listener, err := net.Listen("tcp", s.addr)
if err != nil {
@@ -229,10 +231,10 @@ func (s *apiSrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http
func (s *apiSrv) handlePOST(ctx context.Context, remoteAddr *net.TCPAddr, w http.ResponseWriter, req *http.Request) {
reqID := ctx.Value(idKey).(requestID)
rawCert := certificateBytes(req)
if rawCert == nil {
rawCert, err := certificateBytes(req)
if err != nil {
if debug {
log.Println(reqID, "no certificates")
log.Println(reqID, "no certificates:", err)
}
announceRequestsTotal.WithLabelValues("no_certificate").Inc()
w.Header().Set("Retry-After", errorRetryAfterString())
@@ -300,13 +302,13 @@ func (s *apiSrv) handleAnnounce(deviceID protocol.DeviceID, addresses []string)
return s.db.merge(key, dbAddrs, seen)
}
func handlePing(w http.ResponseWriter, r *http.Request) {
func handlePing(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(204)
}
func certificateBytes(req *http.Request) []byte {
func certificateBytes(req *http.Request) ([]byte, error) {
if req.TLS != nil && len(req.TLS.PeerCertificates) > 0 {
return req.TLS.PeerCertificates[0].Raw
return req.TLS.PeerCertificates[0].Raw, nil
}
var bs []byte
@@ -319,7 +321,7 @@ func certificateBytes(req *http.Request) []byte {
hdr, err := url.QueryUnescape(hdr)
if err != nil {
// Decoding failed
return nil
return nil, err
}
bs = []byte(hdr)
@@ -338,6 +340,15 @@ func certificateBytes(req *http.Request) []byte {
}
}
}
} else if hdr := req.Header.Get("X-Tls-Client-Cert-Der-Base64"); hdr != "" {
// Caddy {tls_client_certificate_der_base64}
hdr, err := base64.StdEncoding.DecodeString(hdr)
if err != nil {
// Decoding failed
return nil, err
}
bs = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: hdr})
} else if hdr := req.Header.Get("X-Forwarded-Tls-Client-Cert"); hdr != "" {
// Traefik 2 passtlsclientcert
// The certificate is in PEM format with url encoding but without newlines
@@ -346,7 +357,7 @@ func certificateBytes(req *http.Request) []byte {
hdr, err := url.QueryUnescape(hdr)
if err != nil {
// Decoding failed
return nil
return nil, err
}
for i := 64; i < len(hdr); i += 65 {
@@ -359,16 +370,16 @@ func certificateBytes(req *http.Request) []byte {
}
if bs == nil {
return nil
return nil, errors.New("empty certificate header")
}
block, _ := pem.Decode(bs)
if block == nil {
// Decoding failed
return nil
return nil, errors.New("certificate decode result is empty")
}
return block.Bytes
return block.Bytes, nil
}
// fixupAddresses checks the list of addresses, removing invalid ones and
@@ -419,7 +430,7 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
// If zero port was specified, use remote port.
if port == "0" && remote.Port > 0 {
port = fmt.Sprintf("%d", remote.Port)
port = strconv.Itoa(remote.Port)
}
}

View File

@@ -16,6 +16,7 @@ import (
"time"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
)
@@ -54,6 +55,18 @@ func newLevelDBStore(dir string) (*levelDBStore, error) {
}, nil
}
func newMemoryLevelDBStore() (*levelDBStore, error) {
db, err := leveldb.Open(storage.NewMemStorage(), nil)
if err != nil {
return nil, err
}
return &levelDBStore{
db: db,
inbox: make(chan func(), 16),
clock: defaultClock{},
}, nil
}
func (s *levelDBStore) put(key string, rec DatabaseRecord) error {
t0 := time.Now()
defer func() {

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

@@ -9,15 +9,12 @@ package main
import (
"context"
"fmt"
"os"
"testing"
"time"
)
func TestDatabaseGetSet(t *testing.T) {
os.RemoveAll("_database")
defer os.RemoveAll("_database")
db, err := newLevelDBStore("_database")
db, err := newMemoryLevelDBStore()
if err != nil {
t.Fatal(err)
}
@@ -119,7 +116,7 @@ func TestDatabaseGetSet(t *testing.T) {
// Put a record with misses
rec = DatabaseRecord{Misses: 42}
rec = DatabaseRecord{Misses: 42, Missed: tc.Now().UnixNano()}
if err := db.put("efgh", rec); err != nil {
t.Fatal(err)
}
@@ -209,5 +206,6 @@ func (t *testClock) wind(d time.Duration) {
}
func (t *testClock) Now() time.Time {
t.now = t.now.Add(time.Nanosecond)
return t.now
}

View File

@@ -116,8 +116,11 @@ func main() {
var replicationDestinations []string
parts := strings.Split(replicationPeers, ",")
for _, part := range parts {
fields := strings.Split(part, "@")
if part == "" {
continue
}
fields := strings.Split(part, "@")
switch len(fields) {
case 2:
// This is an id@address specification. Grab the address for the
@@ -137,6 +140,9 @@ func main() {
if err != nil {
log.Fatalln("Parsing device ID:", err)
}
if id == protocol.EmptyDeviceID {
log.Fatalf("Missing device ID for peer in %q", part)
}
allowedReplicationPeers = append(allowedReplicationPeers, id)
default:

View File

@@ -120,7 +120,7 @@ func (s *replicationSender) Serve(ctx context.Context) error {
if _, err := conn.Write(buf[:4+n]); err != nil {
replicationSendsTotal.WithLabelValues("error").Inc()
log.Println("Replication write:", err)
// Yes, we are loosing the replication event here.
// Yes, we are losing the replication event here.
return err
}
replicationSendsTotal.WithLabelValues("success").Inc()
@@ -135,7 +135,7 @@ func (s *replicationSender) String() string {
return fmt.Sprintf("replicationSender(%q)", s.dst)
}
func (s *replicationSender) send(key string, ps []DatabaseAddress, seen int64) {
func (s *replicationSender) send(key string, ps []DatabaseAddress, _ int64) {
item := ReplicationRecord{
Key: key,
Addresses: ps,

View File

@@ -10,6 +10,7 @@ import (
"os"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
)
var (
@@ -109,7 +110,7 @@ func init() {
databaseKeys, databaseStatisticsSeconds,
databaseOperations, databaseOperationSeconds)
processCollectorOpts := prometheus.ProcessCollectorOpts{
processCollectorOpts := collectors.ProcessCollectorOpts{
Namespace: "syncthing_discovery",
PidFn: func() (int, error) {
return os.Getpid(), nil
@@ -117,7 +118,7 @@ func init() {
}
prometheus.MustRegister(
prometheus.NewProcessCollector(processCollectorOpts),
collectors.NewProcessCollector(processCollectorOpts),
)
}

View File

@@ -84,7 +84,7 @@ func checkServers(deviceID protocol.DeviceID, servers ...string) {
}
func checkServer(deviceID protocol.DeviceID, server string) checkResult {
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger)
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger, nil)
if err != nil {
return checkResult{error: 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/.
// Commmand stfindignored lists ignored files under a given folder root.
// Command stfindignored lists ignored files under a given folder root.
package main
import (

View File

@@ -66,7 +66,7 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
}
func generateOneFile(fd io.ReadSeeker, p1 string, s int64) error {
src := io.LimitReader(&inifiteReader{fd}, s)
src := io.LimitReader(&infiniteReader{fd}, s)
dst, err := os.Create(p1)
if err != nil {
return err
@@ -105,11 +105,11 @@ func readRand(bs []byte) (int, error) {
return len(bs), nil
}
type inifiteReader struct {
type infiniteReader struct {
rd io.ReadSeeker
}
func (i *inifiteReader) Read(bs []byte) (int, error) {
func (i *infiniteReader) Read(bs []byte) (int, error) {
n, err := i.rd.Read(bs)
if err == io.EOF {
err = nil

View File

@@ -4,7 +4,8 @@
// 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 noassets
//go:build noassets
// +build noassets
package auto

View File

@@ -46,18 +46,18 @@
<h1>Relay Pool Data</h1>
<div ng-if="relays === undefined" class="text-center">
<img src="https://cdnjs.cloudflare.com/ajax/libs/galleriffic/2.0.1/css/loader.gif" alt=""/>
<p>Please wait while we gather data</p>
<p>Please wait while we gather data</p>
</div>
<div>
<div ng-show="relays !== undefined" class="ng-hide">
<p>
The relays listed on this page are not managed or vetted by the Syncthing project.
Each relay is the responsibility of the relay operator.
Currently {{ relays.length }} relays online.
Currently {{ relays.length }} relays are online.
</p>
</div>
<div id="map"></div> <!-- Can't hide the map, otherwise it freaks out -->
<p>The circle size represents how much bytes the relay transferred relative to other relays</p>
<p>The circle size represents how much bytes the relay has transferred relatively to other relays.</p>
</div>
<div>
<table class="table table-striped table-condensed table">
@@ -188,7 +188,7 @@
<hr>
<p>
This product includes GeoLite2 data created by MaxMind, available from
<a href="http://www.maxmind.com">http://www.maxmind.com</a>.
<a href="https://www.maxmind.com">https://www.maxmind.com</a>.
</p>
</div>

View File

@@ -3,15 +3,12 @@
package main
import (
"compress/gzip"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
@@ -20,11 +17,13 @@ import (
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"time"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/syncthing/syncthing/lib/httpcache"
"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"
@@ -34,7 +33,6 @@ import (
"github.com/syncthing/syncthing/lib/relay/client"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
"golang.org/x/time/rate"
)
type location struct {
@@ -100,27 +98,13 @@ var (
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.NewMutex()
getLRUCache *lru.Cache
postMut = sync.NewMutex()
postLRUCache *lru.Cache
statsRefresh = time.Minute
requestQueueLen = 64
requestProcessors = 8
requests chan request
@@ -128,6 +112,7 @@ var (
knownRelays = make([]*relay, 0)
permanentRelays = make([]*relay, 0)
evictionTimers = make(map[string]*time.Timer)
globalBlocklist = newErrorTracker(1000)
)
const (
@@ -142,13 +127,8 @@ func main() {
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")
flag.DurationVar(&evictionTime, "eviction", evictionTime, "After how long the relay is evicted")
flag.IntVar(&getLRUSize, "get-limit-cache", getLRUSize, "Get request limiter cache size")
flag.IntVar(&getLimitAvg, "get-limit-avg", getLimitAvg, "Allowed average get request rate, per 10 s")
flag.IntVar(&getLimitBurst, "get-limit-burst", getLimitBurst, "Allowed burst get requests")
flag.IntVar(&postLRUSize, "post-limit-cache", postLRUSize, "Post request limiter cache size")
flag.IntVar(&postLimitAvg, "post-limit-avg", postLimitAvg, "Allowed average post request rate, per minute")
flag.IntVar(&postLimitBurst, "post-limit-burst", postLimitBurst, "Allowed burst post requests")
flag.StringVar(&permRelaysFile, "perm-relays", "", "Path to list of permanent relays")
flag.StringVar(&knownRelaysFile, "known-relays", knownRelaysFile, "Path to list of current relays")
flag.StringVar(&ipHeader, "ip-header", "", "Name of header which holds clients ip:port. Only meaningful when running behind a reverse proxy.")
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")
@@ -160,12 +140,6 @@ func main() {
requests = make(chan request, requestQueueLen)
getLimit = 10 * time.Second / time.Duration(getLimitAvg)
postLimit = time.Minute / time.Duration(postLimitAvg)
getLRUCache = lru.New(getLRUSize)
postLRUCache = lru.New(postLRUSize)
var listener net.Listener
var err error
@@ -241,7 +215,7 @@ func main() {
handler := http.NewServeMux()
handler.HandleFunc("/", handleAssets)
handler.HandleFunc("/endpoint", handleRequest)
handler.Handle("/endpoint", httpcache.SinglePath(http.HandlerFunc(handleRequest), 15*time.Second))
handler.HandleFunc("/metrics", handleMetrics)
srv := http.Server{
@@ -292,21 +266,17 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
}()
if ipHeader != "" {
r.RemoteAddr = r.Header.Get(ipHeader)
hdr := r.Header.Get(ipHeader)
fields := strings.Split(hdr, ",")
if len(fields) > 0 {
r.RemoteAddr = strings.TrimSpace(fields[len(fields)-1])
}
}
w.Header().Set("Access-Control-Allow-Origin", "*")
switch r.Method {
case "GET":
if limit(r.RemoteAddr, getLRUCache, getMut, getLimit, getLimitBurst) {
w.WriteHeader(httpStatusEnhanceYourCalm)
return
}
handleGetRequest(w, r)
case "POST":
if limit(r.RemoteAddr, postLRUCache, postMut, postLimit, postLimitBurst) {
w.WriteHeader(httpStatusEnhanceYourCalm)
return
}
handlePostRequest(w, r)
default:
if debug {
@@ -328,20 +298,28 @@ func handleGetRequest(rw http.ResponseWriter, r *http.Request) {
// Shuffle
rand.Shuffle(relays)
w := io.Writer(rw)
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
rw.Header().Set("Content-Encoding", "gzip")
gw := gzip.NewWriter(rw)
defer gw.Close()
w = gw
}
_ = json.NewEncoder(w).Encode(map[string][]*relay{
_ = json.NewEncoder(rw).Encode(map[string][]*relay{
"relays": relays,
})
}
func handlePostRequest(w http.ResponseWriter, r *http.Request) {
// Get the IP address of the client
rhost := r.RemoteAddr
if host, _, err := net.SplitHostPort(rhost); err == nil {
rhost = host
}
// Check the black list. A client is blacklisted if their last 10
// attempts to join have all failed. The "Unauthorized" status return
// causes strelaysrv to cease attempting to join.
if globalBlocklist.IsBlocked(rhost) {
log.Println("Rejected blocked client", rhost)
http.Error(w, "Too many errors", http.StatusUnauthorized)
globalBlocklist.ClearErrors(rhost)
return
}
var relayCert *x509.Certificate
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
relayCert = r.TLS.PeerCertificates[0]
@@ -369,6 +347,11 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
return
}
// Canonicalize the URL. In particular, parse and re-encode the query
// string so that it's guaranteed to be valid.
uri.RawQuery = uri.Query().Encode()
newRelay.URL = uri.String()
if relayCert != nil {
advertisedId := uri.Query().Get("id")
idFromCert := protocol.NewDeviceID(relayCert.Raw).String()
@@ -388,12 +371,6 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
return
}
// Get the IP address of the client
rhost := r.RemoteAddr
if host, _, err := net.SplitHostPort(rhost); err == nil {
rhost = host
}
ip := net.ParseIP(host)
// The client did not provide an IP address, use the IP address of the client.
if ip == nil || ip.IsUnspecified() {
@@ -425,10 +402,14 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
case requests <- request{&newRelay, reschan, prometheus.NewTimer(relayTestActionsSeconds.WithLabelValues("queue"))}:
result := <-reschan
if result.err != nil {
log.Println("Join from", r.RemoteAddr, "failed:", result.err)
globalBlocklist.AddError(rhost)
relayTestsTotal.WithLabelValues("failed").Inc()
http.Error(w, result.err.Error(), http.StatusBadRequest)
return
}
log.Println("Join from", r.RemoteAddr, "succeeded")
globalBlocklist.ClearErrors(rhost)
relayTestsTotal.WithLabelValues("success").Inc()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(map[string]time.Duration{
@@ -542,25 +523,8 @@ func evict(relay *relay) func() {
}
}
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.Lock()
v, _ := cache.Get(addr)
bkt, ok := v.(*rate.Limiter)
if !ok {
bkt = rate.NewLimiter(rate.Every(intv), burst)
cache.Add(addr, bkt)
}
lock.Unlock()
return !bkt.Allow()
}
func loadRelays(file string) []*relay {
content, err := ioutil.ReadFile(file)
content, err := os.ReadFile(file)
if err != nil {
log.Println("Failed to load relays: " + err.Error())
return nil
@@ -568,7 +532,7 @@ func loadRelays(file string) []*relay {
var relays []*relay
for _, line := range strings.Split(string(content), "\n") {
if len(line) == 0 {
if line == "" {
continue
}
@@ -598,11 +562,11 @@ func saveRelays(file string, relays []*relay) error {
for _, relay := range relays {
content += relay.uri.String() + "\n"
}
return ioutil.WriteFile(file, []byte(content), 0777)
return os.WriteFile(file, []byte(content), 0o777)
}
func createTestCertificate() tls.Certificate {
tmpDir, err := ioutil.TempDir("", "relaypoolsrv")
tmpDir, err := os.MkdirTemp("", "relaypoolsrv")
if err != nil {
log.Fatal(err)
}
@@ -657,3 +621,42 @@ func (lrw *loggingResponseWriter) WriteHeader(code int) {
lrw.statusCode = code
lrw.ResponseWriter.WriteHeader(code)
}
type errorTracker struct {
errors *lru.TwoQueueCache[string, *errorCounter]
}
type errorCounter struct {
count atomic.Int32
}
func newErrorTracker(size int) *errorTracker {
cache, err := lru.New2Q[string, *errorCounter](size)
if err != nil {
panic(err)
}
return &errorTracker{
errors: cache,
}
}
func (b *errorTracker) AddError(host string) {
entry, ok := b.errors.Get(host)
if !ok {
entry = &errorCounter{}
b.errors.Add(host, entry)
}
c := entry.count.Add(1)
log.Printf("Error count for %s is now %d", host, c)
}
func (b *errorTracker) ClearErrors(host string) {
b.errors.Remove(host)
}
func (b *errorTracker) IsBlocked(host string) bool {
if be, ok := b.errors.Get(host); ok {
return be.count.Load() > 10
}
return false
}

View File

@@ -11,6 +11,7 @@ import (
"encoding/json"
"fmt"
"net/http/httptest"
"net/url"
"strings"
"sync"
"testing"
@@ -65,3 +66,29 @@ func TestHandleGetRequest(t *testing.T) {
}
}
}
func TestCanonicalizeQueryValues(t *testing.T) {
// This just demonstrates and validates the uri.Parse/String stuff in
// regards to query strings.
in := "http://example.com/?some weird= query^value"
exp := "http://example.com/?some+weird=+query%5Evalue"
uri, err := url.Parse(in)
if err != nil {
t.Fatal(err)
}
str := uri.String()
if str != in {
// Just re-encoding the URL doesn't sanitize the query string.
t.Errorf("expected %q, got %q", in, str)
}
uri.RawQuery = uri.Query().Encode()
str = uri.String()
if str != exp {
// The query string is now in correct format.
t.Errorf("expected %q, got %q", exp, str)
}
}

View File

@@ -10,11 +10,12 @@ import (
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/syncthing/syncthing/lib/sync"
)
func init() {
processCollectorOpts := prometheus.ProcessCollectorOpts{
processCollectorOpts := collectors.ProcessCollectorOpts{
Namespace: "syncthing_relaypoolsrv",
PidFn: func() (int, error) {
return os.Getpid(), nil
@@ -22,7 +23,7 @@ func init() {
}
prometheus.MustRegister(
prometheus.NewProcessCollector(processCollectorOpts),
collectors.NewProcessCollector(processCollectorOpts),
)
}

View File

@@ -20,10 +20,10 @@ import (
var (
outboxesMut = sync.RWMutex{}
outboxes = make(map[syncthingprotocol.DeviceID]chan interface{})
numConnections int64
numConnections atomic.Int64
)
func listener(proto, addr string, config *tls.Config) {
func listener(_, addr string, config *tls.Config, token string) {
tcpListener, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalln(err)
@@ -49,7 +49,7 @@ func listener(proto, addr string, config *tls.Config) {
}
if isTLS {
go protocolConnectionHandler(conn, config)
go protocolConnectionHandler(conn, config, token)
} else {
go sessionConnectionHandler(conn)
}
@@ -57,7 +57,7 @@ func listener(proto, addr string, config *tls.Config) {
}
}
func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config, token string) {
conn := tls.Server(tcpConn, config)
if err := conn.SetDeadline(time.Now().Add(messageTimeout)); err != nil {
if debug {
@@ -76,7 +76,7 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
}
state := conn.ConnectionState()
if (!state.NegotiatedProtocolIsMutual || state.NegotiatedProtocol != protocol.ProtocolName) && debug {
if debug && state.NegotiatedProtocol != protocol.ProtocolName {
log.Println("Protocol negotiation error")
}
@@ -119,7 +119,16 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
switch msg := message.(type) {
case protocol.JoinRelayRequest:
if atomic.LoadInt32(&overLimit) > 0 {
if token != "" && msg.Token != token {
if debug {
log.Printf("invalid token %s\n", msg.Token)
}
protocol.WriteMessage(conn, protocol.ResponseWrongToken)
conn.Close()
continue
}
if overLimit.Load() {
protocol.WriteMessage(conn, protocol.RelayFull{})
if debug {
log.Println("Refusing join request from", id, "due to being over limits")
@@ -258,7 +267,7 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
conn.Close()
}
if atomic.LoadInt32(&overLimit) > 0 && !hasSessions(id) {
if overLimit.Load() && !hasSessions(id) {
if debug {
log.Println("Dropping", id, "as it has no sessions and we are over our limits")
}
@@ -351,8 +360,8 @@ func sessionConnectionHandler(conn net.Conn) {
}
func messageReader(conn net.Conn, messages chan<- interface{}, errors chan<- error) {
atomic.AddInt64(&numConnections, 1)
defer atomic.AddInt64(&numConnections, -1)
numConnections.Add(1)
defer numConnections.Add(-1)
for {
msg, err := protocol.ReadMessage(conn)

View File

@@ -14,7 +14,6 @@ import (
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"sync/atomic"
"syscall"
@@ -50,13 +49,14 @@ var (
sessionLimitBps int
globalLimitBps int
overLimit int32
overLimit atomic.Bool
descriptorLimit int64
sessionLimiter *rate.Limiter
globalLimiter *rate.Limiter
networkBufferSize int
statusAddr string
token string
poolAddrs string
pools []string
providedBy string
@@ -90,6 +90,7 @@ func main() {
flag.IntVar(&globalLimitBps, "global-rate", globalLimitBps, "Global rate limit, in bytes/s")
flag.BoolVar(&debug, "debug", debug, "Enable debug output")
flag.StringVar(&statusAddr, "status-srv", ":22070", "Listen address for status service (blank to disable)")
flag.StringVar(&token, "token", "", "Token to restrict access to the relay (optional). Disables joining any pools.")
flag.StringVar(&poolAddrs, "pools", defaultPoolAddrs, "Comma separated list of relay pool addresses to join")
flag.StringVar(&providedBy, "provided-by", "", "An optional description about who provides the relay")
flag.StringVar(&extAddress, "ext-address", "", "An optional address to advertise as being available on.\n\tAllows listening on an unprivileged port with port forwarding from e.g. 443, and be connected to on port 443.")
@@ -146,7 +147,7 @@ func main() {
log.Println("Connection limit", descriptorLimit)
go monitorLimits()
} else if err != nil && runtime.GOOS != "windows" {
} else if err != nil && !build.IsWindows {
log.Println("Assuming no connection limit, due to error retrieving rlimits:", err)
}
@@ -200,7 +201,7 @@ func main() {
go natSvc.Serve(ctx)
defer cancel()
found := make(chan struct{})
mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) {
mapping.OnChanged(func() {
select {
case found <- struct{}{}:
default:
@@ -230,14 +231,37 @@ func main() {
go statusService(statusAddr)
}
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))
uri, err := url.Parse(fmt.Sprintf("relay://%s/", mapping.Address()))
if err != nil {
log.Fatalln("Failed to construct URI", err)
return
}
// Add properly encoded query string parameters to URL.
query := make(url.Values)
query.Set("id", id.String())
query.Set("pingInterval", pingInterval.String())
query.Set("networkTimeout", networkTimeout.String())
if sessionLimitBps > 0 {
query.Set("sessionLimitBps", fmt.Sprint(sessionLimitBps))
}
if globalLimitBps > 0 {
query.Set("globalLimitBps", fmt.Sprint(globalLimitBps))
}
if statusAddr != "" {
query.Set("statusAddr", statusAddr)
}
if providedBy != "" {
query.Set("providedBy", providedBy)
}
uri.RawQuery = query.Encode()
log.Println("URI:", uri.String())
if token != "" {
poolAddrs = ""
}
if poolAddrs == defaultPoolAddrs {
log.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
log.Println("!! Joining default relay pools, this relay will be available for public use. !!")
@@ -253,7 +277,7 @@ func main() {
}
}
go listener(proto, listen, tlsCfg)
go listener(proto, listen, tlsCfg, token)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
@@ -284,10 +308,10 @@ func main() {
func monitorLimits() {
limitCheckTimer = time.NewTimer(time.Minute)
for range limitCheckTimer.C {
if atomic.LoadInt64(&numConnections)+atomic.LoadInt64(&numProxies) > descriptorLimit {
atomic.StoreInt32(&overLimit, 1)
if numConnections.Load()+numProxies.Load() > descriptorLimit {
overLimit.Store(true)
log.Println("Gone past our connection limits. Starting to refuse new/drop idle connections.")
} else if atomic.CompareAndSwapInt32(&overLimit, 1, 0) {
} else if overLimit.CompareAndSwap(true, false) {
log.Println("Dropped below our connection limits. Accepting new connections.")
}
limitCheckTimer.Reset(time.Minute)

View File

@@ -6,7 +6,7 @@ import (
"bytes"
"crypto/tls"
"encoding/json"
"io/ioutil"
"io"
"log"
"net/http"
"net/url"
@@ -56,7 +56,7 @@ func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certifi
continue
}
bs, err := ioutil.ReadAll(resp.Body)
bs, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Printf("Error joining pool %v: reading response: %v", pool, err)
@@ -74,9 +74,8 @@ func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certifi
log.Printf("Joined pool %s, rejoining in %v", pool, rejoin)
time.Sleep(rejoin)
continue
} else {
log.Printf("Joined pool %s, failed to deserialize response: %v", pool, err)
}
log.Printf("Joined pool %s, failed to deserialize response: %v", pool, err)
case http.StatusInternalServerError:
log.Printf("Failed to join %v: server error", pool)

View File

@@ -23,8 +23,8 @@ var (
sessionMut = sync.RWMutex{}
activeSessions = make([]*session, 0)
pendingSessions = make(map[string]*session)
numProxies int64
bytesProxied int64
numProxies atomic.Int64
bytesProxied atomic.Int64
)
func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionRateLimit, globalRateLimit *rate.Limiter) *session {
@@ -251,8 +251,8 @@ func (s *session) proxy(c1, c2 net.Conn) error {
log.Println("Proxy", c1.RemoteAddr(), "->", c2.RemoteAddr())
}
atomic.AddInt64(&numProxies, 1)
defer atomic.AddInt64(&numProxies, -1)
numProxies.Add(1)
defer numProxies.Add(-1)
buf := make([]byte, networkBufferSize)
for {
@@ -262,7 +262,7 @@ func (s *session) proxy(c1, c2 net.Conn) error {
return err
}
atomic.AddInt64(&bytesProxied, int64(n))
bytesProxied.Add(int64(n))
if debug {
log.Printf("%d bytes from %s to %s", n, c1.RemoteAddr(), c2.RemoteAddr())

View File

@@ -36,7 +36,7 @@ func statusService(addr string) {
}
}
func getStatus(w http.ResponseWriter, r *http.Request) {
func getStatus(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
status := make(map[string]interface{})
@@ -51,9 +51,9 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
status["numPendingSessionKeys"] = len(pendingSessions)
status["numActiveSessions"] = len(activeSessions)
sessionMut.Unlock()
status["numConnections"] = atomic.LoadInt64(&numConnections)
status["numProxies"] = atomic.LoadInt64(&numProxies)
status["bytesProxied"] = atomic.LoadInt64(&bytesProxied)
status["numConnections"] = numConnections.Load()
status["numProxies"] = numProxies.Load()
status["bytesProxied"] = bytesProxied.Load()
status["goVersion"] = runtime.Version()
status["goOS"] = runtime.GOOS
status["goArch"] = runtime.GOARCH
@@ -88,13 +88,13 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
}
type rateCalculator struct {
counter *int64 // atomic, must remain 64-bit aligned
counter *atomic.Int64
rates []int64
prev int64
startTime time.Time
}
func newRateCalculator(keepIntervals int, interval time.Duration, counter *int64) *rateCalculator {
func newRateCalculator(keepIntervals int, interval time.Duration, counter *atomic.Int64) *rateCalculator {
r := &rateCalculator{
rates: make([]int64, keepIntervals),
counter: counter,
@@ -112,7 +112,7 @@ func (r *rateCalculator) updateRates(interval time.Duration) {
next := now.Truncate(interval).Add(interval)
time.Sleep(next.Sub(now))
cur := atomic.LoadInt64(r.counter)
cur := r.counter.Load()
rate := int64(float64(cur-r.prev) / interval.Seconds())
copy(r.rates[1:], r.rates)
r.rates[0] = rate

View File

@@ -57,7 +57,7 @@ func main() {
if join {
log.Println("Creating client")
relay, err := client.NewClient(uri, []tls.Certificate{cert}, nil, 10*time.Second)
relay, err := client.NewClient(uri, []tls.Certificate{cert}, 10*time.Second)
if err != nil {
log.Fatal(err)
}
@@ -127,10 +127,6 @@ func stdinReader(c chan<- string) {
}
func connectToStdio(stdin <-chan string, conn net.Conn) {
go func() {
}()
buf := make([]byte, 1024)
for {
conn.SetReadDeadline(time.Now().Add(time.Millisecond))

View File

@@ -9,7 +9,6 @@ package main
import (
"flag"
"io"
"io/ioutil"
"log"
"os"
@@ -69,7 +68,7 @@ func gen() {
}
func sign(keyname, dataname string) {
privkey, err := ioutil.ReadFile(keyname)
privkey, err := os.ReadFile(keyname)
if err != nil {
log.Fatal(err)
}
@@ -95,7 +94,7 @@ func sign(keyname, dataname string) {
}
func verifyWithFile(signame, dataname, keyname string) {
pubkey, err := ioutil.ReadFile(keyname)
pubkey, err := os.ReadFile(keyname)
if err != nil {
log.Fatal(err)
}
@@ -103,7 +102,7 @@ func verifyWithFile(signame, dataname, keyname string) {
}
func verifyWithKey(signame, dataname string, pubkey []byte) {
sig, err := ioutil.ReadFile(signame)
sig, err := os.ReadFile(signame)
if err != nil {
log.Fatal(err)
}

View File

@@ -7,31 +7,112 @@
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"sort"
"strings"
"time"
"github.com/alecthomas/kong"
"github.com/syncthing/syncthing/lib/httpcache"
"github.com/syncthing/syncthing/lib/upgrade"
)
const defaultURL = "https://api.github.com/repos/syncthing/syncthing/releases?per_page=25"
type cli struct {
Listen string `default:":8080" help:"Listen address"`
URL string `short:"u" default:"https://api.github.com/repos/syncthing/syncthing/releases?per_page=25" help:"GitHub releases url"`
Forward []string `short:"f" help:"Forwarded pages, format: /path->https://example/com/url"`
CacheTime time.Duration `default:"15m" help:"Cache time"`
}
func main() {
url := flag.String("u", defaultURL, "GitHub releases url")
flag.Parse()
rels := upgrade.FetchLatestReleases(*url, "")
if rels == nil {
// An error was already logged
var params cli
kong.Parse(&params)
if err := server(&params); err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}
func server(params *cli) error {
http.Handle("/meta.json", httpcache.SinglePath(&githubReleases{url: params.URL}, params.CacheTime))
for _, fwd := range params.Forward {
path, url, ok := strings.Cut(fwd, "->")
if !ok {
return fmt.Errorf("invalid forward: %q", fwd)
}
http.Handle(path, httpcache.SinglePath(&proxy{url: url}, params.CacheTime))
}
return http.ListenAndServe(params.Listen, nil)
}
type githubReleases struct {
url string
}
func (p *githubReleases) ServeHTTP(w http.ResponseWriter, req *http.Request) {
log.Println("Fetching", p.url)
rels := upgrade.FetchLatestReleases(p.url, "")
if rels == nil {
http.Error(w, "no releases", http.StatusInternalServerError)
return
}
sort.Sort(upgrade.SortByRelease(rels))
rels = filterForLatest(rels)
if err := json.NewEncoder(os.Stdout).Encode(rels); err != nil {
os.Exit(1)
buf := new(bytes.Buffer)
_ = json.NewEncoder(buf).Encode(rels)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Write(buf.Bytes())
}
type proxy struct {
url string
}
func (p *proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
log.Println("Fetching", p.url)
req, err := http.NewRequestWithContext(req.Context(), http.MethodGet, p.url, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
ct := resp.Header.Get("Content-Type")
w.Header().Set("Content-Type", ct)
if resp.StatusCode == http.StatusOK {
w.Header().Set("Cache-Control", "public, max-age=900")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
}
w.WriteHeader(resp.StatusCode)
if strings.HasPrefix(ct, "application/json") {
// Special JSON handling; clean it up a bit.
var v interface{}
if err := json.NewDecoder(resp.Body).Decode(&v); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(v)
} else {
_, _ = io.Copy(w, resp.Body)
}
}

View File

@@ -44,7 +44,7 @@ func main() {
found := make(chan result)
stop := make(chan struct{})
var count int64
var count atomic.Int64
// Print periodic progress reports.
go printProgress(prefix, &count)
@@ -72,7 +72,7 @@ func main() {
// Try certificates until one is found that has the prefix at the start of
// the resulting device ID. Increments count atomically, sends the result to
// found, returns when stop is closed.
func generatePrefixed(prefix string, count *int64, found chan<- result, stop <-chan struct{}) {
func generatePrefixed(prefix string, count *atomic.Int64, found chan<- result, stop <-chan struct{}) {
notBefore := time.Now()
notAfter := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
@@ -109,7 +109,7 @@ func generatePrefixed(prefix string, count *int64, found chan<- result, stop <-c
}
id := protocol.NewDeviceID(derBytes)
atomic.AddInt64(count, 1)
count.Add(1)
if strings.HasPrefix(id.String(), prefix) {
select {
@@ -121,7 +121,7 @@ func generatePrefixed(prefix string, count *int64, found chan<- result, stop <-c
}
}
func printProgress(prefix string, count *int64) {
func printProgress(prefix string, count *atomic.Int64) {
started := time.Now()
wantBits := 5 * len(prefix)
if wantBits > 63 {
@@ -132,7 +132,7 @@ func printProgress(prefix string, count *int64) {
fmt.Printf("Want %d bits for prefix %q, about %.2g certs to test (statistically speaking)\n", wantBits, prefix, expectedIterations)
for range time.NewTicker(15 * time.Second).C {
tried := atomic.LoadInt64(count)
tried := count.Load()
elapsed := time.Since(started)
rate := float64(tried) / elapsed.Seconds()
expected := timeStr(expectedIterations / rate)

View File

@@ -10,8 +10,10 @@ import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"net/http"
"strings"
@@ -25,6 +27,7 @@ import (
type APIClient interface {
Get(url string) (*http.Response, error)
Post(url, body string) (*http.Response, error)
PutJSON(url string, o interface{}) (*http.Response, error)
}
type apiClient struct {
@@ -118,28 +121,46 @@ func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
return resp, checkResponse(resp)
}
func (c *apiClient) Get(url string) (*http.Response, error) {
request, err := http.NewRequest("GET", c.Endpoint()+"rest/"+url, nil)
func (c *apiClient) Request(url, method string, r io.Reader) (*http.Response, error) {
request, err := http.NewRequest(method, c.Endpoint()+"rest/"+url, r)
if err != nil {
return nil, err
}
return c.Do(request)
}
func (c *apiClient) RequestString(url, method, data string) (*http.Response, error) {
return c.Request(url, method, bytes.NewBufferString(data))
}
func (c *apiClient) RequestJSON(url, method string, o interface{}) (*http.Response, error) {
data, err := json.Marshal(o)
if err != nil {
return nil, err
}
return c.Request(url, method, bytes.NewBuffer(data))
}
func (c *apiClient) Get(url string) (*http.Response, error) {
return c.RequestString(url, "GET", "")
}
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)
return c.RequestString(url, "POST", body)
}
func (c *apiClient) PutJSON(url string, o interface{}) (*http.Response, error) {
return c.RequestJSON(url, "PUT", o)
}
var errNotFound = errors.New("invalid endpoint or API call")
func checkResponse(response *http.Response) error {
if response.StatusCode == 404 {
return errors.New("invalid endpoint or API call")
} else if response.StatusCode == 403 {
if response.StatusCode == http.StatusNotFound {
return errNotFound
} else if response.StatusCode == http.StatusUnauthorized {
return errors.New("invalid API key")
} else if response.StatusCode != 200 {
} else if response.StatusCode != http.StatusOK {
data, err := responseToBArray(response)
if err != nil {
return err

View File

@@ -8,11 +8,11 @@ package cli
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"github.com/AudriusButkevicius/recli"
"github.com/pkg/errors"
"github.com/syncthing/syncthing/lib/config"
"github.com/urfave/cli"
)
@@ -60,7 +60,7 @@ func (h *configHandler) configBefore(c *cli.Context) error {
return h.err
}
func (h *configHandler) configAfter(c *cli.Context) error {
func (h *configHandler) configAfter(_ *cli.Context) error {
if h.err != nil {
// Error was already returned in configBefore
return nil

View File

@@ -8,6 +8,7 @@ package cli
import (
"fmt"
"net/url"
"github.com/urfave/cli"
)
@@ -35,7 +36,10 @@ var debugCommand = cli.Command{
func debugFile() cli.ActionFunc {
return func(c *cli.Context) error {
return indexDumpOutput(fmt.Sprintf("debug/file?folder=%v&file=%v", c.Args()[0], normalizePath(c.Args()[1])))(c)
query := make(url.Values)
query.Set("folder", c.Args()[0])
query.Set("file", normalizePath(c.Args()[1]))
return indexDumpOutput("debug/file?" + query.Encode())(c)
}
}

View File

@@ -27,7 +27,7 @@ var errorsCommand = cli.Command{
{
Name: "push",
Usage: "Push an error to active clients",
ArgsUsage: "[error message]",
ArgsUsage: "ERROR-MESSAGE",
Action: expects(1, errorsPush),
},
{

View File

@@ -7,53 +7,35 @@
package cli
import (
"container/heap"
"encoding/binary"
"fmt"
"sort"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/lib/db"
)
type SizedElement struct {
key string
size int
}
type ElementHeap []SizedElement
func (h ElementHeap) Len() int { return len(h) }
func (h ElementHeap) Less(i, j int) bool { return h[i].size > h[j].size }
func (h ElementHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *ElementHeap) Push(x interface{}) {
*h = append(*h, x.(SizedElement))
}
func (h *ElementHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func indexDumpSize(*cli.Context) error {
type sizedElement struct {
key string
size int
}
ldb, err := getDB()
if err != nil {
return err
}
h := &ElementHeap{}
heap.Init(h)
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
return err
}
var ele SizedElement
var elems []sizedElement
for it.Next() {
var ele sizedElement
key := it.Key()
switch key[0] {
case db.KeyTypeDevice:
@@ -94,11 +76,13 @@ func indexDumpSize(*cli.Context) error {
ele.key = fmt.Sprintf("UNKNOWN:%x", key)
}
ele.size = len(it.Value())
heap.Push(h, ele)
elems = append(elems, ele)
}
for h.Len() > 0 {
ele = heap.Pop(h).(SizedElement)
sort.Slice(elems, func(i, j int) bool {
return elems[i].size > elems[j].size
})
for _, ele := range elems {
fmt.Println(ele.key, ele.size)
}

View File

@@ -57,7 +57,7 @@ func indexCheck(*cli.Context) (err error) {
defer func() {
if err == nil {
if success {
fmt.Println("Index check completed succesfully.")
fmt.Println("Index check completed successfully.")
} else {
err = errors.New("Inconsistencies found in the index")
}
@@ -349,7 +349,7 @@ func indexCheck(*cli.Context) (err error) {
func needsLocally(vl db.VersionList) bool {
gfv, gok := vl.GetGlobal()
if !gok { // That's weird, but we hardly need something non-existant
if !gok { // That's weird, but we hardly need something non-existent
return false
}
fv, ok := vl.Get(protocol.LocalDeviceID[:])

View File

@@ -8,14 +8,14 @@ package cli
import (
"bufio"
"io/ioutil"
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/alecthomas/kong"
"github.com/flynn-archive/go-shlex"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
@@ -38,11 +38,20 @@ func Run() error {
// add flags there...
c := preCli{}
parseFlags(&c)
return runInternal(c, os.Args)
}
func RunWithArgs(cliArgs []string) error {
c := preCli{}
parseFlagsWithArgs(cliArgs, &c)
return runInternal(c, cliArgs)
}
func runInternal(c preCli, cliArgs []string) error {
// 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:")
return fmt.Errorf("Command line options: %w", err)
}
clientFactory := &apiClientFactory{
cfg: config.GUIConfiguration{
@@ -61,23 +70,23 @@ func Run() error {
fakeFlags := []cli.Flag{
cli.StringFlag{
Name: "gui-address",
Value: "URL",
Usage: "Override GUI address (e.g. \"http://192.0.2.42:8443\")",
Usage: "Override GUI address to `URL` (e.g. \"192.0.2.42:8443\")",
},
cli.StringFlag{
Name: "gui-apikey",
Value: "API-KEY",
Usage: "Override GUI API key",
Usage: "Override GUI API key to `API-KEY`",
},
cli.StringFlag{
Name: "home",
Value: "PATH",
Usage: "Set configuration and data directory",
Usage: "Set configuration and data directory to `PATH`",
},
cli.StringFlag{
Name: "conf",
Value: "PATH",
Usage: "Set configuration directory (config and keys)",
Name: "config",
Usage: "Set configuration directory (config and keys) to `PATH`",
},
cli.StringFlag{
Name: "data",
Usage: "Set data directory (database and logs) to `PATH`",
},
}
@@ -97,38 +106,41 @@ func Run() error {
operationCommand,
errorsCommand,
debugCommand,
{
Name: "-",
HideHelp: true,
Usage: "Read commands from stdin",
Action: func(ctx *cli.Context) error {
if ctx.NArg() > 0 {
return errors.New("command does not expect any arguments")
}
// Drop the `-` not to recurse into self.
args := make([]string, len(cliArgs)-1)
copy(args, cliArgs)
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 fmt.Errorf("parsing input: %w", err)
}
if len(input) == 0 {
continue
}
err = app.Run(append(args, input...))
if err != nil {
return err
}
}
return scanner.Err()
},
},
},
}}
tty := isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd())
if !tty {
// Not a TTY, consume from stdin
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input, err := shlex.Split(scanner.Text())
if err != nil {
return errors.Wrap(err, "parsing input")
}
if len(input) == 0 {
continue
}
err = app.Run(append(os.Args, input...))
if err != nil {
return err
}
}
err = scanner.Err()
if err != nil {
return err
}
} else {
err = app.Run(os.Args)
if err != nil {
return err
}
}
return nil
return app.Run(cliArgs)
}
func parseFlags(c *preCli) error {
@@ -137,7 +149,10 @@ func parseFlags(c *preCli) error {
if len(os.Args) <= 2 {
return nil
}
args := os.Args[2:]
return parseFlagsWithArgs(os.Args[2:], c)
}
func parseFlagsWithArgs(args []string, c *preCli) error {
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "--") {
args = args[:i]
@@ -148,7 +163,7 @@ func parseFlags(c *preCli) error {
}
}
// 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) {}))
parser, err := kong.New(c, kong.Writers(io.Discard, io.Discard), kong.Exit(func(int) {}))
if err != nil {
return err
}

View File

@@ -7,8 +7,13 @@
package cli
import (
"bufio"
"errors"
"fmt"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/fs"
"github.com/urfave/cli"
)
@@ -35,9 +40,15 @@ var operationCommand = cli.Command{
{
Name: "folder-override",
Usage: "Override changes on folder (remote for sendonly, local for receiveonly). WARNING: Destructive - deletes/changes your data.",
ArgsUsage: "[folder id]",
ArgsUsage: "FOLDER-ID",
Action: expects(1, foldersOverride),
},
{
Name: "default-ignores",
Usage: "Set the default ignores (config) from a file",
ArgsUsage: "PATH",
Action: expects(1, setDefaultIgnores),
},
},
}
@@ -67,10 +78,36 @@ func foldersOverride(c *cli.Context) error {
if body != "" {
errStr += "\nBody: " + body
}
return fmt.Errorf(errStr)
return errors.New(errStr)
}
return nil
}
}
return fmt.Errorf("Folder " + rid + " not found")
return fmt.Errorf("Folder %q not found", rid)
}
func setDefaultIgnores(c *cli.Context) error {
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
dir, file := filepath.Split(c.Args()[0])
filesystem := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
fd, err := filesystem.Open(file)
if err != nil {
return err
}
scanner := bufio.NewScanner(fd)
var lines []string
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
fd.Close()
if err := scanner.Err(); err != nil {
return err
}
_, err = client.PutJSON("config/defaults/ignores", config.Ignores{Lines: lines})
return err
}

View File

@@ -0,0 +1,45 @@
// 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 (
"net/url"
"github.com/urfave/cli"
)
var pendingCommand = cli.Command{
Name: "pending",
HideHelp: true,
Usage: "Pending subcommand group",
Subcommands: []cli.Command{
{
Name: "devices",
Usage: "Show pending devices",
Action: expects(0, indexDumpOutput("cluster/pending/devices")),
},
{
Name: "folders",
Usage: "Show pending folders",
Flags: []cli.Flag{
cli.StringFlag{Name: "device", Usage: "Show pending folders offered by given device"},
},
Action: expects(0, folders()),
},
},
}
func folders() cli.ActionFunc {
return func(c *cli.Context) error {
if c.String("device") != "" {
query := make(url.Values)
query.Set("device", c.String("device"))
return indexDumpOutput("cluster/pending/folders?" + query.Encode())(c)
}
return indexDumpOutput("cluster/pending/folders")(c)
}
}

View File

@@ -35,6 +35,12 @@ var showCommand = cli.Command{
Usage: "Report about connections to other devices",
Action: expects(0, indexDumpOutput("system/connections")),
},
{
Name: "discovery",
Usage: "Show the discovered addresses of remote devices (from cache of the running syncthing instance)",
Action: expects(0, indexDumpOutput("system/discovery")),
},
pendingCommand,
{
Name: "usage",
Usage: "Show usage report",

View File

@@ -10,7 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"mime"
"net/http"
"os"
@@ -23,7 +23,7 @@ import (
)
func responseToBArray(response *http.Response) ([]byte, error) {
bytes, err := ioutil.ReadAll(response.Body)
bytes, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
@@ -48,10 +48,13 @@ func indexDumpOutput(url string) cli.ActionFunc {
return err
}
response, err := client.Get(url)
if errors.Is(err, errNotFound) {
return errors.New("not found (folder/file not in database)")
}
if err != nil {
return err
}
return prettyPrintResponse(c, response)
return prettyPrintResponse(response)
}
}
@@ -102,8 +105,8 @@ func getConfig(c APIClient) (config.Configuration, error) {
return cfg, err
}
err = json.Unmarshal(bytes, &cfg)
if err == nil {
return cfg, err
if err != nil {
return config.Configuration{}, err
}
return cfg, nil
}
@@ -127,7 +130,7 @@ func prettyPrintJSON(data interface{}) error {
return enc.Encode(data)
}
func prettyPrintResponse(c *cli.Context, response *http.Response) error {
func prettyPrintResponse(response *http.Response) error {
bytes, err := responseToBArray(response)
if err != nil {
return err

View File

@@ -0,0 +1,16 @@
// 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 cmdutil
// CommonOptions are reused among several subcommands
type CommonOptions struct {
buildCommonOptions
ConfDir string `name:"config" placeholder:"PATH" help:"Set configuration directory (config and keys)"`
HomeDir string `name:"home" placeholder:"PATH" help:"Set configuration and data directory"`
NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"`
SkipPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup"`
}

View File

@@ -4,10 +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/.
//go:build !windows
// +build !windows
package main
package cmdutil
type buildServeOptions struct {
type buildCommonOptions struct {
HideConsole bool `hidden:""`
}

View File

@@ -4,8 +4,8 @@
// 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 cmdutil
type buildServeOptions struct {
type buildCommonOptions struct {
HideConsole bool `name:"no-console" help:"Hide console window"`
}

View File

@@ -18,9 +18,9 @@ func SetConfigDataLocationsFromFlags(homeDir, confDir, dataDir string) error {
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")
return errors.New("either both or none of --config 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")
return errors.New("--home must not be used together with --config and --data")
case homeSet:
confDir = homeDir
dataDir = homeDir

View File

@@ -10,7 +10,6 @@ import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -62,7 +61,7 @@ func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
// the log contents. A HEAD request is made to see if the log has already
// been reported. If not, a PUT is made with the log contents.
func uploadPanicLog(ctx context.Context, urlBase, file string) error {
data, err := ioutil.ReadFile(file)
data, err := os.ReadFile(file)
if err != nil {
return err
}

View File

@@ -10,10 +10,11 @@ package decrypt
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
@@ -34,6 +35,7 @@ type CLI struct {
TokenPath string `placeholder:"PATH" help:"Path to the token file within the folder (used to determine folder ID)"`
folderKey *[32]byte
keyGen *protocol.KeyGenerator
}
type storedEncryptionToken struct {
@@ -45,7 +47,7 @@ func (c *CLI) Run() error {
log.SetFlags(0)
if c.To == "" && !c.VerifyOnly {
return fmt.Errorf("must set --to or --verify")
return errors.New("must set --to or --verify-only")
}
if c.TokenPath == "" {
@@ -67,7 +69,8 @@ func (c *CLI) Run() error {
}
}
c.folderKey = protocol.KeyFromPassword(c.FolderID, c.Password)
c.keyGen = protocol.NewKeyGenerator()
c.folderKey = c.keyGen.KeyFromPassword(c.FolderID, c.Password)
return c.walk()
}
@@ -112,7 +115,7 @@ func (c *CLI) withContinue(err error) error {
// error.
func (c *CLI) getFolderID() (string, error) {
tokenPath := filepath.Join(c.Path, c.TokenPath)
bs, err := ioutil.ReadFile(tokenPath)
bs, err := os.ReadFile(tokenPath)
if err != nil {
return "", fmt.Errorf("reading folder token: %w", err)
}
@@ -128,6 +131,9 @@ func (c *CLI) getFolderID() (string, error) {
// 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 {
// Which filemode bits to preserve
const retainBits = fs.ModePerm | fs.ModeSetgid | fs.ModeSetuid | fs.ModeSticky
if c.Verbose {
log.Printf("Processing %q", path)
}
@@ -138,7 +144,7 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
}
defer encFd.Close()
encFi, err := c.loadEncryptedFileInfo(encFd)
encFi, err := loadEncryptedFileInfo(encFd)
if err != nil {
return fmt.Errorf("%s: loading metadata trailer: %w", path, err)
}
@@ -147,7 +153,7 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
// in native format, while protocol expects wire format (slashes).
encFi.Name = osutil.NormalizedFilename(encFi.Name)
plainFi, err := protocol.DecryptFileInfo(*encFi, c.folderKey)
plainFi, err := protocol.DecryptFileInfo(c.keyGen, *encFi, c.folderKey)
if err != nil {
return fmt.Errorf("%s: decrypting metadata: %w", path, err)
}
@@ -158,7 +164,7 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
var plainFd fs.File
if dstFs != nil {
if err := dstFs.MkdirAll(filepath.Dir(plainFi.Name), 0700); err != nil {
if err := dstFs.MkdirAll(filepath.Dir(plainFi.Name), 0o700); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
@@ -167,6 +173,9 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
defer plainFd.Close() // also closed explicitly in the return
if err := dstFs.Chmod(plainFi.Name, fs.FileMode(plainFi.Permissions&uint32(retainBits))); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
}
if err := c.decryptFile(encFi, &plainFi, encFd, plainFd); err != nil {
@@ -183,7 +192,12 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
}
if plainFd != nil {
return plainFd.Close()
if err := plainFd.Close(); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
if err := dstFs.Chtimes(plainFi.Name, plainFi.ModTime(), plainFi.ModTime()); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
}
return nil
}
@@ -197,7 +211,7 @@ func (c *CLI) decryptFile(encFi *protocol.FileInfo, plainFi *protocol.FileInfo,
return fmt.Errorf("block count mismatch: encrypted %d != plaintext %d", len(encFi.Blocks), len(plainFi.Blocks))
}
fileKey := protocol.FileKey(plainFi.Name, c.folderKey)
fileKey := c.keyGen.FileKey(plainFi.Name, c.folderKey)
for i, encBlock := range encFi.Blocks {
// Read the encrypted block
buf := make([]byte, encBlock.Size)
@@ -246,7 +260,7 @@ func (c *CLI) decryptFile(encFi *protocol.FileInfo, plainFi *protocol.FileInfo,
// loadEncryptedFileInfo loads the encrypted FileInfo trailer from a file on
// disk.
func (c *CLI) loadEncryptedFileInfo(fd fs.File) (*protocol.FileInfo, error) {
func 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

View File

@@ -0,0 +1,136 @@
// 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 generate implements the `syncthing generate` subcommand.
package generate
import (
"bufio"
"context"
"crypto/tls"
"errors"
"fmt"
"os"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/logger"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/syncthing"
)
type CLI struct {
cmdutil.CommonOptions
GUIUser string `placeholder:"STRING" help:"Specify new GUI authentication user name"`
GUIPassword string `placeholder:"STRING" help:"Specify new GUI authentication password (use - to read from standard input)"`
}
func (c *CLI) Run(l logger.Logger) error {
if c.HideConsole {
osutil.HideConsole()
}
if c.HomeDir != "" {
if c.ConfDir != "" {
return errors.New("--home must not be used together with --config")
}
c.ConfDir = c.HomeDir
}
if c.ConfDir == "" {
c.ConfDir = locations.GetBaseDir(locations.ConfigBaseDir)
}
// Support reading the password from a pipe or similar
if c.GUIPassword == "-" {
reader := bufio.NewReader(os.Stdin)
password, _, err := reader.ReadLine()
if err != nil {
return fmt.Errorf("failed reading GUI password: %w", err)
}
c.GUIPassword = string(password)
}
if err := Generate(l, c.ConfDir, c.GUIUser, c.GUIPassword, c.NoDefaultFolder, c.SkipPortProbing); err != nil {
return fmt.Errorf("failed to generate config and keys: %w", err)
}
return nil
}
func Generate(l logger.Logger, confDir, guiUser, guiPassword string, noDefaultFolder, skipPortProbing bool) error {
dir, err := fs.ExpandTilde(confDir)
if err != nil {
return err
}
if err := syncthing.EnsureDir(dir, 0700); err != nil {
return err
}
locations.SetBaseDir(locations.ConfigBaseDir, dir)
var myID protocol.DeviceID
certFile, keyFile := locations.Get(locations.CertFile), locations.Get(locations.KeyFile)
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
l.Warnln("Key exists; will not overwrite.")
} else {
cert, err = syncthing.GenerateCertificate(certFile, keyFile)
if err != nil {
return fmt.Errorf("create certificate: %w", err)
}
}
myID = protocol.NewDeviceID(cert.Certificate[0])
l.Infoln("Device ID:", myID)
cfgFile := locations.Get(locations.ConfigFile)
cfg, _, err := config.Load(cfgFile, myID, events.NoopLogger)
if fs.IsNotExist(err) {
if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder, skipPortProbing); err != nil {
return fmt.Errorf("create config: %w", err)
}
} else if err != nil {
return fmt.Errorf("load config: %w", err)
}
ctx, cancel := context.WithCancel(context.Background())
go cfg.Serve(ctx)
defer cancel()
var updateErr error
waiter, err := cfg.Modify(func(cfg *config.Configuration) {
updateErr = updateGUIAuthentication(l, &cfg.GUI, guiUser, guiPassword)
})
if err != nil {
return fmt.Errorf("modify config: %w", err)
}
waiter.Wait()
if updateErr != nil {
return updateErr
}
if err := cfg.Save(); err != nil {
return fmt.Errorf("save config: %w", err)
}
return nil
}
func updateGUIAuthentication(l logger.Logger, guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
if guiUser != "" && guiCfg.User != guiUser {
guiCfg.User = guiUser
l.Infoln("Updated GUI authentication user name:", guiUser)
}
if guiPassword != "" && guiCfg.Password != guiPassword {
if err := guiCfg.HashAndSetPassword(guiPassword); err != nil {
return fmt.Errorf("failed to set GUI authentication password: %w", err)
}
l.Infoln("Updated GUI authentication password.")
}
return nil
}

View File

@@ -10,9 +10,9 @@ import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
_ "net/http/pprof" // Need to import this to support STPROFILER.
@@ -36,6 +36,7 @@ import (
"github.com/syncthing/syncthing/cmd/syncthing/cli"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/cmd/syncthing/decrypt"
"github.com/syncthing/syncthing/cmd/syncthing/generate"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/db"
@@ -49,16 +50,11 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/svcutil"
"github.com/syncthing/syncthing/lib/syncthing"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/pkg/errors"
)
const (
tlsDefaultCommonName = "syncthing"
deviceCertLifetimeDays = 20 * 365
sigTerm = syscall.Signal(15)
sigTerm = syscall.Signal(15)
)
const (
@@ -71,14 +67,14 @@ The --logflags value is a sum of the following:
8 Long filename
16 Short filename
I.e. to prefix each log line with date and time, set --logflags=3 (1 + 2 from
above). The value 0 is used to disable all of the above. The default is to
show time only (2).
I.e. to prefix each log line with time and filename, set --logflags=18 (2 + 16
from above). The value 0 is used to disable all of the above. The default is
to show date and time (3).
Logging always happens to the command line (stdout) and optionally to the
file at the path specified by -logfile=path. In addition to an path, the special
file at the path specified by --logfile=path. In addition to an path, the special
values "default" and "-" may be used. The former logs to DATADIR/syncthing.log
(see -data-dir), which is the default on Windows, and the latter only to stdout,
(see --data), which is the default on Windows, and the latter only to stdout,
no file, which is the default anywhere else.
@@ -135,32 +131,30 @@ var (
// commands and options here are top level commands to syncthing.
// Cli is just a placeholder for the help text (see main).
var entrypoint struct {
Serve serveOptions `cmd:"" help:"Run Syncthing"`
Decrypt decrypt.CLI `cmd:"" help:"Decrypt or verify an encrypted folder"`
Cli struct{} `cmd:"" help:"Command line interface for Syncthing"`
Serve serveOptions `cmd:"" help:"Run Syncthing"`
Generate generate.CLI `cmd:"" help:"Generate key and config, then exit"`
Decrypt decrypt.CLI `cmd:"" help:"Decrypt or verify an encrypted folder"`
Cli struct{} `cmd:"" help:"Command line interface for Syncthing"`
}
// serveOptions are the options for the `syncthing serve` command.
type serveOptions struct {
buildServeOptions
cmdutil.CommonOptions
AllowNewerConfig bool `help:"Allow loading newer than current config version"`
Audit bool `help:"Write events to audit file"`
AuditFile string `name:"auditfile" placeholder:"PATH" help:"Specify audit file (use \"-\" for stdout, \"--\" for stderr)"`
BrowserOnly bool `help:"Open GUI in browser"`
ConfDir string `name:"config" placeholder:"PATH" help:"Set configuration directory (config and keys)"`
DataDir string `name:"data" placeholder:"PATH" help:"Set data directory (database and logs)"`
DeviceID bool `help:"Show the device ID"`
GenerateDir string `name:"generate" placeholder:"PATH" help:"Generate key and config in specified dir, then exit"`
GenerateDir string `name:"generate" placeholder:"PATH" help:"Generate key and config in specified dir, then exit"` //DEPRECATED: replaced by subcommand!
GUIAddress string `name:"gui-address" placeholder:"URL" help:"Override GUI address (e.g. \"http://192.0.2.42:8443\")"`
GUIAPIKey string `name:"gui-apikey" placeholder:"API-KEY" help:"Override GUI API key"`
HomeDir string `name:"home" placeholder:"PATH" help:"Set configuration and data directory"`
LogFile string `name:"logfile" default:"${logFile}" placeholder:"PATH" help:"Log file name (see below)"`
LogFlags int `name:"logflags" default:"${logFlags}" placeholder:"BITS" help:"Select information in log line prefix (see below)"`
LogMaxFiles int `placeholder:"N" default:"${logMaxFiles}" name:"log-max-old-files" help:"Number of old files to keep (zero to keep only current)"`
LogMaxSize int `placeholder:"BYTES" default:"${logMaxSize}" help:"Maximum size of any file (zero to disable log rotation)"`
NoBrowser bool `help:"Do not start browser"`
NoRestart bool `env:"STNORESTART" help:"Do not restart Syncthing when exiting due to API/GUI command, upgrade, or crash"`
NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"`
NoUpgrade bool `env:"STNOUPGRADE" help:"Disable automatic upgrades"`
Paths bool `help:"Show configuration paths"`
Paused bool `help:"Start with all devices and folders paused"`
@@ -178,7 +172,7 @@ type serveOptions struct {
DebugGUIAssetsDir string `placeholder:"PATH" help:"Directory to load GUI assets from" env:"STGUIASSETS"`
DebugPerfStats bool `env:"STPERFSTATS" help:"Write running performance statistics to perf-$pid.csv (Unix only)"`
DebugProfileBlock bool `env:"STBLOCKPROFILE" help:"Write block profiles to block-$pid-$timestamp.pprof every 20 seconds"`
DebugProfileCPU bool `help:"Write a CPU profile to cpu-$pid.pprof on exit" env:"CPUPROFILE"`
DebugProfileCPU bool `help:"Write a CPU profile to cpu-$pid.pprof on exit" env:"STCPUPROFILE"`
DebugProfileHeap bool `env:"STHEAPPROFILE" help:"Write heap profiles to heap-$pid-$timestamp.pprof each time heap usage increases"`
DebugProfilerListen string `placeholder:"ADDR" env:"STPROFILER" help:"Network profiler listen address"`
DebugResetDatabase bool `name:"reset-database" help:"Reset the database, forcing a full rescan and resync"`
@@ -192,7 +186,7 @@ type serveOptions struct {
func defaultVars() kong.Vars {
vars := kong.Vars{}
vars["logFlags"] = strconv.Itoa(log.Ltime)
vars["logFlags"] = strconv.Itoa(logger.DefaultFlags)
vars["logMaxSize"] = strconv.Itoa(10 << 20) // 10 MiB
vars["logMaxFiles"] = "3" // plus the current one
@@ -204,7 +198,7 @@ func defaultVars() kong.Vars {
// Windows, the "default" options.logFile will later be replaced with the
// default path, unless the user has manually specified "-" or
// something else.
if runtime.GOOS == "windows" {
if build.IsWindows {
vars["logFile"] = "default"
} else {
vars["logFile"] = "-"
@@ -257,6 +251,7 @@ func main() {
ctx, err := parser.Parse(args)
parser.FatalIfErrorf(err)
ctx.BindTo(l, (*logger.Logger)(nil)) // main logger available to subcommands
err = ctx.Run()
parser.FatalIfErrorf(err)
}
@@ -297,16 +292,25 @@ func (options serveOptions) Run() error {
os.Exit(svcutil.ExitError.AsInt())
}
if options.LogFile == "default" || options.LogFile == "" {
// Treat an explicitly empty log file name as no log file
if options.LogFile == "" {
options.LogFile = "-"
}
if options.LogFile != "default" {
// We must set this *after* expandLocations above.
// Handling an empty value is for backwards compatibility (<1.4.1).
options.LogFile = locations.Get(locations.LogFile)
if err := locations.Set(locations.LogFile, options.LogFile); err != nil {
l.Warnln("Setting log file path:", err)
os.Exit(svcutil.ExitError.AsInt())
}
}
if options.DebugGUIAssetsDir == "" {
if options.DebugGUIAssetsDir != "" {
// The asset dir is blank if STGUIASSETS wasn't set, in which case we
// should look for extra assets in the default place.
options.DebugGUIAssetsDir = locations.Get(locations.GUIAssets)
if err := locations.Set(locations.GUIAssets, options.DebugGUIAssetsDir); err != nil {
l.Warnln("Setting GUI assets path:", err)
os.Exit(svcutil.ExitError.AsInt())
}
}
if options.Version {
@@ -315,7 +319,7 @@ func (options serveOptions) Run() error {
}
if options.Paths {
showPaths(options)
fmt.Print(locations.PrettyPaths())
return nil
}
@@ -334,7 +338,7 @@ func (options serveOptions) Run() error {
}
if options.BrowserOnly {
if err := openGUI(protocol.EmptyDeviceID); err != nil {
if err := openGUI(); err != nil {
l.Warnln("Failed to open web UI:", err)
os.Exit(svcutil.ExitError.AsInt())
}
@@ -342,7 +346,7 @@ func (options serveOptions) Run() error {
}
if options.GenerateDir != "" {
if err := generate(options.GenerateDir, options.NoDefaultFolder); err != nil {
if err := generate.Generate(l, options.GenerateDir, "", "", options.NoDefaultFolder, options.SkipPortProbing); err != nil {
l.Warnln("Failed to generate config and keys:", err)
os.Exit(svcutil.ExitError.AsInt())
}
@@ -350,7 +354,7 @@ func (options serveOptions) Run() error {
}
// Ensure that our home directory exists.
if err := ensureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
if err := syncthing.EnsureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
l.Warnln("Failure on home directory:", err)
os.Exit(svcutil.ExitError.AsInt())
}
@@ -411,13 +415,13 @@ func (options serveOptions) Run() error {
return nil
}
func openGUI(myID protocol.DeviceID) error {
cfg, err := loadOrDefaultConfig(myID, events.NoopLogger, true)
func openGUI() error {
cfg, err := loadOrDefaultConfig()
if err != nil {
return err
}
if cfg.GUI().Enabled {
if err := openURL(cfg.GUI().URL()); err != nil {
if guiCfg := cfg.GUI(); guiCfg.Enabled {
if err := openURL(guiCfg.URL()); err != nil {
return err
}
} else {
@@ -426,46 +430,6 @@ func openGUI(myID protocol.DeviceID) error {
return nil
}
func generate(generateDir string, noDefaultFolder bool) error {
dir, err := fs.ExpandTilde(generateDir)
if err != nil {
return err
}
if err := ensureDir(dir, 0700); err != nil {
return err
}
var myID protocol.DeviceID
certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
l.Warnln("Key exists; will not overwrite.")
} else {
cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName, deviceCertLifetimeDays)
if err != nil {
return errors.Wrap(err, "create certificate")
}
}
myID = protocol.NewDeviceID(cert.Certificate[0])
l.Infoln("Device ID:", myID)
cfgFile := filepath.Join(dir, "config.xml")
if _, err := os.Stat(cfgFile); err == nil {
l.Warnln("Config exists; will not overwrite.")
return nil
}
cfg, err := syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder)
if err != nil {
return err
}
err = cfg.Save()
if err != nil {
return errors.Wrap(err, "save config")
}
return nil
}
func debugFacilities() string {
facilities := l.Facilities()
@@ -497,7 +461,7 @@ func (e *errNoUpgrade) Error() string {
}
func checkUpgrade() (upgrade.Release, error) {
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger, true)
cfg, err := loadOrDefaultConfig()
if err != nil {
return upgrade.Release{}, err
}
@@ -516,7 +480,11 @@ func checkUpgrade() (upgrade.Release, error) {
}
func upgradeViaRest() error {
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger, true)
cfg, err := loadOrDefaultConfig()
if err != nil {
return err
}
u, err := url.Parse(cfg.GUI().URL())
if err != nil {
return err
@@ -540,7 +508,7 @@ func upgradeViaRest() error {
return err
}
if resp.StatusCode != 200 {
bs, err := ioutil.ReadAll(resp.Body)
bs, err := io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return err
@@ -592,7 +560,7 @@ func syncthingMain(options serveOptions) {
evLogger := events.NewLogger()
earlyService.Add(evLogger)
cfgWrapper, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, options.AllowNewerConfig, options.NoDefaultFolder)
cfgWrapper, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, options.AllowNewerConfig, options.NoDefaultFolder, options.SkipPortProbing)
if err != nil {
l.Warnln("Failed to initialize config:", err)
os.Exit(svcutil.ExitError.AsInt())
@@ -624,7 +592,7 @@ func syncthingMain(options serveOptions) {
}
// Check if auto-upgrades is possible, and if yes, and it's enabled do an initial
// upgrade immedately. The auto-upgrade routine can only be started
// upgrade immediately. The auto-upgrade routine can only be started
// later after App is initialised.
autoUpgradePossible := autoUpgradePossible(options)
@@ -653,7 +621,6 @@ func syncthingMain(options serveOptions) {
}
appOpts := syncthing.Options{
AssetDir: options.DebugGUIAssetsDir,
DeadlockTimeoutS: options.DebugDeadlockTimeout,
NoUpgrade: options.NoUpgrade,
ProfilerAddr: options.DebugProfilerListen,
@@ -688,7 +655,7 @@ func syncthingMain(options serveOptions) {
setupSignalHandling(app)
if len(os.Getenv("GOMAXPROCS")) == 0 {
if os.Getenv("GOMAXPROCS") == "" {
runtime.GOMAXPROCS(runtime.NumCPU())
}
@@ -704,8 +671,6 @@ func syncthingMain(options serveOptions) {
}
}
go standbyMonitor(app, cfgWrapper)
if err := app.Start(); err != nil {
os.Exit(svcutil.ExitError.AsInt())
}
@@ -752,12 +717,15 @@ func setupSignalHandling(app *syncthing.App) {
}()
}
func loadOrDefaultConfig(myID protocol.DeviceID, evLogger events.Logger, noDefaultFolder bool) (config.Wrapper, error) {
// loadOrDefaultConfig creates a temporary, minimal configuration wrapper if no file
// exists. As it disregards some command-line options, that should never be persisted.
func loadOrDefaultConfig() (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, _, err := config.Load(cfgFile, myID, evLogger)
cfg, _, err := config.Load(cfgFile, protocol.EmptyDeviceID, events.NoopLogger)
if err != nil {
cfg, err = syncthing.DefaultConfig(cfgFile, myID, evLogger, noDefaultFolder)
newCfg := config.New(protocol.EmptyDeviceID)
return config.Wrap(cfgFile, newCfg, protocol.EmptyDeviceID, events.NoopLogger), nil
}
return cfg, err
@@ -799,49 +767,6 @@ func resetDB() error {
return os.RemoveAll(locations.Get(locations.Database))
}
func ensureDir(dir string, mode fs.FileMode) error {
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
err := fs.MkdirAll(".", mode)
if err != nil {
return err
}
if fi, err := fs.Stat("."); err == nil {
// Apprently the stat may fail even though the mkdirall passed. If it
// does, we'll just assume things are in order and let other things
// fail (like loading or creating the config...).
currentMode := fi.Mode() & 0777
if currentMode != mode {
err := fs.Chmod(".", mode)
// This can fail on crappy filesystems, nothing we can do about it.
if err != nil {
l.Warnln(err)
}
}
}
return nil
}
func standbyMonitor(app *syncthing.App, cfg config.Wrapper) {
restartDelay := 60 * time.Second
now := time.Now()
for {
time.Sleep(10 * time.Second)
if time.Since(now) > 2*time.Minute && cfg.Options().RestartOnWakeup {
l.Infof("Paused state detected, possibly woke up from standby. Restarting in %v.", restartDelay)
// We most likely just woke from standby. If we restart
// immediately chances are we won't have networking ready. Give
// things a moment to stabilize.
time.Sleep(restartDelay)
app.Stop(svcutil.ExitRestart)
return
}
now = time.Now()
}
}
func autoUpgradePossible(options serveOptions) bool {
if upgrade.DisabledByCompilation {
return false
@@ -973,16 +898,6 @@ func cleanConfigDirectory() {
}
}
func showPaths(options serveOptions) {
fmt.Printf("Configuration file:\n\t%s\n\n", locations.Get(locations.ConfigFile))
fmt.Printf("Database directory:\n\t%s\n\n", locations.Get(locations.Database))
fmt.Printf("Device private key & certificate files:\n\t%s\n\t%s\n\n", locations.Get(locations.KeyFile), locations.Get(locations.CertFile))
fmt.Printf("HTTPS private key & certificate files:\n\t%s\n\t%s\n\n", locations.Get(locations.HTTPSKeyFile), locations.Get(locations.HTTPSCertFile))
fmt.Printf("Log file:\n\t%s\n\n", options.LogFile)
fmt.Printf("GUI override directory:\n\t%s\n\n", options.DebugGUIAssetsDir)
fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations.Get(locations.DefFolder))
}
func setPauseState(cfgWrapper config.Wrapper, paused bool) {
_, err := cfgWrapper.Modify(func(cfg *config.Configuration) {
for i := range cfg.Devices {

View File

@@ -15,16 +15,14 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/fs"
"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"
)
@@ -50,7 +48,7 @@ func monitorMain(options serveOptions) {
var dst io.Writer = os.Stdout
logFile := options.LogFile
logFile := locations.Get(locations.LogFile)
if logFile != "-" {
if expanded, err := fs.ExpandTilde(logFile); err == nil {
logFile = expanded
@@ -68,7 +66,7 @@ func monitorMain(options serveOptions) {
if err != nil {
l.Warnln("Failed to setup logging to file, proceeding with logging to stdout only:", err)
} else {
if runtime.GOOS == "windows" {
if build.IsWindows {
// Translate line breaks to Windows standard
fileDst = osutil.ReplacingWriter{
Writer: fileDst,
@@ -85,6 +83,11 @@ func monitorMain(options serveOptions) {
}
args := os.Args
binary, err := getBinary(args[0])
if err != nil {
l.Warnln("Error starting the main Syncthing process:", err)
panic("Error starting the main Syncthing process")
}
var restarts [restartCounts]time.Time
stopSign := make(chan os.Signal, 1)
@@ -106,7 +109,7 @@ func monitorMain(options serveOptions) {
copy(restarts[0:], restarts[1:])
restarts[len(restarts)-1] = time.Now()
cmd := exec.Command(args[0], args[1:]...)
cmd := exec.Command(binary, args[1:]...)
cmd.Env = childEnv
stderr, err := cmd.StderrPipe()
@@ -182,7 +185,7 @@ func monitorMain(options serveOptions) {
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
l.Infoln("Restarting monitor...")
if err = restartMonitor(args); err != nil {
if err = restartMonitor(binary, args); err != nil {
l.Warnln("Restart:", err)
}
os.Exit(exitCode)
@@ -205,6 +208,19 @@ func monitorMain(options serveOptions) {
}
}
func getBinary(args0 string) (string, error) {
e, err := os.Executable()
if err == nil {
return e, nil
}
// Check if args0 cuts it
e, lerr := exec.LookPath(args0)
if lerr == nil {
return e, nil
}
return "", err
}
func copyStderr(stderr io.Reader, dst io.Writer) {
br := bufio.NewReader(stderr)
@@ -257,7 +273,7 @@ func copyStderr(stderr io.Reader, dst io.Writer) {
* This crash usually occurs due to one of the following reasons: *
* - Syncthing being stopped abruptly (killed/loss of power) *
* - Bad hardware (memory/disk issues) *
* - Software that affects disk writes (SSD caching software and simillar) *
* - Software that affects disk writes (SSD caching software and similar) *
* *
* Please see the following URL for instructions on how to recover: *
* https://docs.syncthing.net/users/faq.html#my-syncthing-database-is-corrupt *
@@ -311,40 +327,30 @@ func copyStdout(stdout io.Reader, dst io.Writer) {
}
}
func restartMonitor(args []string) error {
func restartMonitor(binary string, 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" {
if !build.IsWindows {
// syscall.Exec is the cleanest way to restart on Unixes as it
// replaces the current process with the new one, keeping the pid and
// controlling terminal and so on
return restartMonitorUnix(args)
return restartMonitorUnix(binary, args)
}
// but it isn't supported on Windows, so there we start a normal
// exec.Command and return.
return restartMonitorWindows(args)
return restartMonitorWindows(binary, args)
}
func restartMonitorUnix(args []string) error {
if !strings.ContainsRune(args[0], os.PathSeparator) {
// The path to the binary doesn't contain a slash, so it should be
// found in $PATH.
binary, err := exec.LookPath(args[0])
if err != nil {
return err
}
args[0] = binary
}
return syscall.Exec(args[0], args, os.Environ())
func restartMonitorUnix(binary string, args []string) error {
return syscall.Exec(binary, args, os.Environ())
}
func restartMonitorWindows(args []string) error {
cmd := exec.Command(args[0], args[1:]...)
func restartMonitorWindows(binary string, args []string) error {
cmd := exec.Command(binary, args[1:]...)
// Retain the standard streams
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
@@ -515,7 +521,7 @@ func (f *autoclosedFile) ensureOpenLocked() error {
// We open the file for write only, and create it if it doesn't exist.
flags := os.O_WRONLY | os.O_CREATE | os.O_APPEND
fd, err := os.OpenFile(f.name, flags, 0644)
fd, err := os.OpenFile(f.name, flags, 0o644)
if err != nil {
return err
}
@@ -564,7 +570,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, true)
cfg, err := loadOrDefaultConfig()
if err != nil {
l.Warnln("Couldn't load config; not reporting crash")
return

View File

@@ -8,7 +8,6 @@ package main
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"testing"
@@ -18,14 +17,17 @@ import (
func TestRotatedFile(t *testing.T) {
// Verify that log rotation happens.
dir, err := ioutil.TempDir("", "syncthing")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
dir := t.TempDir()
open := func(name string) (io.WriteCloser, error) {
return os.Create(name)
f, err := os.Create(name)
t.Cleanup(func() {
if f != nil {
_ = f.Close()
}
})
return f, err
}
logName := filepath.Join(dir, "log.txt")
@@ -179,7 +181,7 @@ func TestAutoClosedFile(t *testing.T) {
}
// The file should have both writes in it.
bs, err := ioutil.ReadFile(file)
bs, err := os.ReadFile(file)
if err != nil {
t.Fatal(err)
}
@@ -199,7 +201,7 @@ func TestAutoClosedFile(t *testing.T) {
}
// It should now contain three writes, as the file is always opened for appending
bs, err = ioutil.ReadFile(file)
bs, err = os.ReadFile(file)
if err != nil {
t.Fatal(err)
}

View File

@@ -4,26 +4,25 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !windows
// +build !windows
package main
import (
"os/exec"
"runtime"
"syscall"
"github.com/syncthing/syncthing/lib/build"
)
func openURL(url string) error {
switch runtime.GOOS {
case "darwin":
if build.IsDarwin {
return exec.Command("open", url).Run()
default:
cmd := exec.Command("xdg-open", url)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
return cmd.Run()
}
cmd := exec.Command("xdg-open", url)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
return cmd.Run()
}

View File

@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build windows
// +build windows
package main

View File

@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build !solaris && !windows
// +build !solaris,!windows
package main

View File

@@ -4,6 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//go:build solaris || windows
// +build solaris windows
package main

View File

@@ -4,7 +4,8 @@
// 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 go1.7
//go:build go1.7
// +build go1.7
package main

View File

@@ -47,32 +47,25 @@ 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("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")
}
@@ -119,13 +112,13 @@ func setupDB(db *sql.DB) error {
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS BlockStats (
Day TIMESTAMP NOT NULL,
Reports INTEGER NOT NULL,
Total INTEGER NOT NULL,
Renamed INTEGER NOT NULL,
Reused INTEGER NOT NULL,
Pulled INTEGER NOT NULL,
CopyOrigin INTEGER NOT NULL,
CopyOriginShifted INTEGER NOT NULL,
CopyElsewhere INTEGER NOT NULL
Total BIGINT NOT NULL,
Renamed BIGINT NOT NULL,
Reused BIGINT NOT NULL,
Pulled BIGINT NOT NULL,
CopyOrigin BIGINT NOT NULL,
CopyOriginShifted BIGINT NOT NULL,
CopyElsewhere BIGINT NOT NULL
)`)
if err != nil {
return err
@@ -163,7 +156,7 @@ func setupDB(db *sql.DB) error {
func maxIndexedDay(db *sql.DB, table string) time.Time {
var t time.Time
row := db.QueryRow("SELECT MAX(Day) FROM " + table)
row := db.QueryRow("SELECT MAX(DATE_TRUNC('day', Day)) FROM " + table)
err := row.Scan(&t)
if err != nil {
return time.Time{}
@@ -179,8 +172,8 @@ func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
COUNT(*) AS Count
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
GROUP BY Day, Ver
);
@@ -198,7 +191,8 @@ func aggregateUserMovement(db *sql.DB) (int64, error) {
Report->>'uniqueID'
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Report->>'uniqueID' IS NOT NULL
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
ORDER BY Day
`)
@@ -283,9 +277,11 @@ func aggregatePerformance(db *sql.DB, since time.Time) (int64, error) {
AVG((Report->>'memoryUsageMiB')::numeric) As MemoryUsageMiB
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
/* Some custom implementation reported bytes when we expect megabytes, cap at petabyte */
AND (Report->>'memorySize')::numeric < 1073741824
GROUP BY Day
);
`, since)
@@ -303,17 +299,17 @@ func aggregateBlockStats(db *sql.DB, since time.Time) (int64, error) {
SELECT
DATE_TRUNC('day', Received) AS Day,
COUNT(1) As 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
SUM((Report->'blockStats'->>'total')::numeric)::bigint AS Total,
SUM((Report->'blockStats'->>'renamed')::numeric)::bigint AS Renamed,
SUM((Report->'blockStats'->>'reused')::numeric)::bigint AS Reused,
SUM((Report->'blockStats'->>'pulled')::numeric)::bigint AS Pulled,
SUM((Report->'blockStats'->>'copyOrigin')::numeric)::bigint AS CopyOrigin,
SUM((Report->'blockStats'->>'copyOriginShifted')::numeric)::bigint AS CopyOriginShifted,
SUM((Report->'blockStats'->>'copyElsewhere')::numeric)::bigint AS CopyElsewhere
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND (Report->>'urVersion')::numeric >= 3
AND Report->>'version' like 'v_.%'
AND Report->>'version' NOT LIKE 'v0.14.40%'

View File

@@ -13,7 +13,6 @@ import (
"encoding/json"
"html/template"
"io"
"io/ioutil"
"log"
"net"
"net/http"
@@ -26,7 +25,10 @@ import (
"time"
"unicode"
_ "github.com/lib/pq" // PostgreSQL driver
"github.com/oschwald/geoip2-golang"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/ur/contract"
@@ -48,19 +50,19 @@ var (
knownDistributions = []distributionMatch{
// Maps well known builders to the official distribution method that
// they represent
{regexp.MustCompile("android-.*teamcity@build.syncthing.net"), "Google Play"},
{regexp.MustCompile("teamcity@build.syncthing.net"), "GitHub"},
{regexp.MustCompile("deb@build.syncthing.net"), "APT"},
{regexp.MustCompile("docker@syncthing.net"), "Docker Hub"},
{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@(archlinux|svetlemodry)"), "Arch (3rd party)"},
{regexp.MustCompile("synology@kastelo.net"), "Synology (Kastelo)"},
{regexp.MustCompile("@debian"), "Debian (3rd party)"},
{regexp.MustCompile("@fedora"), "Fedora (3rd party)"},
{regexp.MustCompile(`android-.*teamcity@build\.syncthing\.net`), "Google Play"},
{regexp.MustCompile(`teamcity@build\.syncthing\.net`), "GitHub"},
{regexp.MustCompile(`deb@build\.syncthing\.net`), "APT"},
{regexp.MustCompile(`docker@syncthing\.net`), "Docker Hub"},
{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@(archlinux|svetlemodry)`), "Arch (3rd party)"},
{regexp.MustCompile(`synology@kastelo\.net`), "Synology (Kastelo)"},
{regexp.MustCompile(`@debian`), "Debian (3rd party)"},
{regexp.MustCompile(`@fedora`), "Fedora (3rd party)"},
{regexp.MustCompile(`\bbrew@`), "Homebrew (3rd party)"},
{regexp.MustCompile("."), "Others"},
{regexp.MustCompile(`.`), "Others"},
}
)
@@ -130,11 +132,6 @@ func setupDB(db *sql.DB) error {
}
}
// Migrate from old schema to new schema if the table exists.
if err := migrate(db); err != nil {
return err
}
return nil
}
@@ -162,7 +159,7 @@ func main() {
if err != nil {
log.Fatalln("template:", err)
}
bs, err := ioutil.ReadAll(fd)
bs, err := io.ReadAll(fd)
if err != nil {
log.Fatalln("template:", err)
}
@@ -285,7 +282,7 @@ func rootHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
}
}
func locationsHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
func locationsHandler(db *sql.DB, w http.ResponseWriter, _ *http.Request) {
cacheMut.Lock()
defer cacheMut.Unlock()
@@ -324,7 +321,7 @@ func newDataHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
rep.Address = addr
lr := &io.LimitedReader{R: r.Body, N: 40 * 1024}
bs, _ := ioutil.ReadAll(lr)
bs, _ := io.ReadAll(lr)
if err := json.Unmarshal(bs, &rep); err != nil {
log.Println("decode:", err)
if debug {
@@ -378,7 +375,7 @@ func summaryHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
w.Write(bs)
}
func movementHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
func movementHandler(db *sql.DB, w http.ResponseWriter, _ *http.Request) {
s, err := getMovement(db)
if err != nil {
log.Println("movementHandler:", err)
@@ -397,7 +394,7 @@ func movementHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
w.Write(bs)
}
func performanceHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
func performanceHandler(db *sql.DB, w http.ResponseWriter, _ *http.Request) {
s, err := getPerformance(db)
if err != nil {
log.Println("performanceHandler:", err)
@@ -416,7 +413,7 @@ func performanceHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
w.Write(bs)
}
func blockStatsHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
func blockStatsHandler(db *sql.DB, w http.ResponseWriter, _ *http.Request) {
s, err := getBlockStats(db)
if err != nil {
log.Println("blockStatsHandler:", err)
@@ -581,7 +578,6 @@ func getReport(db *sql.DB) map[string]interface{} {
for rows.Next() {
err := rows.Scan(&rep.Received, &rep)
if err != nil {
log.Println("sql:", err)
return nil
@@ -774,7 +770,7 @@ func getReport(db *sql.DB) map[string]interface{} {
}
for transport, count := range rep.TransportStats {
add(featureGroups["Connection"]["v3"], "Transport", strings.Title(transport), count)
add(featureGroups["Connection"]["v3"], "Transport", cases.Title(language.English).String(transport), count)
if strings.HasSuffix(transport, "4") {
add(featureGroups["Connection"]["v3"], "IP version", "IPv4", count)
} else if strings.HasSuffix(transport, "6") {
@@ -786,72 +782,53 @@ func getReport(db *sql.DB) map[string]interface{} {
}
}
var categories []category
categories = append(categories, category{
Values: statsForInts(totFiles),
Descr: "Files Managed per Device",
})
categories = append(categories, category{
Values: statsForInts(maxFiles),
Descr: "Files in Largest Folder",
})
categories = append(categories, category{
Values: statsForInt64s(totMiB),
Descr: "Data Managed per Device",
Unit: "B",
Type: NumberBinary,
})
categories = append(categories, category{
Values: statsForInt64s(maxMiB),
Descr: "Data in Largest Folder",
Unit: "B",
Type: NumberBinary,
})
categories = append(categories, category{
Values: statsForInts(numDevices),
Descr: "Number of Devices in Cluster",
})
categories = append(categories, category{
Values: statsForInts(numFolders),
Descr: "Number of Folders Configured",
})
categories = append(categories, category{
Values: statsForInt64s(memoryUsage),
Descr: "Memory Usage",
Unit: "B",
Type: NumberBinary,
})
categories = append(categories, category{
Values: statsForInt64s(memorySize),
Descr: "System Memory",
Unit: "B",
Type: NumberBinary,
})
categories = append(categories, category{
Values: statsForFloats(sha256Perf),
Descr: "SHA-256 Hashing Performance",
Unit: "B/s",
Type: NumberBinary,
})
categories = append(categories, category{
Values: statsForInts(numCPU),
Descr: "Number of CPU cores",
})
categories = append(categories, category{
Values: statsForInts(uptime),
Descr: "Uptime (v3)",
Type: NumberDuration,
})
categories := []category{
{
Values: statsForInts(totFiles),
Descr: "Files Managed per Device",
}, {
Values: statsForInts(maxFiles),
Descr: "Files in Largest Folder",
}, {
Values: statsForInt64s(totMiB),
Descr: "Data Managed per Device",
Unit: "B",
Type: NumberBinary,
}, {
Values: statsForInt64s(maxMiB),
Descr: "Data in Largest Folder",
Unit: "B",
Type: NumberBinary,
}, {
Values: statsForInts(numDevices),
Descr: "Number of Devices in Cluster",
}, {
Values: statsForInts(numFolders),
Descr: "Number of Folders Configured",
}, {
Values: statsForInt64s(memoryUsage),
Descr: "Memory Usage",
Unit: "B",
Type: NumberBinary,
}, {
Values: statsForInt64s(memorySize),
Descr: "System Memory",
Unit: "B",
Type: NumberBinary,
}, {
Values: statsForFloats(sha256Perf),
Descr: "SHA-256 Hashing Performance",
Unit: "B/s",
Type: NumberBinary,
}, {
Values: statsForInts(numCPU),
Descr: "Number of CPU cores",
}, {
Values: statsForInts(uptime),
Descr: "Uptime (v3)",
Type: NumberDuration,
},
}
reportFeatures := make(map[string][]feature)
for featureType, versions := range features {
@@ -917,7 +894,7 @@ func getReport(db *sql.DB) map[string]interface{} {
r["distributions"] = analyticsFor(distributions, len(knownDistributions))
r["featureOrder"] = featureOrder
r["locations"] = locations
r["contries"] = countryList
r["countries"] = countryList
return r
}
@@ -1041,7 +1018,7 @@ func (s *summary) filter(min int) {
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;`)
rows, err := db.Query(`SELECT Day, Version, Count FROM VersionSummary WHERE Day > now() - '3 year'::INTERVAL;`)
if err != nil {
return summary{}, err
}
@@ -1074,7 +1051,7 @@ func getSummary(db *sql.DB, min int) (summary, error) {
}
func getMovement(db *sql.DB) ([][]interface{}, error) {
rows, err := db.Query(`SELECT Day, Added, Removed, Bounced FROM UserMovement WHERE Day > now() - '2 year'::INTERVAL ORDER BY Day`)
rows, err := db.Query(`SELECT Day, Added, Removed, Bounced FROM UserMovement WHERE Day > now() - '3 year'::INTERVAL ORDER BY Day`)
if err != nil {
return nil, err
}
@@ -1107,7 +1084,7 @@ func getMovement(db *sql.DB) ([][]interface{}, error) {
}
func getPerformance(db *sql.DB) ([][]interface{}, error) {
rows, err := db.Query(`SELECT Day, TotFiles, TotMiB, SHA256Perf, MemorySize, MemoryUsageMiB FROM Performance WHERE Day > '2014-06-20'::TIMESTAMP ORDER BY Day`)
rows, err := db.Query(`SELECT Day, TotFiles, TotMiB, SHA256Perf, MemorySize, MemoryUsageMiB FROM Performance WHERE Day > now() - '5 year'::INTERVAL ORDER BY Day`)
if err != nil {
return nil, err
}
@@ -1134,7 +1111,7 @@ func getPerformance(db *sql.DB) ([][]interface{}, error) {
}
func getBlockStats(db *sql.DB) ([][]interface{}, error) {
rows, err := db.Query(`SELECT Day, Reports, Pulled, Renamed, Reused, CopyOrigin, CopyOriginShifted, CopyElsewhere FROM BlockStats WHERE Day > '2017-10-23'::TIMESTAMP ORDER BY Day`)
rows, err := db.Query(`SELECT Day, Reports, Pulled, Renamed, Reused, CopyOrigin, CopyOriginShifted, CopyElsewhere FROM BlockStats WHERE Day > now() - '3 year'::INTERVAL ORDER BY Day`)
if err != nil {
return nil, err
}
@@ -1151,6 +1128,10 @@ func getBlockStats(db *sql.DB) ([][]interface{}, error) {
if err != nil {
return nil, err
}
// Legacy bad data on certain days
if reports <= 0 || pulled < 0 || renamed < 0 || reused < 0 || copyOrigin < 0 || copyOriginShifted < 0 || copyElsewhere < 0 {
continue
}
row := []interface{}{
day.Format("2006-01-02"),
reports,
@@ -1172,9 +1153,11 @@ type sortableFeatureList []feature
func (l sortableFeatureList) Len() int {
return len(l)
}
func (l sortableFeatureList) Swap(a, b int) {
l[a], l[b] = l[b], l[a]
}
func (l sortableFeatureList) Less(a, b int) bool {
if l[a].Pct != l[b].Pct {
return l[a].Pct < l[b].Pct

View File

@@ -1,143 +0,0 @@
// 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

@@ -50,7 +50,6 @@ found in the LICENSE file.
<script type="text/javascript">
google.setOnLoadCallback(drawVersionChart);
google.setOnLoadCallback(drawMovementChart);
google.setOnLoadCallback(drawBlockStatsChart);
google.setOnLoadCallback(drawPerformanceCharts);
@@ -82,37 +81,6 @@ found in the LICENSE file.
chart.draw(data, options);
}
function drawMovementChart() {
var jsonData = $.ajax({url: "movement.json", dataType:"json", async: false}).responseText;
var rows = JSON.parse(jsonData);
var data = new google.visualization.DataTable();
data.addColumn('date', 'Day');
for (var i = 1; i < rows[0].length; i++){
data.addColumn('number', rows[0][i]);
}
for (var i = 1; i < rows.length; i++){
rows[i][0] = new Date(rows[i][0]);
if (rows[i][1] > 500) {
rows[i][1] = null;
}
if (rows[i][2] < -500) {
rows[i][2] = null;
}
data.addRow(rows[i]);
};
var options = {
legend: { position: 'bottom', alignment: 'center' },
colors: ['rgb(102,194,165)','rgb(252,141,98)','rgb(141,160,203)','rgb(231,138,195)','rgb(166,216,84)','rgb(255,217,47)'],
chartArea: {left: 80, top: 20, width: '1020', height: '300'},
};
var chart = new google.visualization.AreaChart(document.getElementById('movementChart'));
chart.draw(data, options);
}
function formatGibibytes(gibibytes, decimals) {
if(gibibytes == 0) return '0 GiB';
var k = 1024,
@@ -273,14 +241,6 @@ found in the LICENSE file.
</p>
<div class="img-thumbnail" id="versionChart" style="width: 1130px; height: 400px; padding: 10px;"></div>
<h4 id="joining-leaving">Users Joining and Leaving per Day</h4>
<p>
This is the total number of unique users joining and leaving per day. A user is counted as "joined" on first the day their unique ID is seen, and as "left" on the last day the unique ID was seen before a two weeks or longer absence. "Bounced" refers to users who joined and left on the same day.
</p>
<div class="img-thumbnail" id="movementChart" style="width: 1130px; height: 400px; padding: 10px;"></div>
<p class="text-muted">
Reappearance of users cause the "left" data to shrink retroactively.
</p>
<div id="block-stats">
<h4>Data Transfers per Day</h4>
<p>
@@ -315,7 +275,7 @@ found in the LICENSE file.
<div class="col-md-6">
<table class="table table-striped">
<tbody>
{{range .contries | slice 2 1}}
{{range .countries | slice 2 1}}
<tr>
<td style="width: 45%">{{.Key}}</td>
<td style="width: 5%" class="text-right">{{if ge .Pct 10.0}}{{.Pct | printf "%.0f"}}{{else if ge .Pct 1.0}}{{.Pct | printf "%.01f"}}{{else}}{{.Pct | printf "%.02f"}}{{end}}%</td>
@@ -331,7 +291,7 @@ found in the LICENSE file.
<div class="col-md-6">
<table class="table table-striped">
<tbody>
{{range .contries | slice 2 2}}
{{range .countries | slice 2 2}}
<tr>
<td style="width: 45%">{{.Key}}</td>
<td style="width: 5%" class="text-right">{{if ge .Pct 10.0}}{{.Pct | printf "%.0f"}}{{else if ge .Pct 1.0}}{{.Pct | printf "%.01f"}}{{else}}{{.Pct | printf "%.02f"}}{{end}}%</td>

View File

@@ -13,4 +13,4 @@ syncthing_log_file=</path/to/syncthing/log/file>
syncthing_user=<syncthing_user>
syncthing_group=<syncthing_group>
```
See the rc.d script for more informations.
See the rc.d script for more information.

View File

@@ -1,3 +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
# see https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size
net.core.rmem_max = 2097152

View File

@@ -5,4 +5,4 @@ This directory contains configuration files for running Syncthing under the
systemd user service. For further documentation take a look at the [systemd
section][1] on https://docs.syncthing.net.
[1]: https://docs.syncthing.net/users/autostart.html#using-systemd
[1]: https://docs.syncthing.net/users/autostart#using-systemd

View File

@@ -20,5 +20,9 @@ SystemCallArchitectures=native
MemoryDenyWriteExecute=true
NoNewPrivileges=true
# Elevated permissions to sync ownership (disabled by default),
# see https://docs.syncthing.net/advanced/folder-sync-ownership
#AmbientCapabilities=CAP_CHOWN CAP_FOWNER
[Install]
WantedBy=multi-user.target

View File

@@ -16,5 +16,9 @@ SystemCallArchitectures=native
MemoryDenyWriteExecute=true
NoNewPrivileges=true
# Elevated permissions to sync ownership (disabled by default),
# see https://docs.syncthing.net/advanced/folder-sync-ownership
#AmbientCapabilities=CAP_CHOWN CAP_FOWNER
[Install]
WantedBy=default.target

110
go.mod
View File

@@ -1,57 +1,83 @@
module github.com/syncthing/syncthing
go 1.19
require (
github.com/AudriusButkevicius/pfilter v0.0.0-20210218141631-7468b85d810a
github.com/AudriusButkevicius/recli v0.0.5
github.com/alecthomas/kong v0.2.12
github.com/bkaradzic/go-lz4 v0.0.0-20160924222819-7224d8d8f27e
github.com/AudriusButkevicius/pfilter v0.0.11
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f
github.com/alecthomas/kong v0.7.1
github.com/calmh/incontainer v0.0.0-20221224152218-b3e71b103d7a
github.com/calmh/xdr v1.1.0
github.com/ccding/go-stun v0.1.3
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
github.com/chmduquesne/rollinghash v0.0.0-20180912150627-a60f8e7142b5
github.com/ccding/go-stun v0.1.4
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chmduquesne/rollinghash v4.0.0+incompatible
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/d4l3k/messagediff v1.2.1
github.com/dchest/siphash v1.2.2
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568
github.com/getsentry/raven-go v0.2.0
github.com/go-ldap/ldap/v3 v3.2.4
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-ldap/ldap/v3 v3.4.5
github.com/gobwas/glob v0.2.3
github.com/gogo/protobuf v1.3.1
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
github.com/golang/protobuf v1.4.3
github.com/greatroar/blobloom v0.5.0
github.com/hashicorp/golang-lru v0.5.1
github.com/jackpal/gateway v1.0.6
github.com/gogo/protobuf v1.3.2
github.com/golang/snappy v0.0.4 // indirect
github.com/greatroar/blobloom v0.7.2
github.com/hashicorp/golang-lru/v2 v2.0.3
github.com/jackpal/gateway v1.0.10
github.com/jackpal/go-nat-pmp v1.0.2
github.com/julienschmidt/httprouter v1.3.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/lib/pq v1.8.0
github.com/lucas-clemente/quic-go v0.19.3
github.com/maruel/panicparse v1.5.1
github.com/mattn/go-isatty v0.0.12
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0 // indirect
github.com/minio/sha256-simd v0.1.1
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/lib/pq v1.10.9
github.com/maruel/panicparse/v2 v2.3.1
github.com/maxbrunsfeld/counterfeiter/v6 v6.5.0
github.com/minio/sha256-simd v1.0.1
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/onsi/gomega v1.10.3 // indirect
github.com/oschwald/geoip2-golang v1.4.0
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.8.0
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0
github.com/sasha-s/go-deadlock v0.2.0
github.com/shirou/gopsutil/v3 v3.20.11
github.com/syncthing/notify v0.0.0-20210308121556-f45149b04939
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7
github.com/thejerf/suture/v4 v4.0.0
github.com/urfave/cli v1.22.4
github.com/oschwald/geoip2-golang v1.8.0
github.com/pierrec/lz4/v4 v4.1.17
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.15.1
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/quic-go/quic-go v0.34.0
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
github.com/sasha-s/go-deadlock v0.3.1
github.com/shirou/gopsutil/v3 v3.23.5
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
github.com/thejerf/suture/v4 v4.0.2
github.com/urfave/cli v1.22.14
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
golang.org/x/text v0.3.4
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
golang.org/x/tools v0.1.0 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
golang.org/x/crypto v0.10.0
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.11.0
golang.org/x/sys v0.9.0
golang.org/x/text v0.10.0
golang.org/x/time v0.3.0
golang.org/x/tools v0.9.3
google.golang.org/protobuf v1.30.0
)
go 1.14
require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/onsi/ginkgo/v2 v2.10.0 // indirect
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
)
// https://github.com/gobwas/glob/pull/55
replace github.com/gobwas/glob v0.2.3 => github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b

812
go.sum
View File

@@ -1,676 +1,330 @@
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-20210218141631-7468b85d810a h1:dUzIAgRmHLIUU0PT+OJ0X1WI5j1hlLbf+G420gUjIQg=
github.com/AudriusButkevicius/pfilter v0.0.0-20210218141631-7468b85d810a/go.mod h1:1N0EEx/irz4B1qV17wW82TFbjQrE7oX316Cki6eDY0Q=
github.com/AudriusButkevicius/recli v0.0.5 h1:xUa55PvWTHBm17T6RvjElRO3y5tALpdceH86vhzQ5wg=
github.com/AudriusButkevicius/recli v0.0.5/go.mod h1:Q2E26yc6RvWWEz/TJ/goUp6yXvipYdJI096hpoaqsNs=
github.com/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/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.12 h1:X3kkCOXGUNzLmiu+nQtoxWqj4U2a39MpSJR3QdQXOwI=
github.com/alecthomas/kong v0.2.12/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
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/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/AudriusButkevicius/pfilter v0.0.11 h1:6emuvqNeH1gGlqkML35pEizyPcaxdAN4JO9sdgwcx78=
github.com/AudriusButkevicius/pfilter v0.0.11/go.mod h1:4eF1UYuEhoycTlr9IOP1sb0lL9u4nfAIouRqt2xJbzM=
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f h1:GmH5lT+moM7PbAJFBq57nH9WJ+wRnBXr/tyaYWbSAx8=
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f/go.mod h1:Nhfib1j/VFnLrXL9cHgA+/n2O6P5THuWelOnbfPNd78=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4=
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
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/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/glob v0.0.0-20220615080505-1d823af5017b h1:Fjm4GuJ+TGMgqfGHN42IQArJb77CfD/mAwLbDUoJe6g=
github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b/go.mod h1:91K7jfEsgJSyfSrX+gmrRfZMtntx6JsHolWubGXDopg=
github.com/calmh/incontainer v0.0.0-20221224152218-b3e71b103d7a h1:CjrQbpvnV4BMzPHf0r8p2FAvzEp/bp761CmBBeNIHXI=
github.com/calmh/incontainer v0.0.0-20221224152218-b3e71b103d7a/go.mod h1:eOhqnw15c9X+4RNBe0W3HlUZFfX16O0EDsCOInTndHY=
github.com/calmh/xdr v1.1.0 h1:U/Dd4CXNLoo8EiQ4ulJUXkgO1/EyQLgDKLgpY1SOoJE=
github.com/calmh/xdr v1.1.0/go.mod h1:E8sz2ByAdXC8MbANf1LCRYzedSnnc+/sXXJs/PVqoeg=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/ccding/go-stun v0.1.2 h1:1CZhjVwfyO/jGxk06a+0OSOGBWZu588kuZQQO4nihsw=
github.com/ccding/go-stun v0.1.2/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
github.com/ccding/go-stun v0.1.3 h1:uEAFsxqPBuo4tvILfloEHUBO3b4BlEAMnx2PZdh54jE=
github.com/ccding/go-stun v0.1.3/go.mod h1:cCZjJ1J3WFSJV6Wj8Y9Di8JMTsEXh6uv2eNmLzKaUeM=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/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/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 h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/ccding/go-stun v0.1.4 h1:lC0co3Q3vjAuu2Jz098WivVPBPbemYFqbwE1syoka4M=
github.com/ccding/go-stun v0.1.4/go.mod h1:cCZjJ1J3WFSJV6Wj8Y9Di8JMTsEXh6uv2eNmLzKaUeM=
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s=
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chmduquesne/rollinghash v4.0.0+incompatible h1:hnREQO+DXjqIw3rUTzWN7/+Dpw+N5Um8zpKV0JOEgbo=
github.com/chmduquesne/rollinghash v4.0.0+incompatible/go.mod h1:Uc2I36RRfTAf7Dge82bi3RU0OQUmXT9iweIcPqvr8A0=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
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 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-ldap/ldap/v3 v3.2.4 h1:PFavAq2xTgzo/loE8qNXcQaofAaqIpI4WgaLdv+1l3E=
github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
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.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8=
github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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/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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-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/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.5.0 h1:jNbCsgDpZ23AI6jgZsXm7oFatkFaLCxr+ZWzlYasONU=
github.com/greatroar/blobloom v0.5.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 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
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/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs=
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
github.com/greatroar/blobloom v0.7.2 h1:F30MGLHOcb4zr0pwCPTcKdlTM70rEgkf+LzdUPc5ss8=
github.com/greatroar/blobloom v0.7.2/go.mod h1:mjMJ1hh1wjGVfr93QIHJ6FfDNVrA0IELv8OvMHJxHKs=
github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPDrgxJa9mE=
github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackpal/gateway v1.0.6 h1:/MJORKvJEwNVldtGVJC2p2cwCnsSoLn3hl3zxmZT7tk=
github.com/jackpal/gateway v1.0.6/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackpal/gateway v1.0.10 h1:7g3fDo4Cd3RnTu6PzAfw6poO4Y81uNxrxFQFsBFSzJM=
github.com/jackpal/gateway v1.0.10/go.mod h1:+uPBgIllrbkwYCAoDkGSZbjvpre/bGYAFCYIcrH+LHs=
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.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/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/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.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/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 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ=
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/maruel/panicparse v1.5.1 h1:hUPcXI7ubtEqj/k+P34KsHQqb86zuVk7zBfkP6tBBPc=
github.com/maruel/panicparse v1.5.1/go.mod h1:aOutY/MUjdj80R0AEVI9qE2zHqig+67t2ffUDDiLzAM=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
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/maxbrunsfeld/counterfeiter/v6 v6.3.0 h1:8E6DrFvII6QR4eJ3PkFvV+lc03P+2qwqTPLm1ax7694=
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0/go.mod h1:fcEyUyXZXoV4Abw8DX0t7wyL8mCDxXyU4iAFZfT3IHw=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/maruel/panicparse/v2 v2.3.1 h1:NtJavmbMn0DyzmmSStE8yUsmPZrZmudPH7kplxBinOA=
github.com/maruel/panicparse/v2 v2.3.1/go.mod h1:s3UmQB9Fm/n7n/prcD2xBGDkwXD6y2LeZnhbEXvs9Dg=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.5.0 h1:rBhB9Rls+yb8kA4x5a/cWxOufWfXt24E+kq4YlbGj3g=
github.com/maxbrunsfeld/counterfeiter/v6 v6.5.0/go.mod h1:fJ0UAZc1fx3xZhU4eSHQDJ1ApFmTVhp5VTpV9tm2ogg=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
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/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
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/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.10.0 h1:sfUl4qgLdvkChZrWCYndY2EAu9BRIw1YphNAzy1VNWs=
github.com/onsi/ginkgo/v2 v2.10.0/go.mod h1:UDQOh5wbQUlMnkLfVaIUMtQ1Vus92oM+P2JX1aulgcE=
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.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/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/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
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/petermattis/goid v0.0.0-20230518223814-80aa455d8761 h1:W04oB3d0J01W5jgYRGKsV8LCM6g9EkCvPkZcmFuy0OE=
github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.1/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.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
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/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.20.11 h1:NeVf1K0cgxsWz+N3671ojRptdgzvp7BXL3KV21R0JnA=
github.com/shirou/gopsutil/v3 v3.20.11/go.mod h1:igHnfak0qnw1biGeI2qKQvu0ZkwvEkUcCLlYhZzdr/4=
github.com/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 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.34.0 h1:OvOJ9LFjTySgwOTYUZmNoq0FzVicP8YujpV0kB7m2lU=
github.com/quic-go/quic-go v0.34.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
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/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/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y=
github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
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/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syncthing/notify v0.0.0-20210308121556-f45149b04939 h1:InjitJPCBfhc1/DP0Z8OglJq5qvQD+J0o64TFyenf68=
github.com/syncthing/notify v0.0.0-20210308121556-f45149b04939/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y=
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7 h1:udtnv1cokhJYqnUfCMCppJ71bFN9VKfG1BQ6UsYZnx8=
github.com/syndtr/goleveldb v1.0.1-0.20200815071216-d9e9293bd0f7/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thejerf/suture/v4 v4.0.0 h1:GX3X+1Qaewtj9flL2wgoTBfLA5NcmrCY39TJRpPbUrI=
github.com/thejerf/suture/v4 v4.0.0/go.mod h1:g0e8vwskm9tI0jRjxrnA6lSr0q6OfPdWJVX7G5bVWRs=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2 h1:F4snRP//nIuTTW9LYEzVH4HVwDG9T3M4t8y/2nqMbiY=
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y=
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
github.com/thejerf/suture/v4 v4.0.2 h1:VxIH/J8uYvqJY1+9fxi5GBfGRkRZ/jlSOP6x9HijFQc=
github.com/thejerf/suture/v4 v4.0.2/go.mod h1:g0e8vwskm9tI0jRjxrnA6lSr0q6OfPdWJVX7G5bVWRs=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA=
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 h1:okhMind4q9H1OxF44gNegWkiP4H/gsTFLalHFa4OOUI=
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0/go.mod h1:TTbGUfE+cXXceWtbTHq6lqcTvYPBKLNejBEbnUsQJtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
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-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
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-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-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-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
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/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/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/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
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-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-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-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-20190916202348-b4ddaad3f8a3/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/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-20191204072324-ce4227a45e2e/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-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/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/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
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-20201023174141-c8cfbd0f21e6/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/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
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=
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=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
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/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/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/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.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -42,7 +42,7 @@ a:hover,a:focus,a.focus{
.nav-tabs > li > a:hover,
.nav-tabs > li > a:focus {
background-color: #222222 !important;
border: none !important;
border-color: transparent !important;
}
.navbar-text, .dropdown>a, .dropdown-menu>li>a, .hidden-xs>a, .navbar-link {
@@ -265,6 +265,16 @@ code.ng-binding{
color: #222;
}
.fancytree-title {
color: #aaa !important;
/*
* Fancytree tweaks
*/
.fancytree-container tr:hover,
.fancytree-focused {
background-color: #222;
}
/* Remote Devices 'connection type'-icon color set to #aaa */
.reception {
filter: invert(77%) sepia(0%) saturate(724%) hue-rotate(146deg) brightness(91%) contrast(85%);
}

View File

@@ -45,7 +45,7 @@ a:hover,a:focus,a.focus{
.nav-tabs > li > a:hover,
.nav-tabs > li > a:focus {
background-color: #424242 !important;
border: none !important;
border-color: transparent !important;
}
@@ -277,6 +277,16 @@ code.ng-binding{
color: #3fa9f0;
}
.fancytree-title {
color: #aaa !important;
/*
* Fancytree tweaks
*/
.fancytree-container tr:hover,
.fancytree-focused {
background-color: #424242;
}
/* Remote Devices 'connection type'-icon color set to #aaa */
.reception {
filter: invert(77%) sepia(0%) saturate(724%) hue-rotate(146deg) brightness(91%) contrast(85%);
}

View File

@@ -10,6 +10,7 @@
body {
padding-bottom: 70px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
overflow-y: scroll;
}
h1, h2, h3, h4, h5 {
@@ -143,8 +144,48 @@ table.table-auto td {
max-width: 0px;
}
td input[type="checkbox"] {
margin-top: 13px;
}
/* Remote Devices connection-quality indicator */
.reception-0 {
background: url('../../vendor/bootstrap/fonts/reception-0.svg') no-repeat;
}
.reception-1 {
background: url('../../vendor/bootstrap/fonts/reception-1.svg') no-repeat;
}
.reception-2 {
background: url('../../vendor/bootstrap/fonts/reception-2.svg') no-repeat;
}
.reception-3 {
background: url('../../vendor/bootstrap/fonts/reception-3.svg') no-repeat;
}
.reception-4 {
background: url('../../vendor/bootstrap/fonts/reception-4.svg') no-repeat;
}
.reception {
width: 1em;
height: 1em;
display: inline-block;
vertical-align: -10%;
background-size: contain;
/* Simulate same width as Fork Awesome icons. */
margin-left: .14285715em;
margin-right: .14285715em;
}
.remote-devices-panel {
display: inline-block;
}
/* Wrap long file paths to prevent text overflow. See issue #6268. */
.file-path {
.word-break-all {
word-break: break-all;
}
@@ -166,16 +207,13 @@ table.table-auto td {
display: none;
}
*[language-select] > .dropdown-menu {
li[language-select] > .dropdown-menu {
column-count: 2;
column-gap: 0;
width: 450px;
}
*[language-select] > .dropdown-menu > li {
float: left;
width: 50%;
}
*[language-select] > .dropdown-menu > li > a {
li[language-select] > .dropdown-menu > li > a {
overflow: hidden;
text-overflow: ellipsis;
}
@@ -304,6 +342,62 @@ ul.three-columns li, ul.two-columns li {
z-index: 980;
}
/*
* Restore Versions tweaks
*/
#restoreTree-container {
overflow-y: scroll;
resize: vertical;
/* Limit height to prevent vertical screen overflow. */
max-height: calc(100vh - 390px);
/* Always fit at least one folder with dropdown open. */
min-height: 136px;
}
@media (min-width: 768px) {
#restoreTree-container {
max-height: calc(100vh - 401px);
}
}
@media (min-width: 992px) {
#restoreTree-container {
max-height: calc(100vh - 333px);
}
}
/* Ignore fixed height when manually resized. */
#restoreTree-container[style*="height"] {
max-height: none;
}
/* Remove table outline as rows have own focus style already. */
#restoreTree:focus {
outline: 0;
}
/* Align dropdown with title first line. */
#restoreTree td + td {
padding-top: 4px;
vertical-align: top;
}
/* Reduce space between toggle and menu on mobile. */
#restoreTree .dropdown-toggle {
margin-bottom: 0;
}
/* Change direction to remain on screen on mobile. */
#restoreTree .dropdown-menu {
left: auto;
right: 0;
}
/* Ensure maximum space for filtering and date range. */
#restoreVersions .form-group,
#restoreVersions .form-control {
width: 100%;
}
/** Footer nav on small devices **/
@media (max-width: 1199px) {
/* Stay at the end of the page, with space reserved for the footer
@@ -351,24 +445,19 @@ ul.three-columns li, ul.two-columns li {
border-radius: 2px;
}
*[language-select] {
li[language-select] {
position: static !important;
}
*[language-select] > .dropdown-menu {
li[language-select] > .dropdown-menu {
column-count: auto;
margin-left: 15px;
margin-right: 15px;
margin-top: -12px !important;
max-width: 450px;
height: 265px;
overflow-y: scroll;
}
table.table-condensed td,
table.table-condensed th {
/* for mobile phones to allow linebreaks in long repro folder/shared with
* columns. */
white-space: normal;
/* height of 5.5 elements + negative margin-top */
height: 276px;
}
.two-columns {
@@ -397,10 +486,6 @@ ul.three-columns li, ul.two-columns li {
padding-top: 10px;
}
.fancytree-ext-table {
width: 100% !important;
}
@media (max-width: 419px) {
/* the selectors are build to target only the content of folder and device
panels as it would "destroy" e.g. out of sync or recent changes listings */
@@ -421,12 +506,32 @@ ul.three-columns li, ul.two-columns li {
width: 100%;
}
/* all buttons, except panel headings, get bottom margin, as they won't fit
beside each other anymore */
/* All buttons, except panel headings, get bottom margin, as they
won't fit beside each other anymore. Reduce footer padding to
compensate for the margin. */
.btn:not(.panel-heading),
/* this "+"-selector is needed to override some bootstrap defaults */
.btn:not(.panel-heading) + .btn:not(.panel-heading) {
margin-bottom: 1rem;
margin-bottom: 10px;
}
.panel-footer {
padding-bottom: 0;
}
.modal-footer {
padding-bottom: 5px;
}
table.table-auto td,
table.table-auto th,
table.table-condensed td,
table.table-condensed th {
/* for mobile phones to allow linebreaks in long repro folder/shared with
* columns. */
white-space: normal;
}
/* Move share buttons below device ID on small screens. */
#shareDeviceIdButtons {
display: inline-block;
}
}
@@ -443,3 +548,40 @@ ul.three-columns li, ul.two-columns li {
background-color: #eeeeee;
opacity: 1;
}
.checkbox[disabled] {
background-color: #eeeeee;
opacity: 1;
margin-left: -5px;
padding-left: 5px;
}
.checkbox[disabled] *, .checkbox[disabled] .help-block {
color: #999999;
cursor: not-allowed;
}
/* 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;
}
/* CJK languages don't use italic at all, hence don't force it on them. */
html[lang|="zh"] i,
html[lang="ja"] i,
html[lang|="ko"] i {
font-style: normal;
}
/* Prevent buttons from jumping up and down
when a tooltip is shown for one of them. */
.btn-group-vertical > .tooltip + .btn,
.btn-group-vertical > .tooltip + .btn-group {
margin-top: -1px;
}
.select-on-click {
-webkit-user-select: all;
user-select: all;
}

View File

@@ -0,0 +1,58 @@
/*
// 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/.
*/
.fancytree-container {
cursor: pointer;
width: 100%;
}
.fancytree-hide {
visibility: collapse;
}
/* Node needs to be block, and expander, icon and title
inline-block to properly wrap unbreakable text. */
.fancytree-node {
display: block;
white-space: nowrap;
/* expander 16px + icon 16px + title padding 8px */
padding-right: 40px;
}
.fancytree-expander,
.fancytree-icon,
.fancytree-title {
display: inline-block;
}
.fancytree-expander,
.fancytree-icon {
margin-top: 4px;
vertical-align: top;
width: 16px;
}
.fancytree-childcounter {
background: #777;
border-radius: 10px;
border: 1px solid gray;
color: #fff;
font-size: 13px;
opacity: .75;
padding: 2px 3px;
position: relative;
right: 8px;
top: -9px;
user-select: none;
}
.fancytree-title {
padding-left: 8px;
white-space: normal;
word-break: break-all;
}

View File

@@ -1,7 +1,7 @@
All files in this directory are auto generated. Do not change any of
them. To contribute translations, please head over to
https://www.transifex.com/projects/p/syncthing/
https://hosted.weblate.org/projects/syncthing/
Any updates made on Transifex will be automatically pulled into these
Any updates made on Weblate will be automatically pulled into these
files.

View File

@@ -0,0 +1,345 @@
{
"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",
"About": "حول",
"Action": "اجراء",
"Actions": "الإجراءات",
"Active filter rules": "قواعد التصفية النشطة",
"Add": "إضافة",
"Add Device": "إضافة جهاز",
"Add Folder": "إضافة مجلد",
"Add Remote Device": "أضافه جهاز بعيد",
"Add devices from the introducer to our device list, for mutually shared folders.": "اضف أجهزة من المعرف/المقدم إلى قائمة الأجهزة الخاصة بنا، للمجلدات المشتركة بشكل متبادل.",
"Add filter entry": "إضافة عامل التصفية",
"Add ignore patterns": "أضف أنماط التجاهل",
"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 مرة، وهو الافتراضي الجديد من 1H). يمكنك أيضًا التحكم بالإعدادات وتعديلها يدويًا لكل مجلد لاحقًا بعد اختيار \"لا\".",
"Address": "العنوان",
"Addresses": "العناوين",
"Advanced": "متقدم",
"Advanced Configuration": "ضبط متقدم",
"All Data": "كل المعلومات",
"All Time": "كل الوقت",
"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": "أبجدية",
"Altered by ignoring deletes.": "تم التغيير بتجاهل عمليات الحذف.",
"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?": "هل تريد الانتقال الى التصميم الجديد لتقرير الاستخدام المجهول ؟",
"Apply": "تقدم",
"Are you sure you want to override all remote changes?": "هل أنت متأكد أنك تريد تجاوز كافة التغييرات عن بُعد؟",
"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 revert all local changes?": "هل أنت متأكد أنك تريد التراجع عن كافة التغييرات المحلية؟",
"Are you sure you want to upgrade?": "هل أنت متأكد أنك تريد الترقية؟",
"Authors": "المؤلفون",
"Auto Accept": "القبول تلقائيا",
"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.": "الترقية التلقائية مفعلة دائمًا للنسخ المرشحة. ",
"Automatically create or share folders that this device advertises at the default path.": "تلقائيا أنشئ وشارك المجلدات الموجودة في المسار الافتراضي.",
"Available debug logging facilities:": "خدمات سجلات تدقيق البرمجيات المتوفرة:",
"Be careful!": "احذر!",
"Body:": "جسم:",
"Bugs": "أخطاء برمجية",
"Cancel": "إلغاء",
"Changelog": "سجل التغيير",
"Clean out after": "نظف بعد",
"Cleanup Interval": "الفاصل الزمني للتنظيف",
"Click to see full identification string and QR code.": "انقر لرؤية سلسلة التعريف الكاملة ورمز الاستجابة السريعة QR.",
"Close": "أغلق",
"Command": "أمر",
"Comment, when used at the start of a line": "التعليق، عندما تستخدم في بداية خط",
"Compression": "ضغط",
"Configuration Directory": "دليل التكوين",
"Configuration File": "ملف الضبط",
"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": "منسوخ من الأصل",
"Copied!": "تم النسخ",
"Copy": "نسخ",
"Copy failed! Try to select and copy manually.": "فشل النسخ! حاول التحديد والنسخ يدويًا.",
"Currently Shared With Devices": "حاليًا تم مشاركته مع الأجهزة",
"Custom Range": "نطاق مخصص",
"Danger!": "خطر!",
"Database Location": "موقع قاعدة البيانات",
"Debugging Facilities": "خدمات تدقيق البرمجيات",
"Default": "أفتراضي",
"Default Configuration": "اعدادات افتراضية",
"Default Device": "الجهاز الافتراضي",
"Default Folder": "المجلد الافتراضي",
"Default Ignore Patterns": "أنماط التجاهل الافتراضية",
"Defaults": "الافتراضات",
"Delete": "حذف",
"Deselect All": "الغاء تحديد الكل",
"Device": "جهاز",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "الجهاز \"{{الاسم}}\" ({{الجهاز}} في {{العنوان}}) يرغب في الاتصال، إضافة جهاز جديد؟",
"Device ID": "هوية الجهاز",
"Device Identification": "هوية الجهاز",
"Device Name": "أسم الجهاز",
"Device rate limits": "حدود معدل نقل البيانات",
"Device that last modified the item": "اخر جهاز جهاز عدل على العنصر",
"Devices": "الأجهزة",
"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:": "تعطيل المسح الدوري وفشل إعداد مشاهدة التغييرات، إعادة المحاولة كل 1 دقيقة:",
"Discard": "تجاهل",
"Disconnected": "غير متصل",
"Discovered": "مكتشفة",
"Discovery": "اكتشاف",
"Discovery Failures": "فشل الاكتشاف",
"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 Device": "تعديل الجهاز",
"Edit Folder": "تعديل المجلد",
"Editing {%path%}.": "تعديل {{path}}.",
"Enable Crash Reporting": "تفعيل التبليغ عن الاخطاء",
"Enable NAT traversal": "تفعيل اجتياز النات",
"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\") أو \"العناوين الديناميكية\" للاكتشاف التلقائي للعنوان.",
"Enter ignore patterns, one per line.": "ادخل نمط التجاهل، كل نمط في سطر.",
"Error": "خطأ",
"External File Versioning": "إصدار الملف الخارجي",
"Failed Items": "العناصر الفاشلة",
"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": "ملف الإصدارات",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "الملفات يتم نقلها إلى دليل .stversions عند الاستبدال أو الحذف بواسطة البرنامج.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "يتم نقل الملفات إلى الإصدارات المؤرخة المختومة في دليل .vversions عند استبدالها أو حذفها بواسطة 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.": "الملفات محمية من التغييرات التي تم إجراؤها على الأجهزة الأخرى ، ولكن سيتم إرسال التغييرات التي تم إجراؤها على هذا الجهاز إلى بقية الأجهزة.",
"Filesystem Watcher Errors": "أخطاء مراقب نظام الملفات",
"Filter by date": "فلتره بالتاريخ ",
"Filter by name": "فلتر باستخدام الاسم",
"Folder": "مجلد",
"Folder ID": "هوية المجلد",
"Folder Label": "تسمية المجلد",
"Folder Path": "مسار المجلد",
"Folder Type": "نوع المجلد",
"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)": "مدة أعاده الفحص الكامل (ثانية)",
"GUI": "واجهة المستخدم الرسومية",
"GUI Authentication Password": "كلمة الس",
"GUI Authentication User": "أسم المستخدم لدخول واجهة الرسومية",
"GUI Listen Address": "واجهة الرسومية الاستماع الى العنوان",
"GUI Theme": "شكل الواجه",
"General": "عام",
"Generate": "توليد",
"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.": "ومع ذلك، تشير إعداداتك الحالية إلى أنك قد لا ترغب في تمكينه. لذلك تم تعطيل الإبلاغ التلقائي عن الأعطال.",
"Ignore": "تجاهل",
"Ignore Patterns": "تجاهل الأنماط",
"Ignore Permissions": "تجاهل الصلاحيات",
"Ignored Devices": "الأجهزة المتجاهلة",
"Ignored Folders": "المجلدات المتجاهلة",
"Ignored at": "تجاهل عند",
"Incoming Rate Limit (KiB/s)": "الحد الأقصى البيانات الواردة (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "الإعدادات الغير صحيحه قد تدمر بيانات المجلد وتجعل المزامنة غير صالحه للعمل",
"Introduced By": "عرف بواسطة",
"Introducer": "المعرف",
"Keep Versions": "احتفظ بالاصدارات",
"LDAP": "LDAP",
"Largest First": "الأكبر أولا",
"Last Scan": "اخر فحص",
"Last seen": "اخر ظهور",
"Latest Change": "اخر التغييرات",
"Learn more": "اعرف اكثر ",
"Limit": "الحد",
"Listeners": "المستمعين",
"Loading data...": "تحميل بيانات...",
"Loading...": "تحميل...",
"Local Discovery": "الاكتشاف المحلي",
"Local State": "الحالة المحلية",
"Local State (Total)": "الحالة المحلية (مجموع)",
"Locally Changed Items": "العناصر المتغيرة محليا",
"Log": "سجل",
"Logs": "سجلات",
"Major Upgrade": "ترقية أساسية",
"Maximum Age": "أقصى مدة",
"Metadata Only": "البيانات الوصفية فقط",
"Minimum Free Disk Space": "أدنى حد لمساحة التخزين الحرة",
"Move to top of queue": "الانتقال لأعلى قائمة الانتظار",
"Never": "أبدا",
"New Device": "جهاز جديد",
"New Folder": "مجلد جديد",
"Newest First": "الأحدث أولا",
"No": "لا",
"No files will be deleted as a result of this operation.": "لن يتم حذف اي ملفات بسبب هذا العملية",
"No upgrades": "لا يوجد ترقيات",
"Notice": "ملاحظة",
"OK": "موافق",
"Off": "اطفئ",
"Oldest First": "الأقدم أولا",
"Optional descriptive label for the folder. Can be different on each device.": "تسمية وصفية اختيارية للمجلد . يمكن أن تكون مختلفة على كل جهاز. ",
"Options": "خيارات",
"Out of Sync": "خارج التزامن",
"Out of Sync Items": "عناصر خارج التزامن",
"Override Changes": "تخطي التغييرات",
"Path": "مسار",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "المسار حيث تخزن الإصدارات (يترك فارغًا لدليل .vversions الافتراضي في المجلد المشترك).",
"Pause": "إيقاف",
"Pause All": "أيقاف الكل ",
"Paused": "توقف",
"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:": "المسح الدوري خلال فترة زمنية معينة وفشل اعداد مشاهدة التغييرات، اعادة المحاولة كل 1 دقيقة.",
"Please consult the release notes before performing a major upgrade.": "يرجى العودة إلى ملاحظات الإصدار قبل تنفيذ ترقية رئيسية.",
"Please wait": "يرجى الانتظار",
"Preview": "معاينة",
"Preview Usage Report": "معاينة تقرير الاستخدام",
"Quick guide to supported patterns": "الدليل مختصر للأنماط المدعومة ",
"Random": "عشوائي",
"Receive Only": "استقبال فقط",
"Recent Changes": "اخر التغييرات",
"Reduced by ignore patterns": "تقليص بواسطة تجاهل الأنماط. ",
"Release Notes": "ملاحظات الإصدار",
"Remote Devices": "جهاز بعيد",
"Remove": "إزالة",
"Remove Device": "حذف جهاز",
"Remove Folder": "حذف مجلد",
"Required identifier for the folder. Must be the same on all cluster devices.": "يتطلب معرفًا للمجلد. يجب أن يستخدم نفس المعرف لبقية الأجهزة. ",
"Rescan": "إعادة فحص",
"Rescan All": "أعادة فحص الكل",
"Rescans": "يعيد الفحص",
"Restart": "إعادة تشغيل",
"Restart Needed": "مطلوب أعادة تشغيل",
"Restarting": "يتم إعادة التشغيل",
"Restore": "استعادة",
"Restore Versions": "استعادة أصدارات ",
"Resume": "استرد",
"Resume All": "استعادة الكل ",
"Reused": "إعادة الاستخدام",
"Revert Local Changes": "التراجع عن التغييرات",
"Save": "حفظ",
"Scan Time Remaining": "فحص الوقت المتبقي",
"Scanning": "يتم الفحص",
"See external versioning help for supported templated command line parameters.": "راجع تعليمات الإصدارات الخارجية لمعرفة القيم المدعومة في سطر الأوامر. ",
"Select All": "تحديد الكل",
"Select a version": "اختار أصدار ",
"Select latest version": "اختار اخر أصدار ",
"Select oldest version": "اختيار أقدم إصدار",
"Send & Receive": "إرسال واستقبال ",
"Send Only": "إرسال فقط",
"Settings": "إعدادات",
"Share": "مشاركة",
"Share Folder": "مشاركة مجلد",
"Share this folder?": "مشاركة هذا المجلد؟",
"Shared With": "مشاركة مع",
"Sharing": "مشاركه",
"Show ID": "عرض الهوية",
"Show QR": "اظهار QR",
"Show diff with previous version": "اظهر الفرق مع النسخة السابقة ",
"Shutdown": "إغلاق",
"Shutdown Complete": "تم الإغلاق",
"Size": "حجم",
"Smallest First": "الأصغر أولا",
"Some items could not be restored:": "بعض العناصر لا يمكن استرجاعها:",
"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 only": "الإصدارات المستقرة فقط",
"Start Browser": "تشغيل المتصفح",
"Statistics": "إحصائيات",
"Stopped": "متوقف",
"Support": "الدعم",
"Support Bundle": "حزمه مدعومه",
"Sync Protocol Listen Addresses": "عناوين بروتوكول استقبال المزامنة",
"Syncing": "يتم التزامن",
"Syncthing has been shut down.": "تم إيقاف Syncthing.",
"Syncthing includes the following software or portions thereof:": "المزامنة تتضمن البرامج التالية أو أجزائها:",
"Syncthing is restarting.": "يتم إعادة تشغيل Syncthing.",
"Syncthing is upgrading.": "يتم تطوير Syncthing.",
"Take me back": "رجوع",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "تم حفظ الإعدادات ولكن لم يتم تفعيلها بعد. يجب أعادة تشغيل Syncthing حتى تم تفعيل الإعدادات.",
"The device ID cannot be blank.": "هوية الجهاز لا يمكن أن تكون فارغة.",
"The folder ID cannot be blank.": "هوية المجلد لا يمكن أن تكون فارغة.",
"The folder ID must be unique.": "يجب أن يكون عنوان المجلد فريد ",
"The folder path cannot be blank.": "مسار المجلد لا يمكن أن يكون فارغ",
"The following items could not be synchronized.": "فشل مزامنة العناصر التالية",
"The following items were changed locally.": "تم تغيير العناصر التالية محليا",
"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 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.": "يجب أن يكون الفاصل الزمني لإعادة الفحص عددًا غير سالب من الثواني.",
"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 is a major version upgrade.": "ترقية أساسية ",
"Time": "الوقت",
"Time the item was last modified": "توقيت اخر تعديل للعنصر",
"Twitter": "Twitter",
"Type": "نوع",
"Unavailable": "غير متوفر",
"Unavailable/Disabled by administrator or maintainer": "غير متوفر/معطل من قبل المسؤول أو الصيانة",
"Undecided (will prompt)": "غير محدد ( ستظهر نافذة للتحديد لاحقًا )",
"Unignore": "لا يتم التجاهل",
"Unknown": "غير معرف",
"Unshared": "غير مشترك",
"Up to Date": "اخز أصدار ",
"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.": "استخدم أشغارات نظام الملفات لمعرفة الملفات المتغيرة",
"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.": "يتم حذف الإصدارات تلقائيًا إذا تجاوزت العمر الأقصى أو تجاوزت عدد الملفات المسموح بها خلال فاصل زمني محدد.",
"Watch for Changes": "راقب التغييرات",
"Watching for Changes": "جاري مراقبة التغيرات",
"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 folders.": "لا يوجد مجلدات في قائمه التجاهل ",
"You have unsaved changes. Do you really want to discard them?": "الإعدادات لم تحفظ. هل انت متأكد من الإلغاء؟ ",
"You must keep at least one version.": "يجب الاحتفاظ بنسخة واحده على الاقل",
"days": "أيام",
"directories": "مجلدات",
"files": "ملفات",
"full documentation": "الوثائق الكاملة",
"items": "العناصر",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} يريد مشاركة مجلد \"{{folder}}\". ",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} يريد مشاركة مجلد \"{{folderlabel}}\" ({{folder}}). "
}

View File

@@ -0,0 +1,124 @@
{
"API Key": "Ключ API",
"About": "Аб праграме",
"Actions": "Дзеянні",
"Add": "Дадаць",
"Add Device": "Дадаць прыладу",
"Add Folder": "Дадаць каталёг",
"Add new folder?": "Дадаць новы каталёг ?",
"Address": "Адрас",
"Addresses": "Адрасы",
"Allow Anonymous Usage Reporting?": "Allow Anonymous Usage Reporting?",
"Anonymous Usage Reporting": "Anonymous Usage Reporting",
"Bugs": "Памылкі",
"Changelog": "Сьпіс зьменаў",
"Close": "Зачыніць",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Connection Error": "Connection Error",
"Danger!": "Небязпечна!",
"Delete": "Выдаліць",
"Device ID": "ID прылады",
"Device Identification": "Ідэнтыфікацыя прылады",
"Device Name": "Назва прылады",
"Devices": "Прылады",
"Disconnected": "Адлучана",
"Documentation": "Дакумэнтацыя",
"Download Rate": "Хуткасьць спампоўваньня",
"Edit": "Зьмяніць",
"Edit Device": "Зьмяніць прыладу",
"Edit Folder": "Зьмяніць каталёг",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Памылка",
"File Versioning": "Вэрсіі файлаў",
"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.",
"Folder ID": "ID каталёгу",
"Folder Path": "Шлях каталёгу",
"Folders": "Каталёгі",
"GUI Authentication Password": "GUI Authentication Password",
"GUI Authentication User": "GUI Authentication User",
"Generate": "Сгенераваць",
"Global Discovery": "Глябальнае вызначэньне",
"Global State": "Глябальны стан",
"Ignore Patterns": "Ігнараваць шаблёны",
"Ignore Permissions": "Ігнараваць правы",
"Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)",
"Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Keep Versions": "Трымаць вэрсій",
"LDAP": "LDAP",
"Last seen": "Апошні раз бачылі",
"Local Discovery": "Лякальнае вызначэньне",
"Local State": "Лякальны стан",
"Maximum Age": "Maximum Age",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Ніколі",
"No": "Не",
"No File Versioning": "Не захоўваць вэрсіі",
"Notice": "Notice",
"OK": "Добра",
"Out of Sync Items": "Несынхранізаваныя складнікі",
"Outgoing Rate Limit (KiB/s)": "Outgoing Rate Limit (KiB/s)",
"Override Changes": "Override Changes",
"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",
"Please wait": "Please wait",
"Preview": "Preview",
"Preview Usage Report": "Preview Usage Report",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"Rescan": "Перачытаць",
"Restart": "Перастартаваць",
"Restart Needed": "Патрэбна перастартоўваньне",
"Restarting": "Перастартоўваньне",
"Save": "Захаваць",
"Scanning": "Скануецца",
"Settings": "Налады",
"Share": "Абагуліць",
"Share this folder?": "Абагуліць гэты каталёг ?",
"Shared With": "Абагулены з",
"Show ID": "Паказаць ID",
"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)": "Single level wildcard (matches within a directory only)",
"Source Code": "Зыходнікі",
"Staggered File Versioning": "Адаптыўнае захоўваньне вэрсій",
"Start Browser": "Start Browser",
"Stopped": "Спынена",
"Support": "Падтрымка",
"Sync Protocol Listen Addresses": "Sync Protocol Listen Addresses",
"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 restarting.": "Syncthing перастартоўвае.",
"Syncthing is upgrading.": "Syncthing is upgrading.",
"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…",
"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 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 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 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 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.",
"Twitter": "Twitter",
"Unknown": "Невядома",
"Up to Date": "Найноўшае",
"Upgrade To {%version%}": "Upgrade To {{version}}",
"Upgrading": "Абнаўленьне",
"Upload Rate": "Хуткасьць запампоўваньня",
"Use HTTPS for GUI": "Use HTTPS for GUI",
"Version": "Вэрсія",
"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.",
"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": "Так",
"You must keep at least one version.": "You must keep at least one version.",
"full documentation": "full documentation",
"items": "складнікаў"
}

View File

@@ -1,418 +1,531 @@
{
"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 Ключ",
"About": "За програмата",
"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": "Ключ за ППИ",
"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?": "Добави нова папка?",
"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ч). Освен това може да го зададете и ръчно за всяка папка след като изберете Не.",
"Actions": "Действия",
"Active filter rules": "Включени филтриращи правила",
"Add": "Добавяне",
"Add Device": "Добавяне на устройство",
"Add Folder": "Добавяне на папка",
"Add Remote Device": "Добавяне на устройство",
"Add devices from the introducer to our device list, for mutually shared folders.": "Добавяйте устройства през поръчителите за взаимно споделени папки.",
"Add filter entry": "Ново филтриращо правило",
"Add ignore patterns": "Добавяне на шаблони за пренебрегване",
"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": "Разширени",
"Advanced Configuration": "Разширени настройки",
"All Data": "Всички данни",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.",
"Allow Anonymous Usage Reporting?": "Разрешаване изпращането на анонимни статистически данни?",
"All Time": "През цялото време",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Всички папки, споделени с устройството трябва да бъдат защитени с парола, така че данните да са недостъпни без нея.",
"Allow Anonymous Usage Reporting?": "Разрешавате ли анонимно отчитане на употребата?",
"Allowed Networks": "Разрешени мрежи",
"Alphabetic": "Азбучен ред",
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Външна команда се занимава с версиите. Тази команда трябва да премахне файла от синхронизираната папка. Ако пътят до това приложение използва интервали, то той трябва да бъде заграден в кавички.",
"Anonymous Usage Reporting": "Анонимен доклад",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Форматът на анонимния доклад е променен. Желаете ли да преминете към новия формат?",
"Are you sure you want to continue?": "Are you sure you want to continue?",
"Are you sure you want to 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?",
"Altered by ignoring deletes.": "Промяна чрез пренебрегване на премахваните елементи.",
"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?": "Форматът на данните за анонимно отчитане на употреба е променен. Желаете ли да използвате него вместо стария?",
"Apply": "Прилагане",
"Are you sure you want to override all remote changes?": "Сигурни ли сте, че желаете да отмените всички промени, направени отдалечено?",
"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 revert all local changes?": "Сигурни ли сте, че желаете всички местни промени да бъдат отменени?",
"Are you sure you want to upgrade?": "Желаете ли приложението да бъде обновено?",
"Authors": "Автори",
"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.",
"Automatically create or share folders that this device advertises at the default path.": "Автоматично създаване или споделяне на папки, които това устройство предлага в пътя по подразбиране.",
"Available debug logging facilities:": ебъгинг функционалност на разположение:",
"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": "Бъгове",
"Changelog": "Списък с промени",
"Clean out after": "Изчисти след",
"Cleaning Versions": "Cleaning Versions",
"Cleanup Interval": "Cleanup Interval",
"Click to see discovery failures": "Натиснете, за да видите грешки при откриването",
"Close": "Затвори",
"Body:": "Съдържание:",
"Bugs": "Дефекти",
"Cancel": "Отказ",
"Changelog": "Дневник на промените",
"Clean out after": "Почистване след",
"Cleaning Versions": "Почистване на версии",
"Cleanup Interval": "Интервал на почистване",
"Click to see full identification string and QR code.": "Преглед на идентификатор и код за QR.",
"Close": "Затваряне",
"Command": "Команда",
"Comment, when used at the start of a line": "Коментар, използван в началото на реда",
"Comment, when used at the start of a line": "Коментар, когато се използва в началото на реда",
"Compression": "Компресиране",
"Configuration Directory": "Папка с настройките",
"Configuration File": "Файл с настройки",
"Configured": "Настроен",
"Connected (Unused)": "Connected (Unused)",
"Connection Error": "Грешка при свързването",
"Connection Type": "Вид връзка",
"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-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",
"Connections via relays might be rate limited by the relay": "Препращаните връзки могат да бъдат обект на ограничения от препращащото устройство",
"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": "Копирано от източника",
"Copied!": "Копирано!",
"Copy": "Копиране",
"Copy failed! Try to select and copy manually.": "Не е копирано! Копирайте текста ръчно.",
"Currently Shared With Devices": "Устройства, с които е споделена",
"Custom Range": "В периода",
"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 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.",
"Database Location": "Местоположение на банката от данни",
"Debugging Facilities": "Отстраняване на дефекти",
"Default": "По подразбиране",
"Default Configuration": "Настройки по подразбиране",
"Default Device": "Устройство по подразбиране",
"Default Folder": "Папка по подразбиране",
"Default Ignore Patterns": "Подразбирани шаблони за пренебрегване",
"Defaults": "Подразбирани",
"Delete": "Изтрий",
"Delete Unexpected Items": "Премахване на неочакваните",
"Deleted {%file%}": "{{file}} премахнат",
"Deselect All": "Изчистване",
"Deselect devices to stop sharing this folder with.": "Махнете отметката от устройство, за да спрете споделяне с него.",
"Deselect folders to stop sharing with this device.": "Махнете отметката пред папката, за да спрете споделянето ѝ с устройството.",
"Device": "Устройство",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Устройство \"{{name}}\" ({{device}}) с адрес {{address}} желае да се свърже. Да бъде ли добавено?",
"Device Certificate": "Сертификат на устройството",
"Device ID": "Идентификатор на устройство",
"Device Identification": "Идентификатор на устройството",
"Device Identification": "Идентификатор на устройство",
"Device Name": "Име на устройството",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device rate limits": "Device rate limits",
"Device is untrusted, enter encryption password": "Устройството е недоверено, въведете парола за шифроване",
"Device rate limits": "Ограничаване на скоростта",
"Device that last modified the item": "Устройство, което последно промени обекта",
"Devices": "Устройства",
"Disable Crash Reporting": "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:": "Периодичните сканирания са деактивирани и задаването на наблюдение за промени е неуспешно, ще опита пак след 1мин:",
"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",
"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:": "Изключено периодично обхождане и грешка при започване на наблюдението за промени, прави се опит всяка минута:",
"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": "Отказване",
"Disconnected": "Не е свързано",
"Disconnected (Unused)": "Disconnected (Unused)",
"Disconnected (Inactive)": "Не е свързано (неизползвано)",
"Disconnected (Unused)": "Не е свързано (неизползвано)",
"Discovered": "Открит",
"Discovery": "Откриване",
"Discovery Failures": "Грешка в откриването",
"Do not restore": "Не възстановявай",
"Do not restore all": "Не възстановявай всички",
"Do you want to enable watching for changes for all your folders?": "Желаете ли да активирате наблюдението за промени на всички папки?",
"Discovery Failures": "Грешка при откриване",
"Discovery Status": "Състояние на откриване",
"Dismiss": "Отхвърляне",
"Do not add it to the ignore list, so this notification may recur.": "Да не бъде добавяна в списъка за пренебрегване, така че да има повторно запитване.",
"Do not restore": "Без възстановяване",
"Do not restore all": "Без възстановяване всички",
"Do you want to enable watching for changes for all your folders?": "Желаете ли да наблюдението за промени да бъде включено за всички папки?",
"Documentation": "Документация",
"Download Rate": "Скорост на сваляне",
"Downloaded": "Изтеглен",
"Download Rate": "Скорост на изтегляне",
"Downloaded": "Изтеглено",
"Downloading": "Изтегляне",
"Edit": "Промени",
"Edit Device": "Промяна на устройството",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Folder": "Промяна на папката",
"Edit Folder Defaults": "Edit Folder Defaults",
"Edit": "Редактиране",
"Edit Device": "Промяна на устройство",
"Edit Device Defaults": "За нови устройства",
"Edit Folder": "Промяна на папка",
"Edit Folder Defaults": "За нови папки",
"Editing {%path%}.": "Променяне на {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable NAT traversal": "Разреши NAT traversal",
"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\") и изберете единица.\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 ignore patterns, one per line.": "Добавете шаблони за игнориране, по един на ред.",
"Enter up to three octal digits.": "Enter up to three octal digits.",
"Enable Crash Reporting": "Включване на доклад за срив",
"Enable NAT traversal": "Преминаване през NAT",
"Enable Relaying": "Препращане",
"Enabled": "Включено",
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "Когато е отметнато разширените атрибути се изпращат към другите устройства, а получените разширени атрибути се прилагат. Обикновено изисква съответните за целта права.",
"Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when \"Sync Extended Attributes\" is enabled.": "Когато е отметнато разширените атрибути се изпращат към другите устройства, но получените разширени атрибути не се прилагат. Може да има значително неблагоприятно влияние върху производителността. Винаги е отметнато когато „Синхронизиране на разширени атрибути“ е отметнато.",
"Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.": "Когато е отметнато информацията за собственост се изпраща към другите устройства, а получената информация за собственост се прилага. Обикновено изисква съответните за целта права.",
"Enables sending ownership information to other devices, but not applying incoming ownership information. This can have a significant performance impact. Always enabled when \"Sync Ownership\" is enabled.": "Когато е отметнато информацията за собственост се изпраща към другите устройства, но получената информация за собственост не се прилага. Може да има значително неблагоприятно влияние върху производителността. Винаги е отметнато когато „Синхронизиране на собственост“ е отметнато.",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Въведете положително число (например „3.14“) и изберете единица мярка. Процентите са части от цялото дисково пространство.",
"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 ignore patterns, one per line.": "Въведете шаблони за пренебрегване, по един на ред.",
"Enter up to three octal digits.": "Въведете до три осмични цифри.",
"Error": "Грешка",
"External File Versioning": "Външно управление на версиите",
"Failed Items": "Неуспешни",
"Failed to setup, retrying": "Неуспешно конфигуриране, правенe на повторен опит",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Неуспешна връзка към IPv6 сървъри може да се очаква ако няма IPv6 свързаност.",
"File Pull Order": "Ред на сваляне",
"Extended Attributes": "Разширени атрибути",
"Extended Attributes Filter": "Филтър за разширени атрибути",
"External": "Външни",
"External File Versioning": "Външно управление на версии",
"Failed Items": "Елементи с грешка",
"Failed to load file versions.": "Грешка при зареждане на версии.",
"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": "Версии на файловете",
"Files are moved to .stversions directory 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 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 Watcher Errors": "Filesystem Watcher Errors",
"Files are moved to .stversions directory 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 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 Watcher Errors": "Грешка при наблюдаване на файловата система",
"Filter by date": "Филтриране по дата",
"Filter by name": "Филтриране по име",
"Folder": "Папка",
"Folder ID": "Идентификатор на папката",
"Folder Label": "Име на папката",
"Folder Path": "Път до папката",
"Folder Type": "Вид папка",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Folder type \"{{receiveEncrypted}}\" can only be set when adding a new folder.",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Folder type \"{{receiveEncrypted}}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.",
"Folder Type": "Вид на папката",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Вида „{{receiveEncrypted}}“ може да бъде избран само при добавяне на папка.",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Видът папката „{{receiveEncrypted}}“ не може да бъде променян след нейното създаване. Трябва да я премахнете, изтриете или разшифровате съдържанието и да добавите папката отново.",
"Folders": "Папки",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "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)": "Интервал(и) за периодичното сканиране",
"GUI": "Потребителски интерфейс",
"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.": "Грешка при започване на наблюдението за промени на следните папки. Всяка минута ще бъде извършван нов опит, така че грешката скоро може да изчезне. Ако все пак не изчезне, отстранете нейната първопричина или потърсете помощ ако не съумявате.",
"Forever": "Завинаги",
"Full Rescan Interval (s)": "Интервал на пълно обхождане (секунди)",
"GUI": "Графичен интерфейс",
"GUI / API HTTPS Certificate": "Сертификат на интерфейса / ППИ през HTTPS",
"GUI Authentication Password": "Парола за интерфейса",
"GUI Authentication User": "Потребител за интерфейса",
"GUI Authentication: Set User and Password": "GUI Authentication: Set User and Password",
"GUI Listen Address": "Адрес на слушане на GUI-то",
"GUI Theme": "Тема за потребителския интерфейс",
"GUI Authentication: Set User and Password": "Удостоверяване на графичния интерфейс: потребител и парола",
"GUI Listen Address": "Адрес на слушане",
"GUI Override Directory": "Папка за заменяне на интерфейса",
"GUI Theme": "Тема на графичния интерфейс",
"General": "Общи",
"Generate": "Генерирай",
"Generate": "Подновяване",
"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.",
"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 Folders": "Игнорирани папки",
"Ignored at": "Ignored at",
"Incoming Rate Limit (KiB/s)": "Лимит на скоростта за сваляне (KiB/s)",
"Hint: only deny-rules detected while the default is deny. Consider adding \"permit any\" as last rule.": "Подсказка: има само забрабяващи правила, а по подразбиране е „забранено“. Помислете дали да не добавите „permit any“ като последно правило.",
"Home page": "Страница",
"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.": "Ако желаете да предотвратите достъпа на другите потребители на устройството до Syncthing, а чрез него и до файловете ви, помислете за удостоверяване на графичния интерфейс.",
"Ignore": "Пренебрегване",
"Ignore Patterns": "Шаблони за пренебрегване",
"Ignore Permissions": "Пренебрегване на права",
"Ignore patterns can only be added after the folder is created. If checked, an input field to enter ignore patterns will be presented after saving.": "Шаблони за пренебрегване могат да бъдат добавяни след като папката бъде създадена. Ако е отметнато, след запазване ще бъде показано текстово поле за шаблоните.",
"Ignored Devices": "Пренебрегнати устройства",
"Ignored Folders": "Пренебрегнати папки",
"Ignored at": "Пренебрегнато на",
"Included Software": "Включен софтуер",
"Incoming Rate Limit (KiB/s)": "Ограничение при изтегляне (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Неправилни настройки могат да повредят файлове и да попречат на синхронизирането.",
"Internally used paths:": "Вътрешно използвани пътища:",
"Introduced By": "Предложено от",
"Introducer": "Може да предлага други устройства",
"Inversion of the given condition (i.e. do not exclude)": "Обратното на даденото условие (пр. не изключвай)",
"Keep Versions": "Пази версии",
"Introducer": "Поръчител",
"Inversion of the given condition (i.e. do not exclude)": "Обръща значението на условието (напр. да не се отхвърля)",
"Keep Versions": "Пазени версии",
"LDAP": "LDAP",
"Largest First": " Първо най-големите",
"Last Scan": "Последно сканирана",
"Largest First": "Първо най-големи",
"Last 30 Days": "Последните 30 дена",
"Last 7 Days": "Последните 7 дена",
"Last Month": "Миналия месец",
"Last Scan": "Последно обхождане",
"Last seen": "Последно видяно",
"Latest Change": "Последна промяна",
"Learn more": "Научете повече",
"Limit": "Limit",
"Listeners": "Синхронизиращи устройства",
"Learn more at {%url%}": "Научете повече на {{url}}",
"Limit": "Ограничение",
"Listener Failures": "Грешки при очакване на връзка",
"Listener Status": "Очакване на връзка",
"Listeners": "Очакване на връзка",
"Loading data...": "Зареждане на информация...",
"Loading...": "Зареждане...",
"Local Additions": "Local Additions",
"Local Discovery": "Локално откриване",
"Local State": "Локално състояние",
"Local State (Total)": "Локално състояние (общо)",
"Locally Changed Items": "Locally Changed Items",
"Log": оклад",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Доклади",
"Major Upgrade": "Основно Обновяване",
"Mass actions": "Действия за всички",
"Local Additions": "Местно добавени",
"Local Discovery": "Месно откриване",
"Local State": "Местно състояние",
"Local State (Total)": "Местно състояние (общо)",
"Locally Changed Items": "Местно променени",
"Log": невник",
"Log File": "Дневник",
"Log tailing paused. Scroll to the bottom to continue.": "Добавяне на редове към дневника е спряно. Плъзнете най-долу за да продължи.",
"Logs": "Дневници",
"Major Upgrade": "Обновяване на значимо издание",
"Mass actions": "Мащабни действия",
"Maximum Age": "Максимална възраст",
"Maximum single entry size": "Максимален размер на обект",
"Maximum total size": "Максимален общ размер",
"Metadata Only": "Само мета информация",
"Minimum Free Disk Space": "Минимално свободно дисково пространство",
"Mod. Device": "Променящо устройство",
"Mod. Time": "Дата на промяна",
"Move to top of queue": "Премести в началото на опашката",
"Multi level wildcard (matches multiple directory levels)": "Маска на много нива (покрива папки с много нива)",
"More than a month ago": "Преди повече от месец",
"More than a week ago": "Преди повече от седмица",
"More than a year ago": "Преди повече от година",
"Move to top of queue": "Премества най-отпред на опашката",
"Multi level wildcard (matches multiple directory levels)": "Заместващ символ за няколко нива (съвпада с папки, вложени на няколко нива)",
"Never": "никога",
"New Device": "Ново устройство",
"New Folder": "Нова папка",
"Newest First": "Първо най-новите",
"Newest First": "Първо най-нови",
"No": "Не",
"No File Versioning": "Без версии",
"No files will be deleted as a result of this operation.": "Няма да бъдат изтрити файлове като резултат от тази операция.",
"No upgrades": "Няма обновления",
"Not shared": "Not shared",
"No File Versioning": "Без пазене на версии",
"No files will be deleted as a result of this operation.": "В резултат на операцията няма да бъдат премахнати файлове.",
"No rules set": "Няма установени правила",
"No upgrades": "Без обновяване",
"Not shared": "Не споделена",
"Notice": "Известие",
"OK": "ОК",
"OK": "Добре",
"Off": "Изключено",
"Oldest First": "Първо най-старите",
"Oldest First": "Първо най-стари",
"Optional descriptive label for the folder. Can be different on each device.": "Незадължително име на папката. Може да бъде различно на всяко устройство.",
"Options": "Настройки",
"Out of Sync": "Несинхронизирано",
"Out of Sync Items": "Несинхронизирани елементи",
"Outgoing Rate Limit (KiB/s)": "Лимит на скорост за качване (KiB/s)",
"Override Changes": "Наложи локалните промени",
"Outgoing Rate Limit (KiB/s)": "Ограничение при качване (KiB/s)",
"Override": "Налагане",
"Override Changes": "Налагане на местни промени",
"Ownership": "Собственост",
"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 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 versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Папка, в която да бъдат запазвани версиите (оставете празно за подразбираната директория .stversions в споделената папка).",
"Paths": "Пътища",
"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.": "Моля задайте потребителско име и парола за потребителския интерфейс в секцията Настройки.",
"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",
"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:": "Периодично обхождане и грешка при започване на наблюдението за промени, прави се опит всяка минута:",
"Permanently add it to the ignore list, suppressing further notifications.": "Добавяне за постоянно в списъка с пренебрегнати елементи, потискайки бъдещи известия.",
"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": "Подготовка за синхронизация",
"Preview": "Преглед",
"Preview Usage Report": "Преглед на статистиката",
"Quick guide to supported patterns": "Бърз наръчник към поддържаните шаблони",
"Preview Usage Report": "Преглед на отчет за употреба",
"QR code": "Код за QR",
"QUIC LAN": "QUIC LAN",
"QUIC WAN": "QUIC WAN",
"QUIC connections are in most cases considered suboptimal": "В повечето случаи връзките през протокола QUIC се считат за неоптимални",
"Quick guide to supported patterns": "Кратък наръчник на поддържаните шаблони",
"Random": "Произволен",
"Receive Encrypted": "Receive Encrypted",
"Receive Only": "Само получаване",
"Received data is already encrypted": "Received data is already encrypted",
"Receive Encrypted": "Приема шифровани данни",
"Receive Only": "Само получава",
"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.": "Кандидат версиите съдържат най-новата функционалност и поправки. Те са близки до традиционните дву-седмични Synchthing обновления.",
"Remote Devices": "Устройства",
"Remote GUI": "Remote GUI",
"Remove": "Премахни",
"Reduced by ignore patterns": "Наложени са шаблони за пренебрегване",
"Relay LAN": "Препращане по LAN",
"Relay WAN": "Препращане по WAN",
"Release Notes": "Бележки по изданието",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Предварителните издания съдържат най-новите възможности и поправки. Те са близки до традиционните, два пъти в седмицата, издания на Synchthing.",
"Remote Devices": "Отдалечени устройства",
"Remote GUI": "Отдалечен графичен интерфейс",
"Remove": "Премахване",
"Remove Device": "Премахване на устройство",
"Remove Folder": "Премахване на папка",
"Required identifier for the folder. Must be the same on all cluster devices.": "Задължителен идентификатор за папката. Трябва да бъде един и същ на всяко устройство.",
"Rescan": "Сканирай",
"Rescan All": "Сканирай всички",
"Rescans": "Повторни сканирания",
"Restart": "Рестартирай",
"Required identifier for the folder. Must be the same on all cluster devices.": "Задължителен идентификатор на папката. Трябва е еднакъв на всички устройства.",
"Rescan": "Обхождане",
"Rescan All": "Обхождане всички",
"Rescans": "Обхождане",
"Restart": "Рестартиране",
"Restart Needed": "Изисква се рестартиране",
"Restarting": "Рестартиране",
"Restore": "Възстановяване",
"Restore Versions": "Възстановяване на версии",
"Resume": "Пусни",
"Resume All": "Пусни всички",
"Reused": овторно използван",
"Revert Local Changes": "Revert Local Changes",
"Save": "Запази",
"Scan Time Remaining": "Оставащо време за сканиране",
"Scanning": "Сканиране",
"See external versioning help for supported templated command line parameters.": "Прегледайте външната документацията за поддържаните командни параметри. ",
"Resume": "Възобновяване",
"Resume All": "Възобновяване всички",
"Reused": реизползвано",
"Revert": "Отменяне",
"Revert Local Changes": "Отменяне на местни промени",
"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 folders to share with this device.": "Select additional folders to share with this device.",
"Select latest version": "Избор на най-новата версия",
"Select oldest version": "Избор на най-старата версия",
"Select the folders to share with this device.": "Изберете папките за споделяне с това устройство.",
"Send & Receive": "Изпращане и получаване",
"Send Only": "Само изпращане",
"Select additional devices to share this folder with.": "Изберете други устройства, с които да споделите с папката.",
"Select additional folders to share with this device.": "Изберете други папки, които да споделите с устройството.",
"Select latest version": "Избиране на най-новата версия",
"Select oldest version": "Избиране на най-старата версия",
"Send & Receive": "Изпраща и получава",
"Send Extended Attributes": "Изпращане на разширени атрибути",
"Send Only": "Само изпраща",
"Send Ownership": "Изпращане на собственост",
"Set Ignores on Added Folder": "Добавяне на шаблони за пренебрегване",
"Settings": "Настройки",
"Share": "Сподели",
"Share Folder": "Сподели папка",
"Share Folders With Device": "Споделяне на папки с устройството",
"Share this folder?": "Сподели тази папка?",
"Shared Folders": "Shared Folders",
"Share": "Споделяне",
"Share Folder": "Споделяне на папка",
"Share by Email": "Споделяне с писмо",
"Share by SMS": "Споделяне чрез SMS",
"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 ID": "Идентификатор",
"Show QR": реглед на QR",
"Show detailed discovery 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.": "В списъка на устройствата се показва вместо идентификатор. Ако бъде оставено празно ще бъде променено на името, което носи устройството.",
"Shutdown": "Изключване",
"Shutdown Complete": "Спирането завършено",
"Simple File Versioning": "Опростени версии",
"Single level wildcard (matches within a directory only)": "Маска на едно ниво (покрива само в папка)",
"Simple": "Обикновени",
"Simple File Versioning": "Обикновени версии",
"Single level wildcard (matches within a directory only)": "Заместващ символ за едно ниво (съвпада само с папка)",
"Size": "Размер",
"Smallest First": "Първо най-малките",
"Smallest First": "Първо най-малки",
"Some discovery methods could not be established for finding other devices or announcing this device:": "Следните методи за откриване не могат да бъдат използвани за намиране на други устройства или за обявяване на това устройство, за да бъде открито от останалите:",
"Some items could not be restored:": "Някои елементи не могат да бъдат възстановени:",
"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.": "Стабилните версии са забавени с две седмици. През това време те преминават през тестване като бъдат кандидат версии.",
"Some listening addresses could not be enabled to accept connections:": "Някои от адресите, на които Syncthing очаква връзка не могат да бъдат настроени да получават входящи връзки:",
"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 only": "Само стабилни версии",
"Staggered File Versioning": "Наслагващи се версии",
"Start Browser": "Стартирай браузъра",
"Staggered": "Разпределени",
"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.": "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.",
"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}}.",
"Subject:": "Относно:",
"Support": "Помощ",
"Support Bundle": "Support Bundle",
"Sync Protocol Listen Addresses": "Адрес за слушане на синхронизиращия протокол",
"Support Bundle": "Архив за поддръжка",
"Sync Extended Attributes": "Синхронизиране на разширени атрибути",
"Sync Ownership": "Синхронизиране на собственост",
"Sync Protocol Listen Addresses": "Адрес, на който слуша синхронизиращия протокол",
"Sync Status": "Състояние",
"Syncing": "Синхронизиране",
"Syncthing has been shut down.": "Syncthing е спрян.",
"Syncthing device ID for \"{%devicename%}\"": "Идентификатор от Syncthing на „{{devicename}}“",
"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 restarting.": "Syncthing се рестартира",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing е свободен софтуер с отворен код, под лиценза на MPL v2.0.",
"Syncthing is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it's transmitted over the internet.": "Syncthing е приложение за непрекъснато синхронизиране на файлове. Тя синхронизира файлове между два или повече компютъра в реално време, като има защита от любопитни погледи. Вашите данни са само ваши и вие заслужавате да избирате къде да бъдат съхранявани, дали да бъдат споделяни с трети страни и как да бъдат предавани през интернет.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "Syncthing очаква опити за установяване на връзка от други устройства на следните мрежови адреси:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Syncthing не слуша за опити за установяване на връзка от други устройства. Вероятно работят само изходящите връзки от това устройство.",
"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 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",
"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 ако проблемът продължава да съществува.",
"TCP LAN": "TCP LAN",
"TCP WAN": "TCP WAN",
"Take me back": "Назад",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "Адресът на интерфейса не се взима под внимание заради параметри при стартиране. Промените тук няма да бъдат отразени докато параметрите не бъдат променени.",
"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.": "Обобщение на събраните статистически ще намерите на долния URL адрес.",
"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 aggregated statistics are publicly available at the URL below.": "Обобщените статистически данни са публично достъпни на адреса по-долу.",
"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 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 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 content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "Съдържанието на папката в другите устройства ще бъде презаписано, за да стане еднакво със съдържанието на това устройство. Файловете, които ги няма тук, но съществуват на другите устройства ще бъдат премахнати.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "Съдържанието на папката в това устройство ще бъде презаписано, за да стане еднакво със съдържанието на другите устройства. Добавените файлове ще бъдат премахнати.",
"The folder path cannot be blank.": "Пътят до папката не може да бъде празен.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "Използва се следния интервал: за първия час се пази версия на всеки 30 секунди, за първия ден се пази версия на всеки час, за първите 30 дена се пази версия всеки ден, до максимума се пази една версия всяка седмица.",
"The following 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 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 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 text will automatically be inserted into a new message.": "Следният текст автоматично ще бъде вмъкнат в ново съобщение.",
"The following unexpected items were found.": "Следните елементи са намерени, но не са очаквани.",
"The interval must be a positive number of seconds.": "Интервалът трябва да е положителен брой секунди.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "Интервал, в секунди, на почистване на папката с версии. Нула изключва периодичното почистване.",
"The 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 maximum time to keep a version (in days, set to 0 to keep versions forever).": "Максимална продължителност за пазене на версия (в дни, за да не бъдат изтривани версии задайте 0).",
"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 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.": "Интервала на сканиране трябва да бъде не отрицателно число в секунди.",
"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 is a major version upgrade.": "Това е нова основна версия.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Тази настройка контролира нужното свободното място на основния (пр. този с базата данни) диск.",
"The remote device has not accepted sharing this folder.": "Отдалеченото устройство не е приело да споделя папката.",
"The remote device has paused this folder.": "Отдалеченото устройство е оставило на пауза папката.",
"The rescan interval must be a non-negative number of seconds.": "Интервалът на обхождане трябва да е положителен брой секунди.",
"There are no devices to share this folder with.": "Няма устройства, с които да споделите папката.",
"There are no file versions to restore.": "Файлът няма версии, които да бъдат възстановени.",
"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 Month": "Този месец",
"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 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",
"Unavailable": "Не е на разположение",
"Unavailable/Disabled by administrator or maintainer": "Не е на разположение/Деактивриан от администраторът или поддръжника",
"Time the item was last modified": "Час на последна промяна на елемента",
"To connect with the Syncthing device named \"{%devicename%}\", add a new remote device on your end with this ID:": "За да се свържете Syncthing с устройство с име „{{devicename}}“, добавете тук ново отдалечено устройство със следния идентификатор:",
"To permit a rule, have the checkbox checked. To deny a rule, leave it unchecked.": "За да разрешите дадено правило, поставете отметка в полето. За да забраните оставете полето без отметка.",
"Today": "Днес",
"Trash Can": "Кошче за отпадъци",
"Trash Can File Versioning": "Версии от вида „кошче за отпадъци“",
"Twitter": "Twitter",
"Type": "Вид",
"UNIX Permissions": "Права на UNIX",
"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",
"Unexpected Items": "Неочаквани елементи",
"Unexpected items have been found in this folder.": "В папката са намерени неочаквани елементи.",
"Unignore": "Отменяне на пренебрегване",
"Unknown": "Неясно",
"Unshared": "Несподелена",
"Unshared Devices": "Unshared Devices",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Unshared Devices": "Устройства, с които не е споделена",
"Unshared Folders": "Несподелени папки",
"Untrusted": "Недоверено",
"Up to Date": "Синхронизирано",
"Updated": "Обновено",
"Upgrade": "Обнови",
"Upgrade To {%version%}": "Обновен до {{version}}",
"Updated {%file%}": "{{file}} обновен",
"Upgrade": "Обновяване",
"Upgrade To {%version%}": "Обновяване до {{version}}",
"Upgrading": "Обновяване",
"Upload Rate": "Скорост на качване",
"Uptime": "Работи от",
"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": "Версия",
"Usage reporting is always enabled for candidate releases.": "Отчитането на употребата винаги е включено за предварителни издания.",
"Use HTTPS for GUI": "Графичният интерфейс работи под HTTPS",
"Use notifications from the filesystem to detect changed items.": "Използва съобщения от файловата система, за да открива променени елементи.",
"User Home": "Папка на потребителя",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "Потребителският интерфейс не е защитен с потребителско име и парола. Настройте защита.",
"Using a QUIC connection over LAN": "Използване на връзка чрез QUIC в LAN",
"Using a QUIC connection over WAN": "Използване на връзка чрез QUIC в WAN",
"Using a direct TCP connection over LAN": "Използване на директна свързаност с TCP през местна мрежа",
"Using a direct TCP connection over WAN": "Използване на директна свързаност с TCP през широкодостъпна мрежа",
"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",
"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": "Мониторинг за промени",
"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.": "Когато добавяте нов идентификатор на папка имайте предвид, че той се използва за свързване на папките между отделните устройства. Идентификатора разграничава главни/малки букви.",
"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 Scan": "Изчаква за обхождане",
"Waiting to Sync": "Изчаква за синхронизиране",
"Warning": "Внимание",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Внимание, този път е родителска папка съществуващата {{otherFolder}}.",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Внимание, този път е родителска папка съществуващата {{otherFolderLabel}} ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Внимание, този път е подпапка съществуващата „{{otherFolder}}.",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Внимание, този път е подпапка на съществуващата {{otherFolderLabel}} ({{otherFolder}}).",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Внимание: Ако използвате външно приложение за наблюдение като {{syncthingInotify}}, трябва да го спрете.",
"Watch for Changes": "Наблюдаване за промени",
"Watching for Changes": "Наблюдаване за промени",
"Watching for changes discovers most changes without periodic scanning.": "Наблюдението за промени открива повечето изменения без периодични обхождания.",
"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:": "Също така може да изберете едно от устройствата, които намират се наблизо:",
"Yesterday": "Вчера",
"You can also copy and paste the text into a new message manually.": "Също така можете ръчно да копирате и поставите текста в ново съобщение.",
"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 folders.": "Няма игнорирани папки.",
"You have unsaved changes. Do you really want to discard them?": "Има незапазени промени. Наистина ли желаете да ги отмените?",
"You must keep at least one version.": "Трябва да пазиш поне една версия.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "You should never add or change anything locally in a \"{{receiveEncrypted}}\" folder.",
"You can read more about the two release channels at the link below.": "Може да научите повече за двата канала на издание, следвайки препратката по-долу.",
"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.": "Никога не трябва да променяте нищо в папка от вида „{{receiveEncrypted}}.",
"Your SMS app should open to let you choose the recipient and send it from your own number.": "Приложението за SMS би трябвало да се отвори, да ви даде възможност да изберете получател, за да изпратите съобщението от вашия телефонен номер.",
"Your email app should open to let you choose the recipient and send it from your own address.": "Пощенският клиент би трябвало да се отвори, да ви даде възможност да изберете получател, за да изпратите съобщението от вашия адрес за електронна поща.",
"days": "дни",
"directories": "директории",
"deleted": "премахнато",
"deny": "отказ",
"directories": "папки",
"file": "файл",
"files": "файла",
"folder": "папка",
"full documentation": "пълна документация",
"items": "елемента",
"seconds": "seconds",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} желае да сподели папката \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} желае да сподели папката \"{{folderlabel}}\" ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} might reintroduce this device."
}
"modified": "променено",
"permit": "разрешаване",
"seconds": "секунди",
"theme-name-black": "Черна",
"theme-name-dark": "Тъмна",
"theme-name-default": "По подразбиране",
"theme-name-light": "Светла",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} споделя папката „{{folder}}“.",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} споделя папката „{{folderlabel}}“ ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "Поръчителят {{reintroducer}} може отново да предложи това устройство."
}

View File

@@ -0,0 +1,529 @@
{
"A device with that ID is already added.": "Ja s'ha afegit un dispositiu amb aquesta ID.",
"A negative number of days doesn't make sense.": "Un nombre negatiu de dies no té sentit.",
"A new major version may not be compatible with previous versions.": "Una nova versió major pot ser incompatible amb versions anteriors.",
"API Key": "Clau API",
"About": "Quant a",
"Action": "Acció",
"Actions": "Accions",
"Active filter rules": "Regles de filtre actiu",
"Add": "Afegeix",
"Add Device": "Afegeix un dispositiu",
"Add Folder": "Afegeix carpeta",
"Add Remote Device": "Afegeix dispositiu remot",
"Add devices from the introducer to our device list, for mutually shared folders.": "Afegiu dispositius de l'introductor a la nostra llista de dispositius, per a carpetes compartides mútuament.",
"Add filter entry": "Afegeix una entrada de filtre",
"Add ignore patterns": "Afegiu patrons per ignorar",
"Add new folder?": "Vols afegir una carpeta nova?",
"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.": "A més, s'augmentarà l'interval de reexploració complet (vegades 60, és a dir, el nou predeterminat d'1 h). També podeu configurar-lo manualment per a cada carpeta més tard després de triar No.",
"Address": "Adreça",
"Addresses": "Adreces",
"Advanced": "Avançat",
"Advanced Configuration": "Configuració Avançada",
"All Data": "Totes les dades",
"All Time": "Tot el temps",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Totes les carpetes compartides amb aquest dispositiu han d'estar protegides amb una contrasenya, de manera que totes les dades enviades no es puguin llegir sense la contrasenya proporcionada.",
"Allow Anonymous Usage Reporting?": "Permetre l'enviament anònim d'informes d'ús?",
"Allowed Networks": "Xarxes permeses",
"Alphabetic": "Alfabètic",
"Altered by ignoring deletes.": "S'ha alterat ignorant les supressions.",
"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.": "Una ordre externa gestiona la versió. Ha d'eliminar el fitxer de la carpeta compartida. Si el camí a l'aplicació conté espais, s'ha de citar.",
"Anonymous Usage Reporting": "Informe anònim d'ús",
"Anonymous usage report format has changed. Would you like to move to the new format?": "El format de l'informe d'ús anònim ha canviat. Vols canviar a aquest nou format?",
"Apply": "Aplica",
"Are you sure you want to override all remote changes?": "Esteu segur que voleu anul·lar tots els canvis remots?",
"Are you sure you want to permanently delete all these files?": "Estàs segur que vols esborrar tots aquests fitxers permanentment?",
"Are you sure you want to remove device {%name%}?": "Estàs segur que vols esborrar el dispositiu {{name}}?",
"Are you sure you want to remove folder {%label%}?": "Estàs segur que vols esborrar la carpeta {{label}}?",
"Are you sure you want to restore {%count%} files?": "Estàs segur que vols restaurar {{count}} fitxers?",
"Are you sure you want to revert all local changes?": "Esteu segur que voleu revertir tots els canvis locals?",
"Are you sure you want to upgrade?": "Esteu segur que voleu actualitzar?",
"Authors": "Autors",
"Auto Accept": "Auto Acceptar",
"Automatic Crash Reporting": "Informe automàtic d'incidències",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "L'actualització automàtica permet escollir entre les versions estables i les versions candidates.",
"Automatic upgrades": "Actualitzacions automàtiques",
"Automatic upgrades are always enabled for candidate releases.": "Les actualitzacions automàtiques sempre estan habilitades per a les versions candidates.",
"Automatically create or share folders that this device advertises at the default path.": "Creeu o compartiu automàticament les carpetes que aquest dispositiu anuncia al camí predeterminat.",
"Available debug logging facilities:": "Recursos disponibles per registrar la depuració:",
"Be careful!": "Ves amb compte!",
"Body:": "Cos de text:",
"Bugs": "Errors (Bugs)",
"Cancel": "Cancel·la",
"Changelog": "Historial de canvis",
"Clean out after": "Netejar després",
"Cleaning Versions": "Netejant versions",
"Cleanup Interval": "Interval de neteja",
"Click to see full identification string and QR code.": "Feu clic per veure la cadena d'identificació completa i el codi QR.",
"Close": "Tancar",
"Command": "Comando",
"Comment, when used at the start of a line": "Comentari quan és usat al principi d'una línia",
"Compression": "Compressió",
"Configuration Directory": "Directori de configuració",
"Configuration File": "Fitxer de configuració",
"Configured": "Configurat",
"Connected (Unused)": "Connectat (no utilitzat)",
"Connection Error": "Error de connexió",
"Connection Type": "Tipus de connexió",
"Connections": "Connexions",
"Connections via relays might be rate limited by the relay": "Les connexions mitjançant relés poden estar limitades pel relé",
"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.": "La vigilància contínua dels canvis ara està disponible a Syncthing. Això detectarà els canvis al disc i emetrà una exploració només als camins modificats. Els avantatges són que els canvis es propaguen més ràpidament i que es requereixen menys exploracions completes.",
"Copied from elsewhere": "Copiat d'un altre lloc",
"Copied from original": "Copiat de l'original",
"Copied!": "Copiat!",
"Copy": "Copia",
"Copy failed! Try to select and copy manually.": "La còpia ha fallat! Intenta seleccionar i copiar manualment.",
"Currently Shared With Devices": "Actualment compartit amb dispositius",
"Custom Range": "Interval personalitzat",
"Danger!": "Perill!",
"Database Location": "Ubicació de la base de dades",
"Debugging Facilities": "Utilitats de Depuració",
"Default": "Per defecte",
"Default Configuration": "Configuració predeterminada",
"Default Device": "Dispositiu predeterminat",
"Default Folder": "Carpeta per defecte",
"Default Ignore Patterns": "Ignora els patrons per defecte",
"Defaults": "Per defecte",
"Delete": "Esborrar",
"Delete Unexpected Items": "Suprimeix els elements inesperats",
"Deleted {%file%}": "S'ha suprimit {{file}}",
"Deselect All": "Deselecciona tot",
"Deselect devices to stop sharing this folder with.": "Desseleccioneu els dispositius amb els quals deixar de compartir aquesta carpeta.",
"Deselect folders to stop sharing with this device.": "Desseleccioneu les carpetes per deixar de compartir-les amb aquest dispositiu.",
"Device": "Dispositiu",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "El dispositiu \"{{name}}\" ({{device}} a {{address}}) vol connectar-se. Vols afegir un dispositiu nou?",
"Device Certificate": "Certificat del dispositiu",
"Device ID": "ID del dispositiu",
"Device Identification": "Identificació del dispositiu",
"Device Name": "Nom del dispositiu",
"Device is untrusted, enter encryption password": "El dispositiu no és de confiança, introduïu la contrasenya d'encriptació",
"Device rate limits": "Límits de velocitat del dispositiu",
"Device that last modified the item": "Dispositiu que ha modificat el fitxer per última vegada",
"Devices": "Dispositius",
"Disable Crash Reporting": "Desactiva els informes d'error",
"Disabled": "Deshabilitat",
"Disabled periodic scanning and disabled watching for changes": "S'ha desactivat l'exploració periòdica i la vigilància dels canvis",
"Disabled periodic scanning and enabled watching for changes": "S'ha desactivat l'exploració periòdica i s'ha activat la vigilància dels canvis",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "S'ha desactivat l'exploració periòdica i s'ha produït un error en configurar l'observació dels canvis, tornant-ho a provar cada 1 minut:",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Desactiva la comparació i la sincronització de permisos de fitxers. Útil en sistemes amb permisos inexistents o personalitzats (per exemple, FAT, exFAT, Synology, Android).",
"Discard": "Descarta",
"Disconnected": "Desconnectat",
"Disconnected (Inactive)": "Desconnectat (inactiu)",
"Disconnected (Unused)": "Desconnectat (no utilitzat)",
"Discovered": "Descobert",
"Discovery": "Descobriment",
"Discovery Failures": "Falles de descobriment",
"Discovery Status": "Estat de descoberta",
"Dismiss": "Descarta",
"Do not add it to the ignore list, so this notification may recur.": "No l'afegiu a la llista d'ignorar, de manera que aquesta notificació pot repetir-se.",
"Do not restore": "No restaurar",
"Do not restore all": "No restaurar-ho tot",
"Do you want to enable watching for changes for all your folders?": "Vols activar la cerca de canvis a totes les teves carpetes?",
"Documentation": "Documentació",
"Download Rate": "Tasca de descarrega",
"Downloaded": "Descarregat",
"Downloading": "Descarregant",
"Edit": "Editar",
"Edit Device": "Editar dispositiu",
"Edit Device Defaults": "Edita els valors predeterminats del dispositiu",
"Edit Folder": "Modificar carpeta",
"Edit Folder Defaults": "Edita els valors per defecte de la carpeta",
"Editing {%path%}.": "S'està editant {{path}}.",
"Enable Crash Reporting": "Activa els informes d'error",
"Enable NAT traversal": "Habilita NAT transversal",
"Enable Relaying": "Activa la retransmissió",
"Enabled": "Habilitat",
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "Permet enviar atributs ampliats a altres dispositius i aplicar atributs ampliats entrants. Pot requerir l'execució amb privilegis elevats.",
"Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when \"Sync Extended Attributes\" is enabled.": "Permet enviar atributs ampliats a altres dispositius, però no aplicar els atributs ampliats entrants. Això pot tenir un impacte significatiu en el rendiment. Sempre activat quan \"Sincronitza els atributs ampliats\" està habilitat.",
"Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.": "Permet enviar informació de propietat a altres dispositius i aplicar la informació de propietat entrant. Normalment requereix córrer amb privilegis elevats.",
"Enables sending ownership information to other devices, but not applying incoming ownership information. This can have a significant performance impact. Always enabled when \"Sync Ownership\" is enabled.": "Permet enviar informació de propietat a altres dispositius, però no aplicar la informació de propietat entrant. Això pot tenir un impacte significatiu en el rendiment. Sempre activat quan la \"Propietat de sincronització\" està activada.",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Introduïu un nombre no negatiu (per exemple \"2,35\") i seleccioneu una unitat. Els percentatges formen part de la mida total del disc.",
"Enter a non-privileged port number (1024 - 65535).": "Introduïu un número de port no privilegiat (1024 - 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduïu adreces separades per comes (\"tcp://ip:port\", \"tcp://host:port\") o \"dinàmiques\" per fer la descoberta automàtica de l'adreça.",
"Enter ignore patterns, one per line.": "Introduex patrons a ignorar, un per línia.",
"Enter up to three octal digits.": "Introduïu fins a tres dígits octals.",
"Error": "Error",
"Extended Attributes": "Atributs ampliats",
"Extended Attributes Filter": "Filtre d'atributs estès",
"External": "Extern",
"External File Versioning": "Versionat de fitxers extern",
"Failed Items": "Elements fallats",
"Failed to load file versions.": "No s'han pogut carregar les versions dels fitxers.",
"Failed to load ignore patterns.": "No s'han pogut carregar els patrons ignorats.",
"Failed to setup, retrying": "No s'ha pogut configurar, s'està tornant a provar",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "S'espera que no es pugui connectar als servidors IPv6 si no hi ha connectivitat IPv6.",
"File Pull Order": "Ordre d'agafar fitxers",
"File Versioning": "Versionat de Fitxers",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Els fitxers es mouen al directori .stversions quan se substitueixen o se suprimeixen mitjançant Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Els fitxers es mouen a versions amb segell de data en un directori .stversions quan Syncthing se substitueix o se suprimeix.",
"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 estan protegits de canvis fets per altres dispositius, però els canvis fets en aquest dispositiu seran enviats a la resta del cluster.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Els fitxers se sincronitzen des del clúster, però els canvis fets localment no s'enviaran a altres dispositius.",
"Filesystem Watcher Errors": "Errors de l'observador del sistema de fitxers",
"Filter by date": "Filtrar per data",
"Filter by name": "Filtrar per nom",
"Folder": "Carpeta",
"Folder ID": "ID de carpeta",
"Folder Label": "Etiqueta de la carpeta",
"Folder Path": "Camí de carpeta",
"Folder Type": "Tipus de carpeta",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "El tipus de carpeta \"{{receiveEncrypted}}\" només es pot definir quan s'afegeix una carpeta nova.",
"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.": "El tipus de carpeta \"{{receiveEncrypted}}\" no es pot canviar després d'afegir la carpeta. Heu d'eliminar la carpeta, suprimir o desxifrar les dades del disc i tornar a afegir la carpeta.",
"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.": "A les carpetes següents s'ha produït un error en començar a buscar canvis. Es tornarà a provar cada minut, de manera que els errors poden desaparèixer aviat. Si persisteixen, intenteu solucionar el problema subjacent i demaneu ajuda si no podeu.",
"Forever": "Per sempre",
"Full Rescan Interval (s)": "Interval(s) de reexploració completa",
"GUI": "GUI (Interfície Gràfica d'Usuari)",
"GUI / API HTTPS Certificate": "Certificat HTTPS GUI / API",
"GUI Authentication Password": "Contrasenya d'autenticació GUI",
"GUI Authentication User": "Usuari d'autenticació GUI",
"GUI Authentication: Set User and Password": "Autenticació de la GUI: defineix l'usuari i la contrasenya",
"GUI Listen Address": "Adreça d'escolta de la GUI",
"GUI Override Directory": "Directori de substitució de la GUI",
"GUI Theme": "Tema de la GUI",
"General": "General",
"Generate": "Generar",
"Global Discovery": "Descobriment Global",
"Global Discovery Servers": "Servidors de Descobriment Global",
"Global State": "Estat global",
"Help": "Ajuda",
"Hint: only deny-rules detected while the default is deny. Consider adding \"permit any\" as last rule.": "Suggeriment: només s'han detectat regles de denegació mentre el valor predeterminat és denegació. Penseu a afegir \"permet qualsevol\" com a darrera regla.",
"Home page": "Pàgina d'inici",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Tanmateix, la vostra configuració actual indica que potser no voleu que estigui activada. Hem desactivat l'informe automàtic d'errors.",
"Identification": "Identificació",
"If untrusted, enter encryption password": "Si no és de confiança, introduïu la contrasenya de xifratge",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Si voleu evitar que altres usuaris d'aquest ordinador accedeixin a Syncthing i a través d'ell els vostres fitxers, penseu a configurar l'autenticació.",
"Ignore": "Ignorar",
"Ignore Patterns": "Patrons d'ignoració",
"Ignore Permissions": "Ignora Permisos",
"Ignore patterns can only be added after the folder is created. If checked, an input field to enter ignore patterns will be presented after saving.": "Els patrons per ignorar només es poden afegir després de crear la carpeta. Si està marcat, un camp d'entrada per introduir patrons d'ignorar es presentarà després de desar.",
"Ignored Devices": "Dispositius ignorats",
"Ignored Folders": "Carpetes ignorades",
"Ignored at": "Ignorat a",
"Included Software": "Programari inclòs",
"Incoming Rate Limit (KiB/s)": "Límit de velocitat d'entrada (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Una configuració incorrecta pot malmetre els continguts de la teva carpeta i que Syncthing esdevingui inoperatiu.",
"Internally used paths:": "Camins utilitzats internament:",
"Introduced By": "Introduït per",
"Introducer": "Introductor",
"Inversion of the given condition (i.e. do not exclude)": "Inversió del patrò introduït",
"Keep Versions": "Mantenir Versions",
"LDAP": "LDAP",
"Largest First": "Més gran primer",
"Last 30 Days": "Últims 30 dies",
"Last 7 Days": "Últims 7 dies",
"Last Month": "Últim mes",
"Last Scan": "Últim escaneig",
"Last seen": "Vist per última vegada",
"Latest Change": "Últim canvi",
"Learn more": "Aprèn més",
"Learn more at {%url%}": "Més informació a {{url}}",
"Limit": "Límit",
"Listener Failures": "Errors en l'escolta",
"Listener Status": "Estat de l'oient",
"Listeners": "Oients",
"Loading data...": "Carregant dades...",
"Loading...": "Carregant...",
"Local Additions": "Addicions locals",
"Local Discovery": "Descobriment Local",
"Local State": "Estat local",
"Local State (Total)": "Estat local (Total)",
"Locally Changed Items": "Elements canviats localment",
"Log": "Registre",
"Log File": "Fitxer de registre",
"Log tailing paused. Scroll to the bottom to continue.": "S'ha posat en pausa el seguiment del registre. Desplaceu-vos cap a la part inferior per continuar.",
"Logs": "Registres",
"Major Upgrade": "Actualització major",
"Mass actions": "Accions massives",
"Maximum Age": "Antiguitat Màxima",
"Maximum single entry size": "Mida màxima d'entrada única",
"Maximum total size": "Mida total màxima",
"Metadata Only": "Només metadades",
"Minimum Free Disk Space": "Espai de disc lliure mínim",
"Mod. Device": "Mod. Dispositiu",
"Mod. Time": "Mod. Data",
"More than a month ago": "Fa més d'un mes",
"More than a week ago": "Fa més d'una setmana",
"More than a year ago": "Fa més d'un any",
"Move to top of queue": "Moure al primer de la cua",
"Multi level wildcard (matches multiple directory levels)": "Caràcter comodí de nivell múltiple (aparella en carpetes de nivells múltiples)",
"Never": "Mai",
"New Device": "Nou dispositiu",
"New Folder": "Nova carpeta",
"Newest First": "Més nou primer",
"No": "No",
"No File Versioning": "Sense Versionat de Fitxer",
"No files will be deleted as a result of this operation.": "No se suprimirà cap fitxer com a resultat d'aquesta operació.",
"No rules set": "No hi ha regles establertes",
"No upgrades": "No hi ha actualitzacions",
"Not shared": "No compartit",
"Notice": "Avís",
"OK": "D'acord",
"Off": "Desactivar",
"Oldest First": "Més antic primer",
"Optional descriptive label for the folder. Can be different on each device.": "Etiqueta descriptiva opcional per a la carpeta. Pot ser diferent a cada dispositiu.",
"Options": "Opcions",
"Out of Sync": "Fora de sincronia",
"Out of Sync Items": "Arxius encara no sincronitzats",
"Outgoing Rate Limit (KiB/s)": "Límit de velocitat de sortida (KiB/s)",
"Override": "Sobreescriu",
"Override Changes": "Sobreescriure Canvis",
"Ownership": "Propietat",
"Path": "Ruta",
"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 de la carpeta a l'equip local. Si no existeix serà creada. El caràcter (~) es pot fer servir com a drecera de",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Ruta on s'han d'emmagatzemar les versions (deixeu buit per al directori predeterminat .stversions a la carpeta compartida).",
"Paths": "Rutes",
"Pause": "Pausa",
"Pause All": "Posa-ho tot en pausa",
"Paused": "Pausat",
"Paused (Unused)": "En pausa (no utilitzat)",
"Pending changes": "Canvis pendents",
"Periodic scanning at given interval and disabled watching for changes": "Escaneig periòdic a un interval determinat i vigilància desactivada dels canvis",
"Periodic scanning at given interval and enabled watching for changes": "Escaneig periòdic a un interval determinat i vigilància activada dels canvis",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "L'escaneig periòdic determinat a un interval ha fallat i no s'ha pogut configurar l'observació dels canvis, tornant-ho a provar cada 1 minut:",
"Permanently add it to the ignore list, suppressing further notifications.": "Afegeix-lo permanentment a la llista d'ignorar, suprimint més notificacions.",
"Please consult the release notes before performing a major upgrade.": "Si us plau consulta les notes de llançament abans de realitzar una actualització major.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Si us plau, estableix un usuari i contrasenya al GUI a través del quadre de diàleg de configuració.",
"Please wait": "Si-us-plau espera",
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefix que indica que el fitxer es pot suprimir si s'impedeix l'eliminació del directori",
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefix que indica que el patró s'ha de fer coincidir sense distinció de majúscules i minúscules",
"Preparing to Sync": "S'està preparant per a la sincronització",
"Preview": "Vista prèvia",
"Preview Usage Report": "Vista Prèvia de l'Informe d'Ús",
"QR code": "Codi QR",
"QUIC LAN": "Connexió QUIC LAN",
"QUIC WAN": "Connexió QUIC WAN",
"QUIC connections are in most cases considered suboptimal": "En la majoria dels casos, les connexions QUIC es consideren subòptimes",
"Quick guide to supported patterns": "Guia ràpida per als possibles patrons",
"Random": "Aleatori",
"Receive Encrypted": "Rebre xifrat",
"Receive Only": "Només rebre",
"Received data is already encrypted": "Les dades rebudes ja estan xifrades",
"Recent Changes": "Canvis recents",
"Reduced by ignore patterns": "Reduït per ignorar patrons",
"Relay LAN": "Relé LAN",
"Relay WAN": "Relé WAN",
"Release Notes": "Notes de llançament",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Els candidats a la versió final contenen les últimes funcions i correccions. Són similars a les versions tradicionals de Syncthing quinzenals.",
"Remote Devices": "Dispositius remots",
"Remote GUI": "GUI remota",
"Remove": "Esborrar",
"Remove Device": "Elimina el dispositiu",
"Remove Folder": "Elimina la carpeta",
"Required identifier for the folder. Must be the same on all cluster devices.": "Identificador obligatori per a la carpeta. Ha de ser el mateix en tots els dispositius del clúster.",
"Rescan": "Re-escanejar",
"Rescan All": "Re-escanejar tot",
"Rescans": "Escaneja de nou",
"Restart": "Reiniciar",
"Restart Needed": "És Necessari Reiniciar",
"Restarting": "Reiniciant",
"Restore": "Restaura",
"Restore Versions": "Restaura versions",
"Resume": "Reprendre",
"Resume All": "Reprèn tot",
"Reused": "Reutilitzat",
"Revert": "Reverteix",
"Revert Local Changes": "Reverteix els canvis locals",
"Save": "Guardar",
"Scan Time Remaining": "Temps d'escanejat restant",
"Scanning": "Escanejant",
"See external versioning help for supported templated command line parameters.": "Consulteu l'ajuda de versions externa per als paràmetres de línia d'ordres de plantilla compatibles.",
"Select All": "Selecciona tot",
"Select a version": "Seleccioneu una versió",
"Select additional devices to share this folder with.": "Seleccioneu dispositius addicionals amb els quals compartir aquesta carpeta.",
"Select additional folders to share with this device.": "Seleccioneu carpetes addicionals per compartir amb aquest dispositiu.",
"Select latest version": "Seleccioneu la darrera versió",
"Select oldest version": "Seleccioneu la versió més antiga",
"Send & Receive": "Enviar i rebre",
"Send Extended Attributes": "Envia atributs ampliats",
"Send Only": "Només enviar",
"Send Ownership": "Envia la propietat",
"Set Ignores on Added Folder": "Estableix filtres per ignorar a la carpeta afegida",
"Settings": "Preferències",
"Share": "Compartir",
"Share Folder": "Compartir carpeta",
"Share by Email": "Comparteix per correu electrònic",
"Share by SMS": "Comparteix per SMS",
"Share this folder?": "Compartir aquesta carpeta?",
"Shared Folders": "Carpetes compartides",
"Shared With": "Compartir Amb",
"Sharing": "Compartint",
"Show ID": "Mostrar ID",
"Show QR": "Mostra QR",
"Show detailed discovery status": "Mostra l'estat detallat del descobriment",
"Show detailed listener status": "Mostra l'estat detallat de l'oient",
"Show diff with previous version": "Mostra la diferència amb la versió anterior",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrat en comptes del ID del Node en l'estat del cluster. Serà advertit als altres dispositius com un 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 comptes del ID del Node en l'estat del cluster. S'actualitzarà al nom del dispositiu si es deixa buit.",
"Shutdown": "Apagar",
"Shutdown Complete": "Apagat complet",
"Simple": "Simple",
"Simple File Versioning": "Versionat de Fitxers Senzill",
"Single level wildcard (matches within a directory only)": "Caràcter comodí de nivell singular (aparella sóls en una carpeta)",
"Size": "Mida",
"Smallest First": "Més petit primer",
"Some discovery methods could not be established for finding other devices or announcing this device:": "No s'han pogut establir alguns mètodes de descoberta per trobar altres dispositius o anunciar aquest dispositiu:",
"Some items could not be restored:": "Alguns elements no s'han pogut restaurar:",
"Some listening addresses could not be enabled to accept connections:": "Algunes adreces d'escolta no s'han pogut habilitar per acceptar connexions:",
"Source Code": "Codi Font",
"Stable releases and release candidates": "Alliberaments estables i candidats al llançament",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Els llançaments estables es retarden unes dues setmanes. Durant aquest temps passen per proves com a candidats al llançament.",
"Stable releases only": "Només versions estables",
"Staggered": "Esglaonat",
"Staggered File Versioning": "Versionat de Fitxers Esglaonat",
"Start Browser": "Arrancar Navegador",
"Statistics": "Estadístiques",
"Stopped": "Aturat",
"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.": "Emmagatzema i sincronitza només dades encriptades. Les carpetes de tots els dispositius connectats s'han de configurar amb la mateixa contrasenya o també ser del tipus \"{{receiveEncrypted}}\".",
"Subject:": "Assumpte:",
"Support": "Suport",
"Support Bundle": "Paquet de suport",
"Sync Extended Attributes": "Sincronitza els atributs ampliats",
"Sync Ownership": "Sincronitza la propietat",
"Sync Protocol Listen Addresses": "Adreça d'escolta del Protocol Sync",
"Sync Status": "Estat de sincronització",
"Syncing": "Synthing",
"Syncthing device ID for \"{%devicename%}\"": "ID del dispositiu Syncthing amb el nom \"{{devicename}}\"",
"Syncthing has been shut down.": "S'ha aturat el synthing.",
"Syncthing includes the following software or portions thereof:": "Syncthing inclou el següent programari o parts dels mateixos:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing és un programari lliure i de codi obert amb llicència MPL v2.0.",
"Syncthing is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it's transmitted over the internet.": "Syncthing és un programa de sincronització contínua de fitxers. Sincronitza fitxers entre dos o més ordinadors en temps real, protegit de manera segura de mirades indiscretes. Les vostres dades són només les vostres i mereixeu triar on s'emmagatzemen, si es comparteixen amb un tercer i com es transmeten per Internet.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "La sincronització està escoltant a les adreces de xarxa següents els intents de connexió des d'altres dispositius:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "La sincronització no és escoltar els intents de connexió d'altres dispositius a cap adreça. Només poden funcionar les connexions sortints d'aquest dispositiu.",
"Syncthing is restarting.": "Reiniciant syncthing.",
"Syncthing is upgrading.": "Actualitzant syncthing.",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing ara admet la notificació automàtica d'errors als desenvolupadors. Aquesta funció està activada per defecte.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Sembla que Syncthing no està funcionant o hi ha un problema amb la connexió a Internet. S'està tornant a provar…",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Sembla ser que Syncthing està tinguent problemes per processar la teva petició. Si us plau, refresca la pàgina o reinicia Syncthing si el problema persisteix.",
"TCP LAN": "Connexió TCP LAN",
"TCP WAN": "Connexió TCP WAN",
"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.": "Les opcions d'inici substitueixen l'adreça de la GUI. Els canvis aquí no tindran efecte mentre la substitució estigui vigent.",
"The Syncthing Authors": "Els autors de Syncthing",
"The Syncthing admin interface is configured to allow remote access without a password.": "La interfície d'administració de Syncthing està configurada per permetre l'accés remot sense contrasenya.",
"The aggregated statistics are publicly available at the URL below.": "Les estadístiques agregades estan disponibles públicament a l'URL següent.",
"The cleanup interval cannot be blank.": "L'interval de neteja no pot estar en blanc.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuració s'ha guardar però no s'ha activat. S'ha de reiniciar el synthing per activar la nova configuració.",
"The device ID cannot be blank.": "El ID del dispositiu no pot estar en blanc.",
"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'identificador del dispositiu que cal introduir aquí es pot trobar al diàleg \"Accions > Mostra l'ID\" de l'altre dispositiu. Els espais i els guions són 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 d'ús encriptat s'envia diàriament. Es fa servir per rastrejar plataformes habituals, mides de carpetes i versions de l'aplicació. Si es canvia el conjunt de dades reportades es demanarà amb aquest diàleg de nou.",
"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.": "El ID del dispositiu introduït no sembla vàlid. Hauria de tenir 52 o 56 caràcters amb lletres i números, els espais i les barres son opcionals.",
"The folder ID cannot be blank.": "El ID del dispositiu no pot estar en blanc.",
"The folder ID must be unique.": "El ID de la carpeta ha de ser únic.",
"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.": "El contingut de la carpeta d'altres dispositius se sobreescriurà per ser idèntic al d'aquest dispositiu. Els fitxers no presents aquí se suprimiran en altres dispositius.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "El contingut de la carpeta d'aquest dispositiu se sobreescriurà per ser idèntic al d'altres dispositius. Els fitxers recentment afegits aquí se suprimiran.",
"The folder path cannot be blank.": "El camí a la carpeta no pot estar en blanc.",
"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 fan servir els següents intervals: per la primera hora es manté una versió cada 30 segons, pel primer dia es manté una versió cada hora, pel primer cada 30 dies es manté una versió cada dia, fins el màxim d'antiguitat es manté una versió cada setmana.",
"The following items could not be synchronized.": "Els següents elements no es poden sincronitzar.",
"The following items were changed locally.": "Els elements següents s'han canviat localment.",
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "Els mètodes següents s'utilitzen per descobrir altres dispositius a la xarxa i anunciar que aquest dispositiu serà trobat per altres:",
"The following text will automatically be inserted into a new message.": "El text següent s'inserirà automàticament en un missatge nou.",
"The following unexpected items were found.": "S'han trobat els següents elements inesperats.",
"The interval must be a positive number of seconds.": "L'interval ha de ser un nombre positiu de segons.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "L'interval, en segons, per executar la neteja al directori de versions. Zero per desactivar la neteja periòdica.",
"The maximum age must be a number and cannot be blank.": "La màxima antiguitat ha de ser un número i no pot estar en blanc.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Temps màxim en mantenir una versió (en dies, si es deixa en 0 es mantenen les versions per sempre).",
"The number of days must be a number and cannot be blank.": "El nombre de dies ha de ser un número 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 guardar els fitxers a la paperera. Zero significa per sempre.",
"The number of old versions to keep, per file.": "El nombre de versions antigues que es mantenen per fitxer.",
"The number of versions must be a number and cannot be blank.": "El nombre de versions ha de ser un número i no es pot deixar en blanc.",
"The path cannot be blank.": "El camí no pot estar en blanc.",
"The rate limit must be a non-negative number (0: no limit)": "El límit de velocitat ha de ser un nombre positiu (0: sense límit)",
"The remote device has not accepted sharing this folder.": "El dispositiu remot no ha acceptat compartir aquesta carpeta.",
"The remote device has paused this folder.": "El dispositiu remot ha posat en pausa aquesta carpeta.",
"The rescan interval must be a non-negative number of seconds.": "El interval de re-escaneig ha der ser un nombre positiu de segons.",
"There are no devices to share this folder with.": "No hi ha cap dispositiu per compartir aquesta carpeta.",
"There are no file versions to restore.": "No hi ha versions de fitxers per restaurar.",
"There are no folders to share with this device.": "No hi ha carpetes que es puguin compartir amb aquest dispositiu",
"They are retried automatically and will be synced when the error is resolved.": "Són reintentats automàticament i seran sincronitzats quan l'error estigui resolt.",
"This Device": "Aquest dispositiu",
"This Month": "Aquest mes",
"This can easily give hackers access to read and change any files on your computer.": "Això pot donar facilment accés a hackers per llegir i canviar qualsevol fitxer del 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.": "Aquest dispositiu no pot detectar automàticament altres dispositius ni anunciar la seva pròpia adreça perquè altres puguin trobar. Només es poden connectar dispositius amb adreces configurades estàticament.",
"This is a major version upgrade.": "Aquesta és una actualització de versió major.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Aquesta configuració controla l'espai lliure necessari al disc d'inici (és a dir, la base de dades d'índex).",
"Time": "Temps",
"Time the item was last modified": "Hora de la darrera modificació de l'element",
"To connect with the Syncthing device named \"{%devicename%}\", add a new remote device on your end with this ID:": "Per connectar-vos amb el dispositiu de sincronització anomenat \"{{devicename}}\", afegiu un nou dispositiu remot amb aquest identificador:",
"To permit a rule, have the checkbox checked. To deny a rule, leave it unchecked.": "Per permetre una regla, marqueu la casella de selecció. Per denegar una regla, deixeu-la sense marcar.",
"Today": "Avui",
"Trash Can": "Paperera",
"Trash Can File Versioning": "Paperera de versionat de fitxers",
"Twitter": "Twitter",
"Type": "Tipus",
"UNIX Permissions": "Permisos UNIX",
"Unavailable": "No disponible",
"Unavailable/Disabled by administrator or maintainer": "No disponible/Desactivat per l'administrador o el responsable",
"Undecided (will prompt)": "No decidit (es preguntarà)",
"Unexpected Items": "Elements inesperats",
"Unexpected items have been found in this folder.": "S'han trobat elements inesperats en aquesta carpeta.",
"Unignore": "No ignorar",
"Unknown": "Desconegut",
"Unshared": "No compartit",
"Unshared Devices": "Dispositius no compartits",
"Unshared Folders": "Carpetes no compartides",
"Untrusted": "No fiable",
"Up to Date": "Actualitzat",
"Updated {%file%}": "S'ha actualitzat {{file}}",
"Upgrade": "Actualització",
"Upgrade To {%version%}": "Actualitzar a {{version}}",
"Upgrading": "Actualitzant",
"Upload Rate": "Tasca de Pujada",
"Uptime": "Temps funcionant",
"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 pel GUI",
"Use notifications from the filesystem to detect changed items.": "Utilitzeu les notificacions del sistema de fitxers per detectar elements canviats.",
"User Home": "Carpeta d'inici de l'usuari",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "El nom d'usuari/contrasenya no s'ha establert per a l'autenticació de la GUI. Penseu en configurar-lo.",
"Using a direct TCP connection over LAN": "Utilitzant una connexió TCP directa per LAN",
"Using a direct TCP connection over WAN": "Utilitzant una connexió TCP directa a través de WAN",
"Version": "Versió",
"Versions": "Versions",
"Versions Path": "Carpeta 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 son automàticament eliminades si son més antigues que el màxim d'antiguitat o si excedeixen del nombre de fitxers permesos en un interval.",
"Waiting to Clean": "Esperant per netejar",
"Waiting to Scan": "Esperant per escanejar",
"Waiting to Sync": "Esperant per sincronitzar",
"Warning": "Avís",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Advertència, aquest camí és un directori principal d'una carpeta existent \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advertència, aquest camí és un directori principal d'una carpeta existent \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Avís, aquest camí és un subdirectori d'una carpeta existent \"{{otherFolder}}\".",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advertència, aquest camí és un subdirectori d'una carpeta existent \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Avís: si feu servir un observador extern com {{syncthingInotify}}, hauríeu d'assegurar-vos que estigui desactivat.",
"Watch for Changes": "Vigilar els Canvis",
"Watching for Changes": "Vigilant els Canvis",
"Watching for changes discovers most changes without periodic scanning.": "Observant els canvis descobreix la majoria dels canvis sense escanejar periòdicament.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Quan s'afegeix un nou dispositiu, recorda que aquest dispositiu tambè s'ha d'afegir a l'altre banda.",
"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.": "Quan s'afegeix una nova carpeta recorda que el ID d'aquesta s'utilitza per lligar repositoris entre els dispositius. Es distingeix entre majúscules i minúscules i ha de ser exactament iguals entre tots els dispositius.",
"Yes": "Si",
"Yesterday": "Ahir",
"You can also copy and paste the text into a new message manually.": "També podeu copiar i enganxar el text en un missatge nou manualment.",
"You can also select one of these nearby devices:": "També pots escollir un d'aquests dispositius pròxims:",
"You can change your choice at any time in the Settings dialog.": "Pots canviar la teva elecció en qualsevol moment al quadre de preferències.",
"You can read more about the two release channels at the link below.": "Podeu llegir més sobre els dos canals de llançament a l'enllaç següent.",
"You have no ignored devices.": "No teniu cap dispositiu ignorat.",
"You have no ignored folders.": "No tens carpetes compartides.",
"You have unsaved changes. Do you really want to discard them?": "Tens canvis no desats. Realment les voleu descartar?",
"You must keep at least one version.": "Has de mantenir com a mínim una versió.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Mai no hauríeu d'afegir ni canviar res localment a una carpeta \"{{receiveEncrypted}}\".",
"Your SMS app should open to let you choose the recipient and send it from your own number.": "La vostra aplicació SMS s'hauria d'obrir per permetre't triar el destinatari i enviar-lo des del teu propi número.",
"Your email app should open to let you choose the recipient and send it from your own address.": "La vostra aplicació de correu electrònic s'hauria d'obrir per permetre-vos triar el destinatari i enviar-lo des de la vostra adreça.",
"days": "dies",
"deleted": "esborrat",
"deny": "denegar",
"directories": "directoris",
"file": "fitxer",
"files": "fitxers",
"folder": "carpeta",
"full documentation": "documentació sencera",
"items": "Elements",
"modified": "modificat",
"permit": "permís",
"seconds": "segons",
"theme-name-black": "Negre",
"theme-name-dark": "Fosc",
"theme-name-default": "Per defecte",
"theme-name-light": "Clar",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} vol compartir la carpeta \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} vol compartir la carpeta \"{{folderlabel}}\" ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} podria tornar a introduir aquest dispositiu."
}

View File

@@ -6,11 +6,14 @@
"About": "Sobre",
"Action": "Acció",
"Actions": "Accions",
"Active filter rules": "Regles de filtre actiu",
"Add": "Afegir",
"Add Device": "Afegir dispositiu",
"Add Folder": "Afegir carpeta",
"Add Remote Device": "Afegir Dispositiu Remot.",
"Add devices from the introducer to our device list, for mutually shared folders.": "Afegir dispositius des-de l'introductor a la nostra llista de dispositius, per a tindre carpetes compartides mútuament",
"Add Remote Device": "Afegeix un dispositiu remot",
"Add devices from the introducer to our device list, for mutually shared folders.": "Afegiu dispositius de l'introductor a la nostra llista de dispositius, per a carpetes compartides mútuament.",
"Add filter entry": "Afegeix una entrada de filtre",
"Add ignore patterns": "Afegir patrons a ignorar",
"Add new folder?": "Afegir nova carpeta?",
"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.": "Adicionalment s'augmentarà l'interval d'escaneig complet (times 60, per exemple, ficarà el nou temps per defecte a 1 hora). També pots configurar-ho manualment per a cada carpeta més tard elegint No.",
"Address": "Direcció",
@@ -18,81 +21,101 @@
"Advanced": "Avançat",
"Advanced Configuration": "Configuració avançada",
"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.",
"All Time": "Tot el temps",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Totes les carpetes en aquest dispositiu han de ser protegides per una contrasenya, de manera que tota la informació enviada siga il·legible sense la contrasenya indicada.",
"Allow Anonymous Usage Reporting?": "Permetre informes d'ús anònim?",
"Allowed Networks": "Xarxes permeses",
"Alphabetic": "Alfabètic",
"Altered by ignoring deletes.": "S'ha alterat ignorant les supressions.",
"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.",
"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?",
"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?",
"Apply": "Aplicar",
"Are you sure you want to override all remote changes?": "Estàs segur de que vols sobrescriure tots els canvis remots?",
"Are you sure you want to permanently delete all these files?": "Estàs segur de que vols esborrar tots aquests fitxers?",
"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?",
"Are you sure you want to upgrade?": "Are you sure you want to upgrade?",
"Are you sure you want to revert all local changes?": "Esteu segurs que voleu revertir tots els canvis locals?",
"Are you sure you want to upgrade?": "Estàs segur de que vols actualitzar?",
"Authors": "Autors",
"Auto Accept": "Auto Acceptar",
"Automatic Crash Reporting": "Automatic Crash Reporting",
"Automatic Crash Reporting": "Informe automàtic d'incidents",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "L'actualització automàtica ara ofereix l'elecció entre les versions estables i les versions candidates.",
"Automatic upgrades": "Actualitzacions automàtiques",
"Automatic upgrades are always enabled for candidate releases.": "Les actualitzacions automàtiques sempre estàn activades per a les versions candidates.",
"Automatically create or share folders that this device advertises at the default path.": "Crear o compartir automàticament les carpetes que aquest dispositiu anuncia en la ruta per defecte.",
"Available debug logging facilities:": "Hi han disponibles les següents utilitats per a depurar el registre:",
"Be careful!": "Tin precaució!",
"Body:": "Cos de text:",
"Bugs": "Errors (Bugs)",
"Cancel": "Cancel·lar",
"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",
"Cleaning Versions": "S'estan netejant les versions",
"Cleanup Interval": "Interval de netega",
"Click to see full identification string and QR code.": "Feu clic per veure la cadena d'identificació completa i el codi QR.",
"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ó",
"Configuration Directory": "Directori de configuració",
"Configuration File": "Fitxer de configuració",
"Configured": "Configurat",
"Connected (Unused)": "Connected (Unused)",
"Connected (Unused)": "Connectat (No utilitzat)",
"Connection Error": "Error de connexió",
"Connection Type": "Tipus de connexió",
"Connections": "Connexions",
"Connections via relays might be rate limited by the relay": "Les connexions mitjançant relés poden estar limitades pel relé",
"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-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",
"Copied!": "Copiat!",
"Copy": "Copiar",
"Copy failed! Try to select and copy manually.": "La còpia ha fallat! Intenta seleccionar i copiar manualment.",
"Currently Shared With Devices": "Actualment compartit amb dispositius",
"Custom Range": "Interval personalitzat",
"Danger!": "Perill!",
"Database Location": "Ubicació de la base de dades",
"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",
"Default": "Per defecte",
"Default Configuration": "Configuració per defecte",
"Default Device": "Dispositiu per Defecte",
"Default Folder": "Carpeta per Defecte",
"Default Ignore Patterns": "Patrons a ignorar per defecte",
"Defaults": "Predeterminats",
"Delete": "Esborrar",
"Delete Unexpected Items": "Esborrar Elements Inesperats",
"Deleted {%file%}": "Esborrat {{file}}",
"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.",
"Deselect devices to stop sharing this folder with.": "Desseleccioneu els dispositius amb els quals deixar de compartir aquesta carpeta.",
"Deselect folders to stop sharing with this device.": "Desseleccioneu les carpetes per deixar de compartir-les amb aquest dispositiu.",
"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 Certificate": "Certificat del 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 is untrusted, enter encryption password": "El dispositiu no és de confiança, introduïu la contrasenya d'encriptació",
"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",
"Disable Crash Reporting": "Disable Crash Reporting",
"Disable Crash Reporting": "Desactiva els informes d'error",
"Disabled": "Desactivat",
"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).",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Desactiva la comparació i sincronització dels permisos de fitxers. Útil en sistemes amb permisos personalitzats o no existents (p. ex. FAT, exFAT, Synology, Android).",
"Discard": "Descartar",
"Disconnected": "Desconnectat",
"Disconnected (Unused)": "Disconnected (Unused)",
"Disconnected (Inactive)": "Desconnectat (inactiu)",
"Disconnected (Unused)": "Desconnectat (No util·litzat)",
"Discovered": "Descobert",
"Discovery": "Descobriment",
"Discovery Failures": "Fallades al Descobriment",
"Discovery Status": "Estat de descoberta",
"Dismiss": "Descarta",
"Do not add it to the ignore list, so this notification may recur.": "No l'afegiu a la llista d'ignorar, de manera que aquesta notificació pot repetir-se.",
"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?",
@@ -102,22 +125,31 @@
"Downloading": "Descarregant",
"Edit": "Editar",
"Edit Device": "Editar Dispositiu",
"Edit Device Defaults": "Edit Device Defaults",
"Edit Device Defaults": "Edita els valors predeterminats del dispositiu",
"Edit Folder": "Editar Carpeta",
"Edit Folder Defaults": "Edit Folder Defaults",
"Edit Folder Defaults": "Edita els valors per defecte de la carpeta",
"Editing {%path%}.": "Editant {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable Crash Reporting": "Activa els informes d'error",
"Enable NAT traversal": "Permetre NAT transversal",
"Enable Relaying": "Permetre Transmissions",
"Enabled": "Activat",
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "Permet enviar atributs ampliats a altres dispositius i aplicar atributs ampliats entrants. Pot requerir l'execució amb privilegis elevats.",
"Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when \"Sync Extended Attributes\" is enabled.": "Permet enviar atributs ampliats a altres dispositius, però no aplicar els atributs ampliats entrants. Això pot tenir un impacte significatiu en el rendiment. Sempre activat quan \"Sincronitza els atributs ampliats\" està habilitat.",
"Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.": "Permet enviar informació de propietat a altres dispositius i aplicar la informació de propietat entrant. Normalment requereix córrer amb privilegis elevats.",
"Enables sending ownership information to other devices, but not applying incoming ownership information. This can have a significant performance impact. Always enabled when \"Sync Ownership\" is enabled.": "Permet enviar informació de propietat a altres dispositius, però no aplicar la informació de propietat entrant. Això pot tenir un impacte significatiu en el rendiment. Sempre activat quan està activat \"Propietat de sincronització\".",
"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.": "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.",
"Enter up to three octal digits.": "Introduïu fins a tres dígits octals.",
"Error": "Error",
"Extended Attributes": "Atributs ampliats",
"Extended Attributes Filter": "Filtre d'atributs estesos",
"External": "Extern",
"External File Versioning": "Versionat extern de fitxers",
"Failed Items": "Objectes fallits",
"Failed to load file versions.": "No s'han pogut carregar les versions dels fitxers.",
"Failed to load ignore patterns.": "No s'han pogut carregar els patrons ignorats.",
"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",
@@ -134,16 +166,19 @@
"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.",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "El tipus de carpeta \"{{receiveEncrypted}}\" només es pot definir quan s'afegeix una carpeta nova.",
"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.": "El tipus de carpeta \"{{receiveEncrypted}}\" no es pot canviar després d'afegir la carpeta. Heu d'eliminar la carpeta, suprimir o desxifrar les dades del disc i tornar a afegir la carpeta.",
"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.",
"Forever": "Per sempre",
"Full Rescan Interval (s)": "Interval de l'Escaneig Complet (segons)",
"GUI": "IGU (Interfície Gràfica d'Usuari)",
"GUI / API HTTPS Certificate": "Certificat HTTPS GUI / API",
"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 Authentication: Set User and Password": "Autenticació de la interfície gràfica d'usuari: defineix l'usuari i la contrasenya",
"GUI Listen Address": "Adreça d'escolta de la Interfície Gràfica d'Usuari (GUI)",
"GUI Override Directory": "Directori de substitució de la interfície gràfica d'usuari",
"GUI Theme": "Tema de l'Interfície Gràfica d'Usuari (GUI)",
"General": "General",
"Generate": "Generar",
@@ -151,47 +186,64 @@
"Global Discovery Servers": "Servidors de Descobriment Global",
"Global State": "Estat global",
"Help": "Ajuda",
"Hint: only deny-rules detected while the default is deny. Consider adding \"permit any\" as last rule.": "Suggeriment: només s'han detectat regles de denegació mentre el valor predeterminat és denegació. Penseu en afegir \"permet qualsevol\" com a darrera regla.",
"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.",
"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.",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "Tanmateix, la vostra configuració actual indica que potser no voleu que estigui activada. Hem desactivat l'informe automàtic d'errors.",
"Identification": "Identificació",
"If untrusted, enter encryption password": "Si no és de confiança, introduïu la contrasenya de xifratge",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "Si voleu evitar que altres usuaris d'aquest ordinador accedeixin a Syncthing i a través d'ell els vostres fitxers, penseu a configurar l'autenticació.",
"Ignore": "Ignorar",
"Ignore Patterns": "Patrons a ignorar",
"Ignore Permissions": "Permisos a ignorar",
"Ignore patterns can only be added after the folder is created. If checked, an input field to enter ignore patterns will be presented after saving.": "Els patrons d'ignorar només es poden afegir després de crear la carpeta. Si està marcat, un camp d'entrada per introduir patrons d'ignorar es presentarà després de desar.",
"Ignored Devices": "Dispositius Ignorats",
"Ignored Folders": "Carpetes Ignorades",
"Ignored at": "Ignorat en",
"Included Software": "Programari inclòs",
"Incoming Rate Limit (KiB/s)": "Límit de descàrrega (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "La configuración incorrecta pot danyar el contingut de la teua carpeta i deixar Syncthing inoperatiu.",
"Internally used paths:": "Rutes de fitxers usades internament:",
"Introduced By": "Introduït Per",
"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 30 Days": "Últims 30 dies",
"Last 7 Days": "Últims 7 dies",
"Last Month": "Últim mes",
"Last Scan": "Últim escaneig",
"Last seen": "Vist per última vegada",
"Latest Change": "Últim Canvi",
"Learn more": "Saber més",
"Learn more at {%url%}": "Més informació a {{url}}",
"Limit": "Límit",
"Listener Failures": "Errors en l'escolta",
"Listener Status": "Estatus en l'escolta",
"Listeners": "Escoltants",
"Loading data...": "Carregant dades...",
"Loading...": "Carregant...",
"Local Additions": "Local Additions",
"Local Additions": "Addicions locals",
"Local Discovery": "Descobriment local",
"Local State": "Estat local",
"Local State (Total)": "Estat Local (Total)",
"Locally Changed Items": "Dispositius Canviats Localment",
"Log": "Registre",
"Log File": "Fitxer de registre",
"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",
"Maximum Age": "Edat màxima",
"Maximum single entry size": "Mida màxima d'entrada única",
"Maximum total size": "Mida total màxima",
"Metadata Only": "Sols metadades",
"Minimum Free Disk Space": "Espai minim de disc lliure",
"Mod. Device": "Dispositiu Modificador",
"Mod. Time": "Temps de la Modificació",
"More than a month ago": "Fa més d'un mes",
"More than a week ago": "Fa més d'una setmana",
"More than a year ago": "Fa més d'un any",
"Move to top of queue": "Moure al principi de la cua",
"Multi level wildcard (matches multiple directory levels)": "Comodí multinivell (coincideix amb múltiples nivells de directoris)",
"Never": "Mai",
@@ -201,50 +253,59 @@
"No": "No",
"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 rules set": "No hi ha regles establertes",
"No upgrades": "Sense actualitzacions",
"Not shared": "Not shared",
"Not shared": "No compartit",
"Notice": "Avís",
"OK": "OK",
"Off": "Off",
"OK": "D'acord",
"Off": "Apagat",
"Oldest First": "El més vell primer",
"Optional descriptive label for the folder. Can be different on each device.": "Etiqueta descriptiva opcional per la carpeta. Pot ser diferent en cada dispositiu.",
"Options": "Opcions",
"Out of Sync": "Sense sincronització",
"Out of Sync Items": "Dispositius sense sincronitzar",
"Outgoing Rate Limit (KiB/s)": "Límit de pujada (KiB/s)",
"Override": "Sobreescriu",
"Override Changes": "Sobreescriure els canvis",
"Ownership": "Pertinença",
"Path": "Ruta",
"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).",
"Paths": "Rutes de fitxers",
"Pause": "Pausa",
"Pause All": "Pausa Tot",
"Paused": "Pausat",
"Paused (Unused)": "Paused (Unused)",
"Paused (Unused)": "Pausat (No util·litzat)",
"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:",
"Permissions": "Permisos",
"Permanently add it to the ignore list, suppressing further notifications.": "Afegeix-lo permanentment a la llista d'ignorar, suprimint més notificacions.",
"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.",
"Please wait": "Per favor, espere",
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefix que indica que el fitxer pot ser eliminat encara que estiga restringida l'eliminació del directori",
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefix que indica que el patró deu coincidir sense tindre en compte les majúscules",
"Preparing to Sync": "Preparing to Sync",
"Preparing to Sync": "S'està preparant per a la sincronització",
"Preview": "Vista prèvia",
"Preview Usage Report": "Informe d'ús de vista prèvia",
"QR code": "Codi QR",
"QUIC LAN": "Xarxa QUIC LAN",
"QUIC WAN": "Xarxa QUIC WAN",
"QUIC connections are in most cases considered suboptimal": "En la majoria dels casos, les connexions QUIC es consideren subòptimes",
"Quick guide to supported patterns": "Guía ràpida de patrons suportats",
"Random": "Aleatori",
"Receive Encrypted": "Receive Encrypted",
"Receive Encrypted": "Rebre xifrat",
"Receive Only": "Només rebre",
"Received data is already encrypted": "Received data is already encrypted",
"Received data is already encrypted": "Les dades rebudes ja estan xifrades",
"Recent Changes": "Canvis Recents",
"Reduced by ignore patterns": "Reduït ignorant patrons",
"Relay LAN": "LAN de relé",
"Relay WAN": "WAN de relé",
"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. ",
"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 correccions. Són semblants a les versions tradicionals bi setmanals de Syncthing.",
"Remote Devices": "Dispositius Remots",
"Remote GUI": "Remote GUI",
"Remote GUI": "Interfície Gràfica d'Usuari remota",
"Remove": "Eliminar",
"Remove Device": "Eliminar Dispositiu",
"Remove Folder": "Eliminar Carpeta",
@@ -260,6 +321,7 @@
"Resume": "Continuar",
"Resume All": "Continuar Tot",
"Reused": "Reutilitzat",
"Revert": "Revertir",
"Revert Local Changes": "Revertir els canvis locals",
"Save": "Gravar",
"Scan Time Remaining": "Temps d'escaneig restant",
@@ -267,76 +329,97 @@
"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 additional devices to share this folder with.": "Seleccioneu dispositius addicionals amb els quals compartiu aquesta carpeta.",
"Select additional folders to share with this device.": "Seleccioneu carpetes addicionals per compartir amb aquest dispositiu.",
"Select latest version": "Seleccionar l'última versió",
"Select oldest version": "Seleccionar la versió més antiga",
"Select the folders to share with this device.": "Selecciona les carpetes per a compartir amb aquest dispositiu.",
"Send & Receive": "Enviar i Rebre",
"Send Extended Attributes": "Enviar atributs ampliats",
"Send Only": "Enviar Solament",
"Send Ownership": "Envia pertinença",
"Set Ignores on Added Folder": "Estableix què ignorar a la carpeta afegida",
"Settings": "Ajustos",
"Share": "Compartir",
"Share Folder": "Compartir carpeta",
"Share Folders With Device": "Compartir carpetes amb el dispositiu",
"Share by Email": "Comparteix per correu electrònic",
"Share by SMS": "Comparteix per SMS",
"Share this folder?": "Compartir aquesta carpeta?",
"Shared Folders": "Shared Folders",
"Shared Folders": "Carpetes compartides",
"Shared With": "Compartit amb",
"Sharing": "Compartint",
"Show ID": "Mostrar ID",
"Show QR": "Mostrar QR",
"Show detailed discovery status": "Mostra l'estat detallat del descobriment",
"Show detailed listener status": "Mostra l'estat detallat de l'escolta",
"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.",
"Shutdown": "Apagar",
"Shutdown Complete": "Apagar completament",
"Simple": "Senzill",
"Simple File Versioning": "Versionat de fitxers senzill",
"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:": "No s'han pogut establir alguns mètodes de descoberta per trobar altres dispositius o anunciar aquest dispositiu:",
"Some items could not be restored:": "Alguns ítems no s'han pogut restaurar:",
"Some listening addresses could not be enabled to accept connections:": "Algunes adreces d'escolta no s'han pogut habilitar per acceptar connexions:",
"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.",
"Stable releases only": "Solament versions estables",
"Staggered": "Esglaonat",
"Staggered File Versioning": "Versionat de fitxers escalonat",
"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.",
"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.": "Emmagatzema i sincronitza només dades encriptades. Les carpetes de tots els dispositius connectats s'han de configurar amb la mateixa contrasenya o també ser del tipus \"{{receiveEncrypted}}\".",
"Subject:": "Assumpte:",
"Support": "Suport",
"Support Bundle": "Lot de Suport",
"Sync Extended Attributes": "Sincronitza els atributs ampliats",
"Sync Ownership": "Sincronitza la pertinença",
"Sync Protocol Listen Addresses": "Direccions d'escolta del protocol de sincronització",
"Sync Status": "Estat de sincronització",
"Syncing": "Sincronitzant",
"Syncthing has been shut down.": "Syncthing s'ha apagat",
"Syncthing device ID for \"{%devicename%}\"": "ID del dispositiu Syncthing amb el nom \"{{devicename}}\"",
"Syncthing has been shut down.": "Syncthing s'ha tancat.",
"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 a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it's transmitted over the internet.": "Syncthing és un programa de sincronització contínua de fitxers. Sincronitza fitxers entre dos o més ordinadors en temps real, protegit de manera segura de mirades indiscretes. Les vostres dades són només les vostres i mereixeu triar on s'emmagatzemen, si es comparteixen amb un tercer i com es transmeten per Internet.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "La sincronització està escoltant a les adreces de xarxa següents els intents de connexió des d'altres dispositius:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Syncthing no està escoltant els intents de connexió d'altres dispositius a cap adreça. Només poden funcionar les connexions sortints d'aquest dispositiu.",
"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.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing pareix apagat o hi ha un problema amb la connexió a Internet. Tornant a intentar...",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing ara admet la notificació automàtica d'errors als desenvolupadors. Aquesta funció està activada per defecte.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing sembla apagat o hi ha un problema amb la connexió a Internet. Tornant a intentar",
"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.",
"TCP LAN": "Connexió TCP LAN",
"TCP WAN": "Connexió TCP WAN",
"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 Authors": "Els autors de Syncthing",
"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 cleanup interval cannot be blank.": "L'interval de neteja no pot estar en blanc.",
"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 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 d'ús xifrat s'envia diàriament. S'utilitza per fer un seguiment de plataformes habituals, mides de carpetes i versions d'aplicacions. Si es canvia el conjunt de dades informat, se us demanarà de nou aquest diàleg.",
"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 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 content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "El contingut de la carpeta d'altres dispositius se sobreescriurà per ser idèntic al d'aquest dispositiu. Els fitxers no presents aquí se suprimiran en altres dispositius.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "El contingut de la carpeta d'aquest dispositiu se sobreescriurà per ser idèntic al d'altres dispositius. Els fitxers recentment afegits aquí se suprimiran.",
"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 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 following methods are used to discover other devices on the network and announce this device to be found by others:": "Els mètodes següents s'utilitzen per descobrir altres dispositius a la xarxa i anunciar que aquest dispositiu serà trobat per altres:",
"The following text will automatically be inserted into a new message.": "El text següent s'inserirà automàticament en un missatge nou.",
"The following unexpected items were found.": "S'han trobat els següents elements inesperats.",
"The interval must be a positive number of seconds.": "L'interval ha de ser un nombre positiu de segons.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "L'interval, en segons, per executar la neteja al directori de versions. Zero per desactivar la neteja periòdica.",
"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 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.",
@@ -345,32 +428,42 @@
"The number of versions must be a number and cannot be blank.": "El nombre de versions deu ser un nombre i no pot estar buit.",
"The path cannot be blank.": "La ruta no pot estar buida.",
"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 remote device has not accepted sharing this folder.": "El dispositiu remot no ha acceptat compartir aquesta carpeta.",
"The remote device has paused this folder.": "El dispositiu remot ha posat en pausa aquesta carpeta.",
"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.",
"There are no devices to share this folder with.": "No hi ha cap dispositiu per compartir aquesta carpeta.",
"There are no file versions to restore.": "No hi ha versions de fitxers per restaurar.",
"There are no folders to share with this device.": "No hi ha carpetes per compartir amb aquest dispositiu.",
"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 Month": "Aquest mes",
"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.": "Aquest dispositiu no pot detectar automàticament altres dispositius ni anunciar la seva pròpia adreça perquè altres puguin trobar. Només es poden connectar dispositius amb adreces configurades estàticament.",
"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",
"Time the item was last modified": "Hora a la que l'ítem fou modificat per última vegada",
"To connect with the Syncthing device named \"{%devicename%}\", add a new remote device on your end with this ID:": "Per connectar-vos amb el dispositiu Syncthing anomenat \"{{devicename}}\", afegiu un nou dispositiu remot amb aquest identificador:",
"To permit a rule, have the checkbox checked. To deny a rule, leave it unchecked.": "Per permetre una regla, marqueu la casella de selecció. Per denegar una regla, deixeu-la sense marcar.",
"Today": "Avui",
"Trash Can": "Paperera",
"Trash Can File Versioning": "Versionat d'arxius de la paperera",
"Twitter": "Twitter",
"Type": "Tipus",
"UNIX Permissions": "UNIX Permissions",
"UNIX Permissions": "Permisos UNIX",
"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.",
"Unexpected Items": "Elements inesperats",
"Unexpected items have been found in this folder.": "S'han trobat elements inesperats en aquesta carpeta.",
"Unignore": "Designorar",
"Unknown": "Desconegut",
"Unshared": "No compartit",
"Unshared Devices": "Unshared Devices",
"Unshared Folders": "Unshared Folders",
"Untrusted": "Untrusted",
"Unshared Devices": "Dispositius no compartits",
"Unshared Folders": "Carpetes no compartides",
"Untrusted": "No fiable",
"Up to Date": "Actualitzat",
"Updated": "Actualitzat",
"Updated {%file%}": "S'ha actualitzat {{file}}",
"Upgrade": "Actualitzar",
"Upgrade To {%version%}": "Actualitzar a {{version}}",
"Upgrading": "Actualitzant",
@@ -378,15 +471,19 @@
"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)",
"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.",
"Use notifications from the filesystem to detect changed items.": "Usar notificacions del sistema de fitxers per a detectar els ítems canviats.",
"User Home": "Carpeta d'inici de l'usuari",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "El nom d'usuari/contrasenya no s'ha establert per a l'autenticació de la interfície gràfica d'usuari. Penseu a configurar-ho.",
"Using a direct TCP connection over LAN": "Utilitzant una connexió TCP directa per LAN",
"Using a direct TCP connection over WAN": "Utilitzant una connexió TCP directa a través de WAN",
"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",
"Warning": "Warning",
"Waiting to Clean": "Esperant per netejar",
"Waiting to Scan": "Esperant per escanejar",
"Waiting to Sync": "Esperant per sincronitzar",
"Warning": "Advertència",
"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}}\".",
@@ -398,21 +495,35 @@
"When adding a new device, keep in mind that this device must be added on the other side too.": "Quant s'afig un nou dispositiu, hi ha que tindre en compte que aquest dispositiu deu ser afegit també en l'altre costat.",
"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.": "Quant s'afig una nova carpeta, hi ha que tindre en compte que l'ID de la carpeta s'utilitza per a juntar les carpetes entre dispositius. Són sensibles a les majúscules i deuen coincidir exactament entre tots els dispositius.",
"Yes": "Sí",
"Yesterday": "Ahir",
"You can also copy and paste the text into a new message manually.": "També podeu copiar i enganxar el text en un missatge nou manualment.",
"You can also select one of these nearby devices:": "Pots seleccionar també un d'aquestos dispositius propers:",
"You can change your choice at any time in the Settings dialog.": "Pots canviar la teua elecció en qualsevol moment en el dialog Ajustos",
"You can change your choice at any time in the Settings dialog.": "Podeu canviar la vostra elecció en qualsevol moment al diàleg Configuració.",
"You can read more about the two release channels at the link below.": "Pots llegir més sobre els dos canals de versions en l'enllaç de baix.",
"You have no ignored devices.": "No tens dispositius ignorats.",
"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.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Mai no hauríeu d'afegir ni canviar res localment en una carpeta \"{{receiveEncrypted}}\".",
"Your SMS app should open to let you choose the recipient and send it from your own number.": "La vostra aplicació SMS s'hauria d'obrir per permetre't triar el destinatari i enviar-lo des del teu propi número.",
"Your email app should open to let you choose the recipient and send it from your own address.": "La vostra aplicació de correu electrònic s'hauria d'obrir per permetre-vos triar el destinatari i enviar-lo des de la vostra adreça.",
"days": "dies",
"deleted": "esborrat",
"deny": "denegar",
"directories": "directoris",
"file": "fitxer",
"files": "arxius",
"folder": "carpeta",
"full documentation": "Documentació completa",
"items": "Elements",
"seconds": "seconds",
"modified": "modificat",
"permit": "permís",
"seconds": "segons",
"theme-name-black": "Negre",
"theme-name-dark": "Fosc",
"theme-name-default": "Per defecte",
"theme-name-light": "Clar",
"{%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}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} might reintroduce this device."
}
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} podria tornar a introduir aquest dispositiu."
}

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