Compare commits

...

212 Commits

Author SHA1 Message Date
Jakob Borg
ae0e56e98d Translation update 2014-11-03 22:11:54 -06:00
Jakob Borg
6efe521e44 Update goleveldb 2014-11-03 22:00:11 -06:00
Jakob Borg
bccd21ac14 Test case to pinpoint DB corruption (failing) 2014-11-03 21:58:22 -06:00
Jakob Borg
8449a65cdf Merge pull request #930 from AudriusButkevicius/avail
Only connected devices are available devices
2014-11-03 21:56:40 -06:00
Audrius Butkevicius
fc47562983 Only connected devices are available devices 2014-11-03 21:25:36 +00:00
Audrius Butkevicius
76900ae291 Fix and relax locking 2014-11-03 21:14:57 +00:00
Jakob Borg
ec55559ff1 Merge pull request #929 from AudriusButkevicius/temp
Do not delete temp files on error (fixes #849)
2014-11-03 13:05:16 -06:00
Audrius Butkevicius
3daa26e1f7 Allow setting rescan interval to 0 (fixes #856) 2014-11-01 23:53:27 +00:00
Audrius Butkevicius
9ea8b6f659 Do not delete temp files on error (fixes #849) 2014-11-01 23:33:49 +00:00
Audrius Butkevicius
387f2f0a94 Do not show self in shared with (fixes #915) 2014-11-01 23:10:39 +00:00
Jakob Borg
b0d95d02be Repair incorrect global entries at startup 2014-10-30 17:10:05 +01:00
Jakob Borg
3a98f01d31 Add insane levels of database debugging 2014-10-30 16:45:39 +01:00
Audrius Butkevicius
d305752749 Cleanup temporary files during directory removal (fixes #919) 2014-10-29 11:19:48 +00:00
Jakob Borg
2ba4b235fc Windows logfile should follow -home by default (fixes #918) 2014-10-28 20:52:28 +01:00
Jakob Borg
6820c0a5d7 Don't crash on nil discoverer (fixes #917) 2014-10-28 20:40:04 +01:00
Audrius Butkevicius
048883ad27 Remove extra tabs from SOAP payload (fixes #914) 2014-10-27 23:33:59 +00:00
Jakob Borg
08e7ada242 Translation update 2014-10-27 15:05:16 +01:00
Jakob Borg
d3ddfa31f7 Merge branch 'pr/909'
* pr/909:
  Add Vilbrekin
  Correctly check whether parent directory is writable for current user. "&04" was checking if file is readable by others, while "&0200" checks if it's writable for current user.
2014-10-26 13:59:09 +01:00
Jakob Borg
4b899a813e Add Vilbrekin 2014-10-26 13:59:03 +01:00
Jakob Borg
15ee9a5cac Break out logger as a reusable component 2014-10-26 13:16:54 +01:00
Audrius Butkevicius
58945a429f Revert removal of test files 2014-10-26 11:36:40 +00:00
Jakob Borg
9f4111015e Blame 2014-10-26 12:07:54 +01:00
Jakob Borg
04b960b415 Merge branch 'pr/903'
* pr/903:
  Ignore all paths within .stversions folder
2014-10-26 11:47:27 +01:00
Lode Hoste
33267f2178 Ignore all paths within .stversions folder 2014-10-26 11:47:02 +01:00
Vilbrekin
970e50d1f1 Correctly check whether parent directory is writable for current user.
"&04" was checking if file is readable by others, while "&0200" checks
if it's writable for current user.

(Fixes #904)
2014-10-26 02:26:40 +01:00
Audrius Butkevicius
d4199c2d08 Recover from corrupt block maps 2014-10-24 23:20:08 +01:00
Audrius Butkevicius
cf4ca7b6a8 Fix test leak 2014-10-24 22:23:19 +01:00
Jakob Borg
d8b335ce65 Don't panic on queries for nonexistent folders (fixes #765) 2014-10-24 14:54:36 +02:00
Jakob Borg
39a2934b05 Translation update 2014-10-24 10:27:14 +02:00
Jakob Borg
7d1c720b84 Slightly more robust HTTP stress test 2014-10-24 10:01:44 +02:00
Jakob Borg
51743461ee Futile attempt at reproducing leveldb issues 2014-10-24 09:50:41 +02:00
Jakob Borg
53cf5ca762 Don't run auto upgrade on non-release builds (fixes #901). 2014-10-23 19:11:53 +02:00
Jakob Borg
b5ef42b0a1 Merge pull request #898 from cqcallaw/upnp
Various UPnP updates
2014-10-23 09:04:58 +02:00
Jakob Borg
0521ddd858 Merge pull request #895 from AudriusButkevicius/puller
Cleanup blockmap on update (fixes #889)
2014-10-23 09:01:28 +02:00
Caleb Callaway
b7bb3bfee2 UPnP discovery fix for devices that send multiple response packets
Fix UPnP discovery and port mapping issues reported in #896
2014-10-22 19:10:44 -07:00
Caleb Callaway
4183044e96 Fix UPnP log spam on networks without UPnP IGDs (see #893)
We should only run the UPnP port mapping renewal routine if the initial
discovery and configuration succeed. This commit applies that logic.
2014-10-22 18:47:15 -07:00
Caleb Callaway
27448bde20 Variable naming clarification 2014-10-22 18:47:15 -07:00
Caleb Callaway
87b9e8fbaf Parse UPnP service ID from root description and expose it to consumers 2014-10-22 18:47:15 -07:00
Caleb Callaway
9d79859ba6 More verbose debug logging of UPnP SOAP requests 2014-10-22 18:47:15 -07:00
Audrius Butkevicius
25bb55491a Cleanup blockmap on update (fixes #889) 2014-10-22 22:18:07 +01:00
Jakob Borg
198cbacc3e Be lenient towards malformed UPnP IGD UUIDs (fixes #890) 2014-10-21 17:07:11 +02:00
Jakob Borg
3f842221f7 Write Windows line breaks on Windows; tee to stdout 2014-10-21 09:35:17 +02:00
Jakob Borg
5d0183a9ed Add -logfile flag, Windows only 2014-10-21 09:20:26 +02:00
Jakob Borg
99df4d660b Move recurring UPnP log messages to debug level 2014-10-21 09:20:26 +02:00
Jakob Borg
f2adfde1a8 Update xdr; handle marshalling errors 2014-10-21 09:20:14 +02:00
Jakob Borg
1e915a2903 Add test for syncing with 100 configured devices 2014-10-21 08:53:53 +02:00
Audrius Butkevicius
e2dc3e9ff3 Fix error messages 2014-10-21 00:01:02 +01:00
Jakob Borg
f1bb8daaab Merge pull request #886 from AudriusButkevicius/limit
Remove 64 device limit
2014-10-20 22:52:58 +02:00
Audrius Butkevicius
b0fcbebdae Remove 64 device limit 2014-10-20 21:46:53 +01:00
Jakob Borg
34f72ecf8f OpenBSD support (fixes #878) 2014-10-19 14:02:17 +02:00
Jakob Borg
9d348319fd Translation update 2014-10-18 20:50:40 +02:00
Jakob Borg
c55fee69de Devices added by introducer should have dynamic address (fixes #866) 2014-10-18 20:40:31 +02:00
Jakob Borg
ce31cb072b Upgrade test configs to v6 2014-10-18 20:37:15 +02:00
Jakob Borg
6b91fc9c91 Merge pull request #876 from cqcallaw/upnp
UPnP API Additions to address outstanding parts of #432
2014-10-18 19:58:56 +02:00
Caleb Callaway
e34f77ba0e Enable portmapping for individual UPnP services 2014-10-18 10:20:57 -07:00
Jakob Borg
bc3b7401a1 Merge branch 'pr/875'
* pr/875:
  Make folder path selectable in FireFox
2014-10-18 13:15:44 +02:00
Caleb Callaway
85677eaf1a UPnP API for querying of services' external IP address 2014-10-17 20:37:00 -07:00
Caleb Callaway
75d5e74059 Refinements to UPnP documentation 2014-10-17 19:47:08 -07:00
Audrius Butkevicius
c4d15b3b95 Fix blockmap hash size 2014-10-18 00:39:36 +01:00
Audrius Butkevicius
aa168ec2d6 Populate block offsets even if the blocks are not diffed 2014-10-17 23:16:29 +01:00
bigbear2nd
4ae0efe887 Make folder path selectable in FireFox
Make the folder name and the folder path selectable in FireFox, as discussed here: https://pulse-forum.ind.ie/t/how-can-the-folder-path-be-changed/1153/6

Add the assets to the commit
Add me to the contributors
Add me to the contributors in the index.html
2014-10-18 01:39:57 +09:00
Jakob Borg
86a57d8b56 Hash mismatch in general doesn't merit a warning 2014-10-17 10:33:02 +02:00
Jakob Borg
9dda7485eb Merge branch 'pr/871'
* pr/871:
  Slight increase of contrast in identicons
  Implement identicon representation for devices.

Conflicts:
	internal/auto/gui.files.go
2014-10-17 09:29:06 +02:00
Jakob Borg
8b9670add9 Add cdata 2014-10-17 09:28:45 +02:00
Jakob Borg
978aebd79c Slight increase of contrast in identicons 2014-10-17 09:26:58 +02:00
Chris Joel
ac079f0f83 Implement identicon representation for devices.
The first fifteen characters of device IDs are now used to procedurally
generate psuedo-unique avatars for their respective devices. The avatars
are represented using SVG elements that replace the icons previously
shown next to device names in the GUI.
2014-10-16 12:28:43 -07:00
Jakob Borg
e82e912151 Dependencies 2014-10-16 14:58:11 +02:00
Jakob Borg
5488ae5b89 Don't log inscrutable 'recovered: leveldb: not found' to web GUI 2014-10-16 13:45:42 +02:00
Jakob Borg
15b875b116 Merge branch 'pr/830'
* pr/830:
  Delete files and directories after pulling
  Add fetcher tests
  Track total block counts, count copier blocks
  Fix tests
  Implement block fetcher (fixes #781, fixes #3)
  Populate BlockMap
  Implement BlockMap
2014-10-16 13:33:20 +02:00
Audrius Butkevicius
dedf835aa6 Delete files and directories after pulling 2014-10-16 12:26:28 +02:00
Audrius Butkevicius
e62b9c6009 Add fetcher tests 2014-10-16 12:26:28 +02:00
Audrius Butkevicius
53da778506 Track total block counts, count copier blocks
Will eventually allow us to track progress per file
2014-10-16 12:26:28 +02:00
Audrius Butkevicius
4360b2c815 Fix tests 2014-10-16 12:26:28 +02:00
Audrius Butkevicius
1e15b1e0be Implement block fetcher (fixes #781, fixes #3) 2014-10-16 12:26:28 +02:00
Audrius Butkevicius
0bc50f7284 Populate BlockMap 2014-10-16 12:26:27 +02:00
Audrius Butkevicius
435f9113e8 Implement BlockMap 2014-10-16 12:26:27 +02:00
Jakob Borg
8818c4785b Fix debug and fmt poopoo 2014-10-16 12:23:33 +02:00
Jakob Borg
2e003e5404 Remove out of date upnp tests 2014-10-16 12:12:59 +02:00
Jakob Borg
e791a8ea07 Handle .stfolder completely in integration test 2014-10-16 12:12:59 +02:00
Jakob Borg
2fb8eb755b Add a few more debug prints 2014-10-16 12:12:54 +02:00
Jakob Borg
d031f958a9 FileInfoTruncated.String() for stindex' benefit 2014-10-16 09:26:24 +02:00
Jakob Borg
9bbadac9dc Asset rebuild 2014-10-16 09:11:23 +02:00
Jakob Borg
b012f77475 Merge pull request #848 from pluby/discovery
Simpler entry of locally discovered nodes
2014-10-16 09:11:08 +02:00
Jakob Borg
3cf36b1773 Add pluby 2014-10-16 09:09:41 +02:00
Jakob Borg
8f93c046a9 Merge pull request #775 from cqcallaw/master
UPnP cleanup and fixes for #432
2014-10-16 08:55:53 +02:00
Jakob Borg
90af68901a Add cqcallaw 2014-10-16 08:55:27 +02:00
Caleb Callaway
c17507b216 Cleanup UPnP API
This commit addresses most of the issues identified in #432:

* Support UPnP IGDs with both WANIPConnection and WANPPPConnection services

  IGDs that offer both WANIPConnection and WANPPPConnection services should
  now have port forwarding correctly configured for all services.

* Support multiple UPnP WANDevice and WANConnection descriptions

  Per Figure 1 of the InternetGatewayDevice specification
  (http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf),
  an IGD may have multiple WAN devices, each with multiple WANConnection
  services

* Support for discovery of UPnP InternetGatewayDevice version 2 devices

* Support for discovery of multiple UPnP IGDs

  Consumers that cannot yet properly process multiple IGDs can simply use
  the first IGD listed in the discovery results

* Logging refinements such as friendly UPnP IGD identifiers in log messages.
2014-10-15 21:48:11 -07:00
Phill Luby
b110b7c3f7 Make cacheEntry public so that it can be marshalled to the UI. 2014-10-15 21:52:06 +01:00
Phill Luby
36431b3dcd Provide a data-list of locally discovered nodes when adding a new node. 2014-10-15 21:20:38 +01:00
Phill Luby
609294deee Set content type on discovery rest request. 2014-10-15 21:20:38 +01:00
Phill Luby
fffae9a741 Repackage discovery registry so that it can be converted to JSON.
The registry uses a non-string type as keys which is not possible in JSON.
2014-10-15 21:20:38 +01:00
Jakob Borg
598ce4bb5f Don't add newline on version string (fixes #865) 2014-10-15 18:15:40 +02:00
Jakob Borg
212f6dc9e0 Merge pull request #861 from AudriusButkevicius/int
Use relative path in integration tests
2014-10-15 18:07:51 +02:00
Jakob Borg
cd05f1c3d7 Merge pull request #860 from AudriusButkevicius/ticker
Cleanup temporaries once an hour (fixes #858)
2014-10-15 18:07:15 +02:00
Jakob Borg
d7a0691c99 Merge pull request #859 from AudriusButkevicius/markerfix
Best attempt when creating a folder marker (fixes #857)
2014-10-15 18:06:40 +02:00
Audrius Butkevicius
86346aa332 Add further nil checks (fixes #862, ref #864) 2014-10-15 15:54:55 +01:00
Audrius Butkevicius
b162b1fa34 Use relative path in integration tests 2014-10-15 14:05:25 +01:00
Audrius Butkevicius
ea9f8b0ceb Cleanup temporaries once an hour (fixes #858) 2014-10-15 10:30:10 +01:00
Audrius Butkevicius
6210b9e746 Best attempt when creating a folder marker (fixes #857) 2014-10-15 10:20:40 +01:00
Jakob Borg
a778b410b9 Only do initial scan if scanInterval==0 (fixes #856) 2014-10-15 10:51:09 +02:00
Jakob Borg
8a674c8bc3 Integration tests should take .stfolder into account when comparing dirs 2014-10-15 09:57:34 +02:00
Audrius Butkevicius
aaf625c624 Merge pull request #854 from AudriusButkevicius/nils
Revert and replace 31d95ac, 65acc7c, 87780a5
2014-10-15 08:24:19 +01:00
Jakob Borg
d4079a3273 Merge pull request #853 from AudriusButkevicius/unfinished
Keep temporaries for reuse, cleanup before pull (fixes #849, fixes #841)
2014-10-15 09:01:14 +02:00
Jakob Borg
8d94fe3346 Merge remote-tracking branch 'origin/pr/852'
* origin/pr/852:
  `-generate` flag should also create config.xml (closes #847).
2014-10-15 08:45:11 +02:00
Jakob Borg
ce510e55ae Add Nutomic 2014-10-15 08:44:58 +02:00
Audrius Butkevicius
5419ff9a71 Keep temporaries for reuse, cleanup before pull (fixes #849, fixes #841) 2014-10-14 22:00:40 +01:00
Audrius Butkevicius
ade437d625 Revert and replace 31d95ac, 65acc7c, 87780a5 2014-10-14 21:35:30 +01:00
Audrius Butkevicius
87780a5b7e Fix a missed nil (fixes #846) 2014-10-14 20:17:42 +01:00
Felix Ableitner
f6f6f261ed -generate flag should also create config.xml (closes #847). 2014-10-14 22:11:05 +03:00
Audrius Butkevicius
65acc7c9ad Merge pull request #850 from AudriusButkevicius/nil
Do not return nil pointers when loading ignores (fixes #846)
2014-10-14 19:16:20 +01:00
Audrius Butkevicius
31d95ac9e6 Do not return nil pointers when loading ignores (fixes #846)
Not sure, perhaps we should check for error, and respect that instead.
But then in the walker we'll have to check for a nil pointer anyway.
2014-10-14 16:28:43 +01:00
Jakob Borg
964d17d05a Merge pull request #842 from AudriusButkevicius/ignorecache
Cache ignore file matches
2014-10-14 12:43:21 +02:00
Audrius Butkevicius
665c5992f0 Cache ignore file matches 2014-10-14 10:30:37 +01:00
Jakob Borg
5f52e0581d Add linientMtimes workaround for Android brokenness (ref #831) 2014-10-14 08:48:43 +02:00
Jakob Borg
870e3a45ef Merge pull request #833 from AudriusButkevicius/marker
Add folder marker (fixes #762)
2014-10-14 08:23:48 +02:00
Audrius Butkevicius
a5fe4a3694 Perform tilde expansion in the config wrapper 2014-10-13 21:59:42 +01:00
Audrius Butkevicius
838670ccbc Add folder marker (fixes #762) 2014-10-13 21:54:42 +01:00
Jakob Borg
baf4cc225e Build without git 2014-10-13 20:13:42 +02:00
Jakob Borg
93ac1605bd Set version on command line when building 2014-10-13 20:10:36 +02:00
Jakob Borg
c8a68001c1 Use HTTP server read timeout (fixes #805, fixes #806) 2014-10-13 19:34:26 +02:00
Jakob Borg
244a22755c Merge branch 'pr-840'
* pr-840:
  More descriptive error if config couldn't be loaded
  Better handling of wrong config files
2014-10-13 16:02:14 +02:00
Jakob Borg
79c3ea82c7 More descriptive error if config couldn't be loaded 2014-10-13 16:01:57 +02:00
Jakob Borg
4b92960975 Add mvdan 2014-10-13 16:00:01 +02:00
Daniel Martí
ef616ff25b Better handling of wrong config files 2014-10-13 15:41:50 +02:00
Jakob Borg
7fb1a470ce Temporary workaround for panics in GUI/Usage reporting (ref #811) 2014-10-13 14:45:40 +02:00
Jakob Borg
fc6b2d9193 Ignore matcher benchmark 2014-10-12 14:54:36 +02:00
Jakob Borg
e5dc66e7e5 Translation update 2014-10-12 14:09:40 +02:00
Jakob Borg
bb01b76582 Fix monitor deadlock on panic 2014-10-12 13:53:30 +02:00
Jakob Borg
f1aff0fd96 Merge pull request #829 from seehuhn/cleanups
Cleanup the code in internal/files/leveldb.go a bit.
2014-10-12 10:50:33 +02:00
Jakob Borg
5656be5206 Folders queried by the REST interface might not exist in the model (fixes #823) 2014-10-12 10:47:23 +02:00
Alexander Graf
484ce8e488 only convert maxAge from days to seconds once 2014-10-11 21:18:16 +02:00
Audrius Butkevicius
dcadefd133 Introducer should default to false (fixes #825) 2014-10-10 23:20:49 +01:00
Jochen Voss
28366677b0 Cleanup the code in internal/files/leveldb.go a bit.
This commit introduces the following, cosmetic changes:

- All callers of 'ldbGenericReplace' specify a non-nil 'deleteFn' argument.
  Thus, remove the checks for 'deleteFn' being nil.

- Before this change, 'ldbInsert' took a 'FileInfo' argument and a
  separate argument for the file name, but all callers passed in the
  value of FileInfo.Name as the file name.  Simplify this, by not not
  passing in the file name as a separate argument.  This makes the
  function signature of 'ldbInsert' more similar to 'ldbUpdate'.

- doc fixes
2014-10-10 22:12:01 +01:00
Jakob Borg
d65302742c Emit info level log when deleting directory fails 2014-10-10 21:20:46 +02:00
Jakob Borg
b2cf28efdd Refactor out functions in main 2014-10-10 17:34:31 +02:00
Jakob Borg
41e20bb6b7 Reinstate ignore permissions 2014-10-10 00:34:32 +02:00
Jakob Borg
6e670a2499 Merge pull request #820 from seehuhn/fixes
ldbGenericReplace: correctly handle files with same version but different flags
2014-10-10 00:05:25 +02:00
Jochen Voss
481b2186cb ldbGenericReplace: correctly handle files with same version but different flags.
This fixes syncthing bug #819.
2014-10-09 19:36:31 +01:00
Jakob Borg
1bc1c0b14f Print some debug info when panicing in leveldb 2014-10-09 10:44:18 +02:00
Jakob Borg
e9d27b9d2b Slightly improve panic log format (...)
- Don't repeat the first log lines
 - Print panic timestamp in context.
2014-10-09 09:39:08 +02:00
Audrius Butkevicius
828bbc407f Restarting monitor process is still considered a restart (fixes #809) 2014-10-09 09:04:33 +02:00
Audrius Butkevicius
e50469d84e Better version change detection (fixes #808, fixes #810) 2014-10-08 21:20:54 +01:00
Jakob Borg
d3a9b126a6 Translation update 2014-10-08 13:58:41 +02:00
Jakob Borg
9eb185ec39 Threshold for existing languages to be included (75%) 2014-10-08 13:57:11 +02:00
Jakob Borg
fcf60e7f7c Archive a copy of config.xml when the format changes 2014-10-08 13:52:05 +02:00
Jakob Borg
0ebee92f7d Test case and goleveldb fix (fixes #740, fixes #796) 2014-10-08 09:30:36 +02:00
Jakob Borg
64b42bba2e Remove dead code 2014-10-07 19:26:55 +02:00
Jochen Voss
d297f9e032 bug fix: allow folder names up to length 64 in leveldb
When extracting a folder name from the byte slices used as database
keys, bytes.IndexByte() is used to find and remove trailing 0 bytes.
In case the folder name is 64 bytes long, bytes.IndexByte() returns
-1.  Before this change, syncthing crashed in this case with an
out-of-bounds slice access.

The commit fixes the problem and also introduces a test case which
checks for the presence of the bug.
2014-10-07 14:05:04 +01:00
Jakob Borg
30aabf1da9 InSync is the opposite of RequiresRestart... 2014-10-07 11:31:19 +02:00
Jakob Borg
eebdaa2f27 Test for ChangeRequiresRestart 2014-10-07 10:46:33 +02:00
Jakob Borg
c3c9c4cde5 Use a separate lock for the subscriber stuff 2014-10-07 10:34:53 +02:00
Jakob Borg
640d5135df Merge remote-tracking branch 'origin/pr/793'
* origin/pr/793:
  Minor fixes.
2014-10-07 07:43:23 +02:00
Jakob Borg
cbbd20a687 Add seehuhn 2014-10-07 07:43:09 +02:00
Jochen Voss
1a2a27b988 Minor fixes.
- Bug fix - use .Errorf() instead of .Error():
  Before this change, an error message for failed tests in files/set_test.go
  wrongly tried to use format strings in a call to .Error()

- Change event constants to be of type EventType rather than untyped integers.

- Slightly relax the locking for registry cache lookups:
  For read access to Discover.registry we only need to take a read lock.

- Some cosmetic fixes.
2014-10-06 23:03:24 +01:00
Jakob Borg
d819151020 Update goleveldb 2014-10-06 22:07:33 +02:00
Jakob Borg
d089436546 Removing a nonexistent file is OK (fixes #792) 2014-10-06 21:47:42 +02:00
Jakob Borg
289d604690 Minor config cleanup 2014-10-06 21:43:38 +02:00
Jakob Borg
2979e0e964 Fix tests for removed methods 2014-10-06 21:28:58 +02:00
Jakob Borg
5338f1cfbd Fix configInSync which is still needed 2014-10-06 21:28:16 +02:00
Jakob Borg
214f18cbfd Clean up flags vs envvars 2014-10-06 17:57:35 +02:00
Jakob Borg
9b11609b63 Use a configuration wrapper to handle loads and saves 2014-10-06 17:57:35 +02:00
Jakob Borg
d476c2b613 Simplify HTTP testing 2014-10-06 12:03:49 +02:00
Jakob Borg
590afebc0a Handle connection closed in reconnect test 2014-10-06 11:13:06 +02:00
Jakob Borg
02bd1af293 Controlled polling interval without keepalives to avoid HTTP errors in integration test. 2014-10-06 10:56:50 +02:00
Jakob Borg
2fde82528d Fix tests for previous 2014-10-06 10:19:27 +02:00
Jakob Borg
6c383e279f Handle corner case where we can reuse a temp file totally 2014-10-06 10:15:57 +02:00
Jakob Borg
5c07477de4 Install verbosely 2014-10-06 08:44:59 +02:00
Jakob Borg
146a284315 Merge branch 'pr/787'
* pr/787:
  Add tests
  Reuse temporary files (fixes #4)
  Have only one block size
2014-10-06 08:31:48 +02:00
Audrius Butkevicius
a8faeeac73 Add tests 2014-10-04 16:01:05 +01:00
Audrius Butkevicius
69e385e4cd Reuse temporary files (fixes #4) 2014-10-04 16:00:59 +01:00
Audrius Butkevicius
41b8dd2863 Have only one block size 2014-10-04 13:20:46 +01:00
Audrius Butkevicius
493dc8fcd5 Remove unused argument/variable 2014-10-04 13:20:07 +01:00
Jakob Borg
87764445e8 Some debug prints in the puller loop skips 2014-10-03 17:55:51 +02:00
Jakob Borg
0bb31e16c9 Move copyright inside <div> (ref #779) 2014-10-03 16:18:22 +02:00
Jakob Borg
72c90abe36 Reschedule pulls when skipping due to scan incomplete (fixes #777) 2014-10-03 16:10:35 +02:00
Audrius Butkevicius
c4d8d33a60 Merge pull request #769 from AudriusButkevicius/fix
Disable autoupgrade if not supported (fixes #763)
2014-10-01 20:08:27 +01:00
Audrius Butkevicius
a267bca8fb Disable autoupgrade if not supported (fixes #763) 2014-10-01 20:06:51 +01:00
Jakob Borg
32d2e78e3c Directory -> Path in folder editor (fixes #772) 2014-10-01 15:34:12 +02:00
Jakob Borg
555e70ebec Remove temporary file on hash mismatch (fixes #771) 2014-10-01 14:43:22 +02:00
Jakob Borg
cd1b2aab46 Merge pull request #760 from syncthing/gpl
Relicense to GPL
2014-10-01 08:07:27 +02:00
Jakob Borg
9edce23e76 Relicense to GPL 2014-10-01 07:53:59 +02:00
Jakob Borg
756a8a35e3 Add file I forgot in previous 2014-09-30 17:56:02 +02:00
Jakob Borg
f3057c61a7 Prepare for being able to start and stop folders at any time 2014-09-30 17:52:05 +02:00
Jakob Borg
25345f08e7 Tone down initial auto upgrade warning 2014-09-30 17:38:12 +02:00
Jakob Borg
2091e12e82 Perform initial scan asynchronously (fixes #509, fixes #464) 2014-09-30 17:35:04 +02:00
Jakob Borg
3eb000fa60 Don't perform any further checks on too short IP numbers (fixes #764) 2014-09-30 17:23:31 +02:00
Jakob Borg
3059b36118 Fix test configs to v5 format 2014-09-29 20:22:16 +02:00
Jakob Borg
35b1887e17 Spelling of Deprecated 2014-09-29 20:07:31 +02:00
Jakob Borg
8f9b8a8550 Fork osext and support Solaris 2014-09-28 23:11:12 +02:00
Jakob Borg
174befe729 Revert "Fix build on Solaris"
This reverts commit e212b64823.
2014-09-28 23:09:55 +02:00
Audrius Butkevicius
e212b64823 Fix build on Solaris 2014-09-28 21:54:24 +01:00
Jakob Borg
991dc32a0b Fix config tests for autoUpgradeIntervalH 2014-09-28 22:38:10 +02:00
Audrius Butkevicius
a76efd4166 Merge pull request #750 from AudriusButkevicius/upgrades
Autoupgrades (fixes #727)
2014-09-28 21:09:08 +01:00
Audrius Butkevicius
8a768baaaa Add autoUpgrade option in UI 2014-09-28 21:07:28 +01:00
Audrius Butkevicius
997692b494 Add autoUpgrade coroutine (fixes #727) 2014-09-28 21:06:46 +01:00
Audrius Butkevicius
59ffec4e39 Allow a single upgrade at a time 2014-09-28 21:06:46 +01:00
Audrius Butkevicius
56d0ecc253 Rebuild assets 2014-09-28 14:39:18 +01:00
Audrius Butkevicius
e863746bd7 Change some text in UI to make more sense 2014-09-28 14:38:57 +01:00
Audrius Butkevicius
d4dc7911eb Migrate config 2014-09-28 14:36:21 +01:00
Audrius Butkevicius
f561d3261a Rename FolderConfiguration.Directory to FolderConfiguration.Path 2014-09-28 14:36:16 +01:00
Audrius Butkevicius
fdf8ee7015 Manual fixup 2014-09-28 14:23:08 +01:00
Audrius Butkevicius
5ec95086f2 Run go fmt -w -s 2014-09-28 14:23:08 +01:00
Audrius Butkevicius
26e4669316 Run go fmt -w 2014-09-28 14:23:08 +01:00
Audrius Butkevicius
6c352dca74 Rename Repository -> Folder, Node -> Device (fixes #739) 2014-09-28 14:23:07 +01:00
Jakob Borg
9d816694ba Don't require godep to build 2014-09-28 13:09:55 +02:00
Audrius Butkevicius
39ef35db0c Merge pull request #753 from AudriusButkevicius/ph
Remove field placeholders (fixes #748)
2014-09-28 11:10:20 +01:00
Jakob Borg
b8ed135183 Don't get stuck in idle while syncing from a disconnecting node 2014-09-28 07:56:05 +02:00
Jakob Borg
6f750582dd Short benchmark test only by default 2014-09-28 07:55:12 +02:00
Jakob Borg
5f93fbd471 Genfiles should be random by default 2014-09-28 07:31:53 +02:00
Jakob Borg
0e2653b7dd Correctly handle ro dirs in ro dirs etc 2014-09-28 01:54:25 +02:00
Audrius Butkevicius
47554b562d Remove field placeholders (fixes #748)
All of them are either required, or empty by default, or for example
node name is later populated on first connection.
2014-09-28 00:47:58 +01:00
Jakob Borg
99427d649e Complete rewrite of the puller (fixes #638, fixes #715, fixes #701) 2014-09-27 21:51:08 +02:00
249 changed files with 13605 additions and 7412 deletions

View File

@@ -12,7 +12,7 @@ least the following:
- What operating system, operating system version and version of
Syncthing you are running
- The same for other connected nodes, where relevant
- The same for other connected devices, where relevant
- Screenshot if the issue concerns something visible in the GUI
@@ -52,10 +52,11 @@ accepted. This means to make sure that the pull request:
## Licensing
All contributions are made under the same MIT License as the rest of the
project, except documentation which is licensed under the Creative
Commons Attribution 4.0 International License. You retain the copyright
to code you have written.
All contributions are made under the same GPL license as the rest of the
project, except documentation, user interface text and translation
strings which are licensed under the Creative Commons Attribution 4.0
International License. You retain the copyright to code you have
written.
When accepting your first contribution, the maintainer of the project
will ensure that you are added to the CONTRIBUTORS file. You are welcome
@@ -101,4 +102,4 @@ Yes please!
## License
MIT
GPLv3

View File

@@ -5,13 +5,21 @@ Audrius Butkevicius <audrius.butkevicius@gmail.com>
Arthur Axel fREW Schmidt <frew@afoolishmanifesto.com> <frioux@gmail.com>
Ben Sidhom <bsidhom@gmail.com>
Brandon Philips <brandon@ifup.org>
Caleb Callaway <enlightened.despot@gmail.com>
Chris Joel <chris@scriptolo.gy>
Daniel Martí <mvdan@mvdan.cc>
Felix Ableitner <me@nutomic.com>
Felix Unterpaintner <bigbear2nd@gmail.com>
Gilli Sigurdsson <gilli@vx.is>
James Patterson <jamespatterson@operamail.com> <jpjp@users.noreply.github.com>
Jens Diemer <github.com@jensdiemer.de> <git@jensdiemer.de>
Jochen Voss <voss@seehuhn.de>
Lode Hoste <zillode@zillode.be>
Marcin Dziadus <dziadus.marcin@gmail.com>
Michael Tilli <pyfisch@gmail.com>
Philippe Schommers <philippe@schommers.be>
Phill Luby <phill.luby@newredo.com>
Ryan Sullivan <kayoticsully@gmail.com>
Tully Robinson <tully@tojr.org>
Veeti Paananen <veeti.paananen@rojekti.fi>
Vil Brekin <vilbrekin@gmail.com>

23
Godeps/Godeps.json generated
View File

@@ -1,15 +1,10 @@
{
"ImportPath": "github.com/syncthing/syncthing",
"GoVersion": "go1.3.1",
"GoVersion": "go1.3.3",
"Packages": [
"./cmd/..."
],
"Deps": [
{
"ImportPath": "bitbucket.org/kardianos/osext",
"Comment": "null-13",
"Rev": "5d3ddcf53a508cc2f7404eaebf546ef2cb5cdb6e"
},
{
"ImportPath": "code.google.com/p/go.crypto/bcrypt",
"Comment": "null-216",
@@ -35,13 +30,25 @@
"Comment": "null-15",
"Rev": "12e4b4183793ac4b061921e7980845e750679fd0"
},
{
"ImportPath": "github.com/AudriusButkevicius/lfu-go",
"Rev": "164bcecceb92fd6037f4d18a8d97b495ec6ef669"
},
{
"ImportPath": "github.com/bkaradzic/go-lz4",
"Rev": "93a831dcee242be64a9cc9803dda84af25932de7"
},
{
"ImportPath": "github.com/calmh/logger",
"Rev": "f50d32b313bec2933a3e1049f7416a29f3413d29"
},
{
"ImportPath": "github.com/calmh/osext",
"Rev": "9bf61584e5f1f172e8766ddc9022d9c401faaa5e"
},
{
"ImportPath": "github.com/calmh/xdr",
"Rev": "a597b63b87d6140f79084c8aab214b4d533833a1"
"Rev": "ec3d404f43731551258977b38dd72cf557d00398"
},
{
"ImportPath": "github.com/juju/ratelimit",
@@ -49,7 +56,7 @@
},
{
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
"Rev": "9bca75c48d6c31becfbb127702b425e7226052e3"
"Rev": "cd2b8f743192883ab9fbc5f070ebda1dc90f3732"
},
{
"ImportPath": "github.com/vitrun/qart/coding",

View File

@@ -0,0 +1,19 @@
Copyright (C) 2012 Dave Grijalva
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,19 @@
A simple LFU cache for golang. Based on the paper [An O(1) algorithm for implementing the LFU cache eviction scheme](http://dhruvbird.com/lfu.pdf).
Usage:
```go
import "github.com/dgrijalva/lfu-go"
// Make a new thing
c := lfu.New()
// Set some values
c.Set("myKey", myValue)
// Retrieve some values
myValue = c.Get("myKey")
// Evict some values
c.Evict(1)
```

View File

@@ -0,0 +1,156 @@
package lfu
import (
"container/list"
"sync"
)
type Eviction struct {
Key string
Value interface{}
}
type Cache struct {
// If len > UpperBound, cache will automatically evict
// down to LowerBound. If either value is 0, this behavior
// is disabled.
UpperBound int
LowerBound int
values map[string]*cacheEntry
freqs *list.List
len int
lock *sync.Mutex
EvictionChannel chan<- Eviction
}
type cacheEntry struct {
key string
value interface{}
freqNode *list.Element
}
type listEntry struct {
entries map[*cacheEntry]byte
freq int
}
func New() *Cache {
c := new(Cache)
c.values = make(map[string]*cacheEntry)
c.freqs = list.New()
c.lock = new(sync.Mutex)
return c
}
func (c *Cache) Get(key string) interface{} {
c.lock.Lock()
defer c.lock.Unlock()
if e, ok := c.values[key]; ok {
c.increment(e)
return e.value
}
return nil
}
func (c *Cache) Set(key string, value interface{}) {
c.lock.Lock()
defer c.lock.Unlock()
if e, ok := c.values[key]; ok {
// value already exists for key. overwrite
e.value = value
c.increment(e)
} else {
// value doesn't exist. insert
e := new(cacheEntry)
e.key = key
e.value = value
c.values[key] = e
c.increment(e)
c.len++
// bounds mgmt
if c.UpperBound > 0 && c.LowerBound > 0 {
if c.len > c.UpperBound {
c.evict(c.len - c.LowerBound)
}
}
}
}
func (c *Cache) Len() int {
c.lock.Lock()
defer c.lock.Unlock()
return c.len
}
func (c *Cache) Evict(count int) int {
c.lock.Lock()
defer c.lock.Unlock()
return c.evict(count)
}
func (c *Cache) evict(count int) int {
// No lock here so it can be called
// from within the lock (during Set)
var evicted int
for i := 0; i < count; {
if place := c.freqs.Front(); place != nil {
for entry, _ := range place.Value.(*listEntry).entries {
if i < count {
if c.EvictionChannel != nil {
c.EvictionChannel <- Eviction{
Key: entry.key,
Value: entry.value,
}
}
delete(c.values, entry.key)
c.remEntry(place, entry)
evicted++
c.len--
i++
}
}
}
}
return evicted
}
func (c *Cache) increment(e *cacheEntry) {
currentPlace := e.freqNode
var nextFreq int
var nextPlace *list.Element
if currentPlace == nil {
// new entry
nextFreq = 1
nextPlace = c.freqs.Front()
} else {
// move up
nextFreq = currentPlace.Value.(*listEntry).freq + 1
nextPlace = currentPlace.Next()
}
if nextPlace == nil || nextPlace.Value.(*listEntry).freq != nextFreq {
// create a new list entry
li := new(listEntry)
li.freq = nextFreq
li.entries = make(map[*cacheEntry]byte)
if currentPlace != nil {
nextPlace = c.freqs.InsertAfter(li, currentPlace)
} else {
nextPlace = c.freqs.PushFront(li)
}
}
e.freqNode = nextPlace
nextPlace.Value.(*listEntry).entries[e] = 1
if currentPlace != nil {
// remove from current position
c.remEntry(currentPlace, e)
}
}
func (c *Cache) remEntry(place *list.Element, entry *cacheEntry) {
entries := place.Value.(*listEntry).entries
delete(entries, entry)
if len(entries) == 0 {
c.freqs.Remove(place)
}
}

View File

@@ -0,0 +1,68 @@
package lfu
import (
"fmt"
"testing"
)
func TestLFU(t *testing.T) {
c := New()
c.Set("a", "a")
if v := c.Get("a"); v != "a" {
t.Errorf("Value was not saved: %v != 'a'", v)
}
if l := c.Len(); l != 1 {
t.Errorf("Length was not updated: %v != 1", l)
}
c.Set("b", "b")
if v := c.Get("b"); v != "b" {
t.Errorf("Value was not saved: %v != 'b'", v)
}
if l := c.Len(); l != 2 {
t.Errorf("Length was not updated: %v != 2", l)
}
c.Get("a")
evicted := c.Evict(1)
if v := c.Get("a"); v != "a" {
t.Errorf("Value was improperly evicted: %v != 'a'", v)
}
if v := c.Get("b"); v != nil {
t.Errorf("Value was not evicted: %v", v)
}
if l := c.Len(); l != 1 {
t.Errorf("Length was not updated: %v != 1", l)
}
if evicted != 1 {
t.Errorf("Number of evicted items is wrong: %v != 1", evicted)
}
}
func TestBoundsMgmt(t *testing.T) {
c := New()
c.UpperBound = 10
c.LowerBound = 5
for i := 0; i < 100; i++ {
c.Set(fmt.Sprintf("%v", i), i)
}
if c.Len() > 10 {
t.Errorf("Bounds management failed to evict properly: %v", c.Len())
}
}
func TestEviction(t *testing.T) {
ch := make(chan Eviction, 1)
c := New()
c.EvictionChannel = ch
c.Set("a", "b")
c.Evict(1)
ev := <-ch
if ev.Key != "a" || ev.Value.(string) != "b" {
t.Error("Incorrect item")
}
}

19
Godeps/_workspace/src/github.com/calmh/logger/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (C) 2013 Jakob Borg
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,15 @@
logger
======
A small wrapper around `log` to provide log levels.
Documentation
-------------
http://godoc.org/github.com/calmh/logger
License
-------
MIT

View File

@@ -1,6 +1,5 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// Copyright (C) 2014 Jakob Borg. All rights reserved. Use of this source code
// is governed by an MIT-style license that can be found in the LICENSE file.
// Package logger implements a standardized logger with callback functionality
package logger
@@ -24,6 +23,7 @@ const (
NumLevels
)
// A MessageHandler is called with the log level and message text.
type MessageHandler func(l LogLevel, msg string)
type Logger struct {
@@ -32,6 +32,7 @@ type Logger struct {
mut sync.Mutex
}
// The default logger logs to standard output with a time prefix.
var DefaultLogger = New()
func New() *Logger {
@@ -40,16 +41,20 @@ func New() *Logger {
}
}
// AddHandler registers a new MessageHandler to receive messages with the
// specified log level or above.
func (l *Logger) AddHandler(level LogLevel, h MessageHandler) {
l.mut.Lock()
defer l.mut.Unlock()
l.handlers[level] = append(l.handlers[level], h)
}
// See log.SetFlags
func (l *Logger) SetFlags(flag int) {
l.logger.SetFlags(flag)
}
// See log.SetPrefix
func (l *Logger) SetPrefix(prefix string) {
l.logger.SetPrefix(prefix)
}
@@ -60,6 +65,7 @@ func (l *Logger) callHandlers(level LogLevel, s string) {
}
}
// Debugln logs a line with a DEBUG prefix.
func (l *Logger) Debugln(vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -68,6 +74,7 @@ func (l *Logger) Debugln(vals ...interface{}) {
l.callHandlers(LevelDebug, s)
}
// Debugf logs a formatted line with a DEBUG prefix.
func (l *Logger) Debugf(format string, vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -75,6 +82,8 @@ func (l *Logger) Debugf(format string, vals ...interface{}) {
l.logger.Output(2, "DEBUG: "+s)
l.callHandlers(LevelDebug, s)
}
// Infoln logs a line with an INFO prefix.
func (l *Logger) Infoln(vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -83,6 +92,7 @@ func (l *Logger) Infoln(vals ...interface{}) {
l.callHandlers(LevelInfo, s)
}
// Infof logs a formatted line with an INFO prefix.
func (l *Logger) Infof(format string, vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -91,6 +101,7 @@ func (l *Logger) Infof(format string, vals ...interface{}) {
l.callHandlers(LevelInfo, s)
}
// Okln logs a line with an OK prefix.
func (l *Logger) Okln(vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -99,6 +110,7 @@ func (l *Logger) Okln(vals ...interface{}) {
l.callHandlers(LevelOK, s)
}
// Okf logs a formatted line with an OK prefix.
func (l *Logger) Okf(format string, vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -107,6 +119,7 @@ func (l *Logger) Okf(format string, vals ...interface{}) {
l.callHandlers(LevelOK, s)
}
// Warnln logs a formatted line with a WARNING prefix.
func (l *Logger) Warnln(vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -115,6 +128,7 @@ func (l *Logger) Warnln(vals ...interface{}) {
l.callHandlers(LevelWarn, s)
}
// Warnf logs a formatted line with a WARNING prefix.
func (l *Logger) Warnf(format string, vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -123,6 +137,8 @@ func (l *Logger) Warnf(format string, vals ...interface{}) {
l.callHandlers(LevelWarn, s)
}
// Fatalln logs a line with a FATAL prefix and exits the process with exit
// code 1.
func (l *Logger) Fatalln(vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()
@@ -132,6 +148,8 @@ func (l *Logger) Fatalln(vals ...interface{}) {
os.Exit(1)
}
// Fatalf logs a formatted line with a FATAL prefix and exits the process with
// exit code 1.
func (l *Logger) Fatalf(format string, vals ...interface{}) {
l.mut.Lock()
defer l.mut.Unlock()

View File

@@ -1,6 +1,5 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// Copyright (C) 2014 Jakob Borg. All rights reserved. Use of this source code
// is governed by an MIT-style license that can be found in the LICENSE file.
package logger

View File

@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux netbsd openbsd
// +build linux netbsd openbsd solaris
package osext
import (
"errors"
"fmt"
"os"
"runtime"
)
@@ -20,6 +21,8 @@ func executable() (string, error) {
return os.Readlink("/proc/curproc/exe")
case "openbsd":
return os.Readlink("/proc/curproc/file")
case "solaris":
return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid()))
}
return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
}

View File

@@ -33,11 +33,15 @@ var s = XDRBenchStruct{
S0: "Hello World! String one.",
S1: "Hello World! String two.",
}
var e = s.MarshalXDR()
var e []byte
func init() {
e, _ = s.MarshalXDR()
}
func BenchmarkThisMarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
res = s.MarshalXDR()
res, _ = s.MarshalXDR()
}
}

View File

@@ -72,15 +72,23 @@ func (o XDRBenchStruct) EncodeXDR(w io.Writer) (int, error) {
return o.encodeXDR(xw)
}
func (o XDRBenchStruct) MarshalXDR() []byte {
func (o XDRBenchStruct) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
}
func (o XDRBenchStruct) AppendXDR(bs []byte) []byte {
func (o XDRBenchStruct) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
}
func (o XDRBenchStruct) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
o.encodeXDR(xw)
return []byte(aw)
_, err := o.encodeXDR(xw)
return []byte(aw), err
}
func (o XDRBenchStruct) encodeXDR(xw *xdr.Writer) (int, error) {
@@ -88,13 +96,13 @@ func (o XDRBenchStruct) encodeXDR(xw *xdr.Writer) (int, error) {
xw.WriteUint32(o.I2)
xw.WriteUint16(o.I3)
xw.WriteUint8(o.I4)
if len(o.Bs0) > 128 {
return xw.Tot(), xdr.ErrElementSizeExceeded
if l := len(o.Bs0); l > 128 {
return xw.Tot(), xdr.ElementSizeExceeded("Bs0", l, 128)
}
xw.WriteBytes(o.Bs0)
xw.WriteBytes(o.Bs1)
if len(o.S0) > 128 {
return xw.Tot(), xdr.ErrElementSizeExceeded
if l := len(o.S0); l > 128 {
return xw.Tot(), xdr.ElementSizeExceeded("S0", l, 128)
}
xw.WriteString(o.S0)
xw.WriteString(o.S1)
@@ -150,15 +158,23 @@ func (o repeatReader) EncodeXDR(w io.Writer) (int, error) {
return o.encodeXDR(xw)
}
func (o repeatReader) MarshalXDR() []byte {
func (o repeatReader) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
}
func (o repeatReader) AppendXDR(bs []byte) []byte {
func (o repeatReader) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
}
func (o repeatReader) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
o.encodeXDR(xw)
return []byte(aw)
_, err := o.encodeXDR(xw)
return []byte(aw), err
}
func (o repeatReader) encodeXDR(xw *xdr.Writer) (int, error) {

View File

@@ -53,15 +53,23 @@ func (o {{.TypeName}}) EncodeXDR(w io.Writer) (int, error) {
return o.encodeXDR(xw)
}//+n
func (o {{.TypeName}}) MarshalXDR() []byte {
func (o {{.TypeName}}) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
}//+n
func (o {{.TypeName}}) AppendXDR(bs []byte) []byte {
func (o {{.TypeName}}) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
}//+n
func (o {{.TypeName}}) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
o.encodeXDR(xw)
return []byte(aw)
_, err := o.encodeXDR(xw)
return []byte(aw), err
}//+n
func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) {
@@ -71,8 +79,8 @@ func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) {
xw.Write{{$fieldInfo.Encoder}}({{$fieldInfo.Convert}}(o.{{$fieldInfo.Name}}))
{{else if $fieldInfo.IsBasic}}
{{if ge $fieldInfo.Max 1}}
if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} {
return xw.Tot(), xdr.ErrElementSizeExceeded
if l := len(o.{{$fieldInfo.Name}}); l > {{$fieldInfo.Max}} {
return xw.Tot(), xdr.ElementSizeExceeded("{{$fieldInfo.Name}}", l, {{$fieldInfo.Max}})
}
{{end}}
xw.Write{{$fieldInfo.Encoder}}(o.{{$fieldInfo.Name}})
@@ -84,8 +92,8 @@ func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) {
{{end}}
{{else}}
{{if ge $fieldInfo.Max 1}}
if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} {
return xw.Tot(), xdr.ErrElementSizeExceeded
if l := len(o.{{$fieldInfo.Name}}); l > {{$fieldInfo.Max}} {
return xw.Tot(), xdr.ElementSizeExceeded("{{$fieldInfo.Name}}", l, {{$fieldInfo.Max}})
}
{{end}}
xw.WriteUint32(uint32(len(o.{{$fieldInfo.Name}})))
@@ -135,7 +143,7 @@ func (o *{{.TypeName}}) decodeXDR(xr *xdr.Reader) error {
_{{$fieldInfo.Name}}Size := int(xr.ReadUint32())
{{if ge $fieldInfo.Max 1}}
if _{{$fieldInfo.Name}}Size > {{$fieldInfo.Max}} {
return xdr.ErrElementSizeExceeded
return xdr.ElementSizeExceeded("{{$fieldInfo.Name}}", _{{$fieldInfo.Name}}Size, {{$fieldInfo.Max}})
}
{{end}}
o.{{$fieldInfo.Name}} = make([]{{$fieldInfo.FieldType}}, _{{$fieldInfo.Name}}Size)

View File

@@ -24,9 +24,10 @@ type TestStruct struct {
UI32 uint32
I64 int64
UI64 uint64
BS []byte
S string
BS []byte // max:1024
S string // max:1024
C Opaque
SS []string // max:1024
}
type Opaque [32]byte
@@ -49,9 +50,12 @@ func (Opaque) Generate(rand *rand.Rand, size int) reflect.Value {
func TestEncDec(t *testing.T) {
fn := func(t0 TestStruct) bool {
bs := t0.MarshalXDR()
bs, err := t0.MarshalXDR()
if err != nil {
t.Fatal(err)
}
var t1 TestStruct
err := t1.UnmarshalXDR(bs)
err = t1.UnmarshalXDR(bs)
if err != nil {
t.Fatal(err)
}

View File

@@ -54,6 +54,14 @@ TestStruct Structure:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Opaque |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number of SS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length of SS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ /
\ SS (variable length) \
/ /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
struct TestStruct {
@@ -66,9 +74,10 @@ struct TestStruct {
unsigned int UI32;
hyper I64;
unsigned hyper UI64;
opaque BS<>;
string S<>;
opaque BS<1024>;
string S<1024>;
Opaque C;
string SS<1024>;
}
*/
@@ -78,15 +87,23 @@ func (o TestStruct) EncodeXDR(w io.Writer) (int, error) {
return o.encodeXDR(xw)
}
func (o TestStruct) MarshalXDR() []byte {
func (o TestStruct) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
}
func (o TestStruct) AppendXDR(bs []byte) []byte {
func (o TestStruct) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
}
func (o TestStruct) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
o.encodeXDR(xw)
return []byte(aw)
_, err := o.encodeXDR(xw)
return []byte(aw), err
}
func (o TestStruct) encodeXDR(xw *xdr.Writer) (int, error) {
@@ -99,12 +116,25 @@ func (o TestStruct) encodeXDR(xw *xdr.Writer) (int, error) {
xw.WriteUint32(o.UI32)
xw.WriteUint64(uint64(o.I64))
xw.WriteUint64(o.UI64)
if l := len(o.BS); l > 1024 {
return xw.Tot(), xdr.ElementSizeExceeded("BS", l, 1024)
}
xw.WriteBytes(o.BS)
if l := len(o.S); l > 1024 {
return xw.Tot(), xdr.ElementSizeExceeded("S", l, 1024)
}
xw.WriteString(o.S)
_, err := o.C.encodeXDR(xw)
if err != nil {
return xw.Tot(), err
}
if l := len(o.SS); l > 1024 {
return xw.Tot(), xdr.ElementSizeExceeded("SS", l, 1024)
}
xw.WriteUint32(uint32(len(o.SS)))
for i := range o.SS {
xw.WriteString(o.SS[i])
}
return xw.Tot(), xw.Error()
}
@@ -129,8 +159,16 @@ func (o *TestStruct) decodeXDR(xr *xdr.Reader) error {
o.UI32 = xr.ReadUint32()
o.I64 = int64(xr.ReadUint64())
o.UI64 = xr.ReadUint64()
o.BS = xr.ReadBytes()
o.S = xr.ReadString()
o.BS = xr.ReadBytesMax(1024)
o.S = xr.ReadStringMax(1024)
(&o.C).decodeXDR(xr)
_SSSize := int(xr.ReadUint32())
if _SSSize > 1024 {
return xdr.ElementSizeExceeded("SS", _SSSize, 1024)
}
o.SS = make([]string, _SSSize)
for i := range o.SS {
o.SS[i] = xr.ReadString()
}
return xr.Error()
}

View File

@@ -5,14 +5,12 @@
package xdr
import (
"errors"
"fmt"
"io"
"reflect"
"unsafe"
)
var ErrElementSizeExceeded = errors.New("element size exceeded")
type Reader struct {
r io.Reader
err error
@@ -71,7 +69,7 @@ func (r *Reader) ReadBytesMaxInto(max int, dst []byte) []byte {
return nil
}
if max > 0 && l > max {
r.err = ErrElementSizeExceeded
r.err = ElementSizeExceeded("bytes field", l, max)
return nil
}
@@ -162,3 +160,7 @@ func (r *Reader) Error() error {
}
return XDRError{"read", r.err}
}
func ElementSizeExceeded(field string, size, limit int) error {
return fmt.Errorf("%s exceeds size limit; %d > %d", field, size, limit)
}

View File

@@ -5,6 +5,7 @@ package xdr
import (
"bytes"
"strings"
"testing"
"testing/quick"
)
@@ -60,7 +61,7 @@ func TestReadBytesMaxInto(t *testing.T) {
if read := len(bs); read != tot {
t.Errorf("Incorrect read bytes, wrote=%d, buf=%d, max=%d, read=%d", tot, tot+diff, max, read)
}
} else if r.err != ErrElementSizeExceeded {
} else if !strings.Contains(r.err.Error(), "exceeds size") {
t.Errorf("Unexpected non-ErrElementSizeExceeded error for wrote=%d, max=%d: %v", tot, max, r.err)
}
}
@@ -84,7 +85,7 @@ func TestReadStringMax(t *testing.T) {
if read != tot {
t.Errorf("Incorrect read bytes, wrote=%d, max=%d, read=%d", tot, max, read)
}
} else if r.err != ErrElementSizeExceeded {
} else if !strings.Contains(r.err.Error(), "exceeds size") {
t.Errorf("Unexpected non-ErrElementSizeExceeded error for wrote=%d, max=%d, read=%d: %v", tot, max, read, r.err)
}
}

View File

@@ -7,10 +7,8 @@
package cache
import (
"fmt"
"math/rand"
"runtime"
"strings"
"sync"
"sync/atomic"
"testing"
@@ -225,16 +223,16 @@ func TestLRUCache_Purge(t *testing.T) {
}
type testingCacheObjectCounter struct {
created uint32
released uint32
created uint
released uint
}
func (c *testingCacheObjectCounter) createOne() {
atomic.AddUint32(&c.created, 1)
c.created++
}
func (c *testingCacheObjectCounter) releaseOne() {
atomic.AddUint32(&c.released, 1)
c.released++
}
type testingCacheObject struct {
@@ -243,17 +241,75 @@ type testingCacheObject struct {
ns, key uint64
releaseCalled uint32
releaseCalled bool
}
func (x *testingCacheObject) Release() {
if atomic.CompareAndSwapUint32(&x.releaseCalled, 0, 1) {
if !x.releaseCalled {
x.releaseCalled = true
x.cnt.releaseOne()
} else {
x.t.Errorf("duplicate setfin NS#%d KEY#%s", x.ns, x.key)
}
}
func TestLRUCache_ConcurrentSetGet(t *testing.T) {
runtime.GOMAXPROCS(runtime.NumCPU())
seed := time.Now().UnixNano()
t.Logf("seed=%d", seed)
const (
N = 2000000
M = 4000
C = 3
)
var set, get uint32
wg := &sync.WaitGroup{}
c := NewLRUCache(M / 4)
for ni := uint64(0); ni < C; ni++ {
r0 := rand.New(rand.NewSource(seed + int64(ni)))
r1 := rand.New(rand.NewSource(seed + int64(ni) + 1))
ns := c.GetNamespace(ni)
wg.Add(2)
go func(ns Namespace, r *rand.Rand) {
for i := 0; i < N; i++ {
x := uint64(r.Int63n(M))
o := ns.Get(x, func() (int, interface{}) {
atomic.AddUint32(&set, 1)
return 1, x
})
if v := o.Value().(uint64); v != x {
t.Errorf("#%d invalid value, got=%d", x, v)
}
o.Release()
}
wg.Done()
}(ns, r0)
go func(ns Namespace, r *rand.Rand) {
for i := 0; i < N; i++ {
x := uint64(r.Int63n(M))
o := ns.Get(x, nil)
if o != nil {
atomic.AddUint32(&get, 1)
if v := o.Value().(uint64); v != x {
t.Errorf("#%d invalid value, got=%d", x, v)
}
o.Release()
}
}
wg.Done()
}(ns, r1)
}
wg.Wait()
t.Logf("set=%d get=%d", set, get)
}
func TestLRUCache_Finalizer(t *testing.T) {
const (
capacity = 100
@@ -262,10 +318,6 @@ func TestLRUCache_Finalizer(t *testing.T) {
keymax = 8000
)
runtime.GOMAXPROCS(runtime.NumCPU())
defer runtime.GOMAXPROCS(1)
wg := &sync.WaitGroup{}
cnt := &testingCacheObjectCounter{}
c := NewLRUCache(capacity)
@@ -273,38 +325,40 @@ func TestLRUCache_Finalizer(t *testing.T) {
type instance struct {
seed int64
rnd *rand.Rand
ns uint64
effective int32
nsid uint64
ns Namespace
effective int
handles []Handle
handlesMap map[uint64]int
delete bool
purge bool
zap bool
wantDel int32
delfinCalledAll int32
delfinCalledEff int32
purgefinCalled int32
wantDel int
delfinCalled int
delfinCalledAll int
delfinCalledEff int
purgefinCalled int
}
instanceGet := func(p *instance, ns Namespace, key uint64) {
h := ns.Get(key, func() (charge int, value interface{}) {
instanceGet := func(p *instance, key uint64) {
h := p.ns.Get(key, func() (charge int, value interface{}) {
to := &testingCacheObject{
t: t, cnt: cnt,
ns: p.ns,
ns: p.nsid,
key: key,
}
atomic.AddInt32(&p.effective, 1)
p.effective++
cnt.createOne()
return 1, releaserFunc{func() {
to.Release()
atomic.AddInt32(&p.effective, -1)
p.effective--
}, to}
})
p.handles = append(p.handles, h)
p.handlesMap[key] = p.handlesMap[key] + 1
}
instanceRelease := func(p *instance, ns Namespace, i int) {
instanceRelease := func(p *instance, i int) {
h := p.handles[i]
key := h.Value().(releaserFunc).value.(*testingCacheObject).key
if n := p.handlesMap[key]; n == 0 {
@@ -319,55 +373,71 @@ func TestLRUCache_Finalizer(t *testing.T) {
p.handles[len(p.handles) : len(p.handles)+1][0] = nil
}
seeds := make([]int64, goroutines)
instances := make([]instance, goroutines)
seed := time.Now().UnixNano()
t.Logf("seed=%d", seed)
instances := make([]*instance, goroutines)
for i := range instances {
p := &instances[i]
p := &instance{}
p.handlesMap = make(map[uint64]int)
if seeds[i] == 0 {
seeds[i] = time.Now().UnixNano()
}
p.seed = seeds[i]
p.seed = seed + int64(i)
p.rnd = rand.New(rand.NewSource(p.seed))
p.ns = uint64(i)
p.nsid = uint64(i)
p.ns = c.GetNamespace(p.nsid)
p.delete = i%6 == 0
p.purge = i%8 == 0
p.zap = i%12 == 0 || i%3 == 0
instances[i] = p
}
seedsStr := make([]string, len(seeds))
for i, seed := range seeds {
seedsStr[i] = fmt.Sprint(seed)
}
t.Logf("seeds := []int64{%s}", strings.Join(seedsStr, ", "))
// Get and release.
for i := range instances {
p := &instances[i]
wg.Add(1)
go func(p *instance) {
defer wg.Done()
ns := c.GetNamespace(p.ns)
for i := 0; i < iterations; i++ {
if len(p.handles) == 0 || p.rnd.Int()%2 == 0 {
instanceGet(p, ns, uint64(p.rnd.Intn(keymax)))
} else {
instanceRelease(p, ns, p.rnd.Intn(len(p.handles)))
runr := rand.New(rand.NewSource(seed - 1))
run := func(rnd *rand.Rand, x []*instance, init func(p *instance) bool, fn func(p *instance, i int) bool) {
var (
rx []*instance
rn []int
)
if init == nil {
rx = append([]*instance{}, x...)
rn = make([]int, len(x))
} else {
for _, p := range x {
if init(p) {
rx = append(rx, p)
rn = append(rn, 0)
}
}
}(p)
}
for len(rx) > 0 {
i := rand.Intn(len(rx))
if fn(rx[i], rn[i]) {
rn[i]++
} else {
rx = append(rx[:i], rx[i+1:]...)
rn = append(rn[:i], rn[i+1:]...)
}
}
}
wg.Wait()
// Get and release.
run(runr, instances, nil, func(p *instance, i int) bool {
if i < iterations {
if len(p.handles) == 0 || p.rnd.Int()%2 == 0 {
instanceGet(p, uint64(p.rnd.Intn(keymax)))
} else {
instanceRelease(p, p.rnd.Intn(len(p.handles)))
}
return true
} else {
return false
}
})
if used, cap := c.Used(), c.Capacity(); used > cap {
t.Errorf("Used > capacity, used=%d cap=%d", used, cap)
}
// Check effective objects.
for i := range instances {
p := &instances[i]
for i, p := range instances {
if int(p.effective) < len(p.handlesMap) {
t.Errorf("#%d effective objects < acquired handle, eo=%d ah=%d", i, p.effective, len(p.handlesMap))
}
@@ -377,103 +447,93 @@ func TestLRUCache_Finalizer(t *testing.T) {
t.Errorf("Invalid cache size, want=%d got=%d", want, c.Size())
}
// Delete and purge.
for i := range instances {
p := &instances[i]
// First delete.
run(runr, instances, func(p *instance) bool {
p.wantDel = p.effective
wg.Add(1)
go func(p *instance) {
defer wg.Done()
ns := c.GetNamespace(p.ns)
if p.delete {
for key := uint64(0); key < keymax; key++ {
_, wantExist := p.handlesMap[key]
gotExist := ns.Delete(key, func(exist, pending bool) {
atomic.AddInt32(&p.delfinCalledAll, 1)
if exist {
atomic.AddInt32(&p.delfinCalledEff, 1)
}
})
if !gotExist && wantExist {
t.Errorf("delete on NS#%d KEY#%d not found", p.ns, key)
}
}
var delfinCalled int
for key := uint64(0); key < keymax; key++ {
func(key uint64) {
gotExist := ns.Delete(key, func(exist, pending bool) {
if exist && !pending {
t.Errorf("delete fin on NS#%d KEY#%d exist and not pending for deletion", p.ns, key)
}
delfinCalled++
})
if gotExist {
t.Errorf("delete on NS#%d KEY#%d found", p.ns, key)
}
}(key)
}
if delfinCalled != keymax {
t.Errorf("(2) #%d not all delete fin called, diff=%d", p.ns, keymax-delfinCalled)
return p.delete
}, func(p *instance, i int) bool {
key := uint64(i)
if key < keymax {
_, wantExist := p.handlesMap[key]
gotExist := p.ns.Delete(key, func(exist, pending bool) {
p.delfinCalledAll++
if exist {
p.delfinCalledEff++
}
})
if !gotExist && wantExist {
t.Errorf("delete on NS#%d KEY#%d not found", p.nsid, key)
}
return true
} else {
return false
}
})
if p.purge {
ns.Purge(func(ns, key uint64) {
atomic.AddInt32(&p.purgefinCalled, 1)
})
// Second delete.
run(runr, instances, func(p *instance) bool {
p.delfinCalled = 0
return p.delete
}, func(p *instance, i int) bool {
key := uint64(i)
if key < keymax {
gotExist := p.ns.Delete(key, func(exist, pending bool) {
if exist && !pending {
t.Errorf("delete fin on NS#%d KEY#%d exist and not pending for deletion", p.nsid, key)
}
p.delfinCalled++
})
if gotExist {
t.Errorf("delete on NS#%d KEY#%d found", p.nsid, key)
}
}(p)
}
wg.Wait()
return true
} else {
if p.delfinCalled != keymax {
t.Errorf("(2) #%d not all delete fin called, diff=%d", p.ns, keymax-p.delfinCalled)
}
return false
}
})
// Purge.
run(runr, instances, func(p *instance) bool {
return p.purge
}, func(p *instance, i int) bool {
p.ns.Purge(func(ns, key uint64) {
p.purgefinCalled++
})
return false
})
if want := int(cnt.created - cnt.released); c.Size() != want {
t.Errorf("Invalid cache size, want=%d got=%d", want, c.Size())
}
// Release.
for i := range instances {
p := &instances[i]
if !p.zap {
wg.Add(1)
go func(p *instance) {
defer wg.Done()
ns := c.GetNamespace(p.ns)
for i := len(p.handles) - 1; i >= 0; i-- {
instanceRelease(p, ns, i)
}
}(p)
run(runr, instances, func(p *instance) bool {
return !p.zap
}, func(p *instance, i int) bool {
if len(p.handles) > 0 {
instanceRelease(p, len(p.handles)-1)
return true
} else {
return false
}
}
wg.Wait()
})
if want := int(cnt.created - cnt.released); c.Size() != want {
t.Errorf("Invalid cache size, want=%d got=%d", want, c.Size())
}
// Zap.
for i := range instances {
p := &instances[i]
if p.zap {
wg.Add(1)
go func(p *instance) {
defer wg.Done()
ns := c.GetNamespace(p.ns)
ns.Zap()
p.handles = nil
p.handlesMap = nil
}(p)
}
}
wg.Wait()
run(runr, instances, func(p *instance) bool {
return p.zap
}, func(p *instance, i int) bool {
p.ns.Zap()
p.handles = nil
p.handlesMap = nil
return false
})
if want := int(cnt.created - cnt.released); c.Size() != want {
t.Errorf("Invalid cache size, want=%d got=%d", want, c.Size())
@@ -485,23 +545,21 @@ func TestLRUCache_Finalizer(t *testing.T) {
c.Purge(nil)
for i := range instances {
p := &instances[i]
for _, p := range instances {
if p.delete {
if p.delfinCalledAll != keymax {
t.Errorf("#%d not all delete fin called, purge=%v zap=%v diff=%d", p.ns, p.purge, p.zap, keymax-p.delfinCalledAll)
t.Errorf("#%d not all delete fin called, purge=%v zap=%v diff=%d", p.nsid, p.purge, p.zap, keymax-p.delfinCalledAll)
}
if p.delfinCalledEff != p.wantDel {
t.Errorf("#%d not all effective delete fin called, diff=%d", p.ns, p.wantDel-p.delfinCalledEff)
t.Errorf("#%d not all effective delete fin called, diff=%d", p.nsid, p.wantDel-p.delfinCalledEff)
}
if p.purge && p.purgefinCalled > 0 {
t.Errorf("#%d some purge fin called, delete=%v zap=%v n=%d", p.ns, p.delete, p.zap, p.purgefinCalled)
t.Errorf("#%d some purge fin called, delete=%v zap=%v n=%d", p.nsid, p.delete, p.zap, p.purgefinCalled)
}
} else {
if p.purge {
if p.purgefinCalled != p.wantDel {
t.Errorf("#%d not all purge fin called, delete=%v zap=%v diff=%d", p.ns, p.delete, p.zap, p.wantDel-p.purgefinCalled)
t.Errorf("#%d not all purge fin called, delete=%v zap=%v diff=%d", p.nsid, p.delete, p.zap, p.wantDel-p.purgefinCalled)
}
}
}

View File

@@ -124,6 +124,9 @@ func (c *lruCache) Zap() {
func (c *lruCache) evict() {
top := &c.recent
for n := c.recent.rPrev; c.used > c.capacity && n != top; {
if n.state != nodeEffective {
panic("evicting non effective node")
}
n.state = nodeEvicted
n.rRemove()
n.derefNB()
@@ -324,6 +327,10 @@ func (ns *lruNs) Get(key uint64, setf SetFunc) Handle {
// Bump to front.
n.rRemove()
n.rInsert(&ns.lru.recent)
case nodeDeleted:
// Do nothing.
default:
panic("invalid state")
}
n.ref++
@@ -472,8 +479,10 @@ func (n *lruNode) fin() {
r.Release()
}
if n.purgefin != nil {
if n.delfin != nil {
panic("conflicting delete and purge fin")
}
n.purgefin(n.ns.id, n.key)
n.delfin = nil
n.purgefin = nil
} else if n.delfin != nil {
n.delfin(true, false)

View File

@@ -7,6 +7,7 @@
package leveldb
import (
"container/list"
"errors"
"fmt"
"io"
@@ -46,7 +47,7 @@ type DB struct {
// Snapshot.
snapsMu sync.Mutex
snapsRoot snapshotElement
snapsList *list.List
// Stats.
aliveSnaps, aliveIters int32
@@ -85,6 +86,8 @@ func openDB(s *session) (*DB, error) {
seq: s.stSeq,
// MemDB
memPool: make(chan *memdb.DB, 1),
// Snapshot
snapsList: list.New(),
// Write
writeC: make(chan *Batch),
writeMergedC: make(chan bool),
@@ -103,7 +106,6 @@ func openDB(s *session) (*DB, error) {
// Close
closeC: make(chan struct{}),
}
db.initSnapshot()
if err := db.recoverJournal(); err != nil {
return nil, err
@@ -609,7 +611,9 @@ func (db *DB) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) {
return
}
return db.get(key, db.getSeq(), ro)
se := db.acquireSnapshot()
defer db.releaseSnapshot(se)
return db.get(key, se.seq, ro)
}
// NewIterator returns an iterator for the latest snapshot of the
@@ -633,9 +637,11 @@ func (db *DB) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Itera
return iterator.NewEmptyIterator(err)
}
snap := db.newSnapshot()
defer snap.Release()
return snap.NewIterator(slice, ro)
se := db.acquireSnapshot()
defer db.releaseSnapshot(se)
// Iterator holds 'version' lock, 'version' is immutable so snapshot
// can be released after iterator created.
return db.newIterator(se.seq, slice, ro)
}
// GetSnapshot returns a latest snapshot of the underlying DB. A snapshot
@@ -655,7 +661,7 @@ func (db *DB) GetSnapshot() (*Snapshot, error) {
//
// Property names:
// leveldb.num-files-at-level{n}
// Returns the number of filer at level 'n'.
// Returns the number of files at level 'n'.
// leveldb.stats
// Returns statistics of the underlying DB.
// leveldb.sstables
@@ -685,11 +691,12 @@ func (db *DB) GetProperty(name string) (value string, err error) {
v := db.s.version()
defer v.release()
numFilesPrefix := "num-files-at-level"
switch {
case strings.HasPrefix(p, "num-files-at-level"):
case strings.HasPrefix(p, numFilesPrefix):
var level uint
var rest string
n, _ := fmt.Scanf("%d%s", &level, &rest)
n, _ := fmt.Sscanf(p[len(numFilesPrefix):], "%d%s", &level, &rest)
if n != 1 || level >= kNumLevels {
err = errors.New("leveldb: GetProperty: invalid property: " + name)
} else {
@@ -796,12 +803,13 @@ func (db *DB) Close() error {
default:
}
// Signal all goroutines.
close(db.closeC)
// Wait for the close WaitGroup.
// Wait for all gorotines to exit.
db.closeW.Wait()
// Close journal.
// Lock writer and closes journal.
db.writeLockC <- struct{}{}
if db.journal != nil {
db.journal.Close()
@@ -827,7 +835,6 @@ func (db *DB) Close() error {
db.journalWriter = nil
db.journalFile = nil
db.frozenJournalFile = nil
db.snapsRoot = snapshotElement{}
db.closer = nil
return err

View File

@@ -260,7 +260,7 @@ func (db *DB) memCompaction() {
return c.commit(db.journalFile.Num(), db.frozenSeq)
}, nil)
db.logf("mem@flush commited F·%d T·%v", len(c.rec.addedTables), stats.duration)
db.logf("mem@flush committed F·%d T·%v", len(c.rec.addedTables), stats.duration)
for _, r := range c.rec.addedTables {
stats.write += r.size
@@ -478,7 +478,7 @@ func (db *DB) tableCompaction(c *compaction, noTrivial bool) {
}, nil)
resultSize := int(stats[1].write)
db.logf("table@compaction commited F%s S%s D·%d T·%v", sint(len(rec.addedTables)-len(rec.deletedTables)), sshortenb(resultSize-sourceSize), dropCnt, stats[1].duration)
db.logf("table@compaction committed F%s S%s D·%d T·%v", sint(len(rec.addedTables)-len(rec.deletedTables)), sshortenb(resultSize-sourceSize), dropCnt, stats[1].duration)
// Save compaction stats
for i := range stats {
@@ -538,6 +538,9 @@ type cIdle struct {
}
func (r cIdle) ack(err error) {
defer func() {
recover()
}()
r.ackC <- err
}
@@ -548,27 +551,33 @@ type cRange struct {
}
func (r cRange) ack(err error) {
defer func() {
recover()
}()
if r.ackC != nil {
defer func() {
recover()
}()
r.ackC <- err
}
}
func (db *DB) compSendIdle(compC chan<- cCmd) error {
func (db *DB) compSendIdle(compC chan<- cCmd) (err error) {
ch := make(chan error)
defer close(ch)
// Send cmd.
select {
case compC <- cIdle{ch}:
case err := <-db.compErrC:
return err
case err = <-db.compErrC:
return
case _, _ = <-db.closeC:
return ErrClosed
}
// Wait cmd.
return <-ch
select {
case err = <-ch:
case err = <-db.compErrC:
case _, _ = <-db.closeC:
return ErrClosed
}
return err
}
func (db *DB) compSendRange(compC chan<- cCmd, level int, min, max []byte) (err error) {
@@ -584,8 +593,10 @@ func (db *DB) compSendRange(compC chan<- cCmd, level int, min, max []byte) (err
}
// Wait cmd.
select {
case err = <-db.compErrC:
case err = <-ch:
case err = <-db.compErrC:
case _, _ = <-db.closeC:
return ErrClosed
}
return err
}

View File

@@ -48,8 +48,7 @@ func (db *DB) newRawIterator(slice *util.Range, ro *opt.ReadOptions) iterator.It
i = append(i, fmi)
}
i = append(i, ti...)
strict := db.s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator)
mi := iterator.NewMergedIterator(i, db.s.icmp, strict)
mi := iterator.NewMergedIterator(i, db.s.icmp, true)
mi.SetReleaser(&versionReleaser{v: v})
return mi
}
@@ -321,9 +320,13 @@ func (i *dbIter) Release() {
}
func (i *dbIter) SetReleaser(releaser util.Releaser) {
if i.dir != dirReleased {
i.releaser = releaser
if i.dir == dirReleased {
panic(util.ErrReleased)
}
if i.releaser != nil && releaser != nil {
panic(util.ErrHasReleaser)
}
i.releaser = releaser
}
func (i *dbIter) Error() error {

View File

@@ -7,6 +7,7 @@
package leveldb
import (
"container/list"
"runtime"
"sync"
"sync/atomic"
@@ -19,51 +20,41 @@ import (
type snapshotElement struct {
seq uint64
ref int
// Next and previous pointers in the doubly-linked list of elements.
next, prev *snapshotElement
}
// Initialize the snapshot.
func (db *DB) initSnapshot() {
db.snapsRoot.next = &db.snapsRoot
db.snapsRoot.prev = &db.snapsRoot
e *list.Element
}
// Acquires a snapshot, based on latest sequence.
func (db *DB) acquireSnapshot() *snapshotElement {
db.snapsMu.Lock()
defer db.snapsMu.Unlock()
seq := db.getSeq()
elem := db.snapsRoot.prev
if elem == &db.snapsRoot || elem.seq != seq {
at := db.snapsRoot.prev
next := at.next
elem = &snapshotElement{
seq: seq,
prev: at,
next: next,
if e := db.snapsList.Back(); e != nil {
se := e.Value.(*snapshotElement)
if se.seq == seq {
se.ref++
return se
} else if seq < se.seq {
panic("leveldb: sequence number is not increasing")
}
at.next = elem
next.prev = elem
}
elem.ref++
db.snapsMu.Unlock()
return elem
se := &snapshotElement{seq: seq, ref: 1}
se.e = db.snapsList.PushBack(se)
return se
}
// Releases given snapshot element.
func (db *DB) releaseSnapshot(elem *snapshotElement) {
if !db.isClosed() {
db.snapsMu.Lock()
elem.ref--
if elem.ref == 0 {
elem.prev.next = elem.next
elem.next.prev = elem.prev
elem.next = nil
elem.prev = nil
} else if elem.ref < 0 {
panic("leveldb: Snapshot: negative element reference")
}
db.snapsMu.Unlock()
func (db *DB) releaseSnapshot(se *snapshotElement) {
db.snapsMu.Lock()
defer db.snapsMu.Unlock()
se.ref--
if se.ref == 0 {
db.snapsList.Remove(se.e)
se.e = nil
} else if se.ref < 0 {
panic("leveldb: Snapshot: negative element reference")
}
}
@@ -71,10 +62,11 @@ func (db *DB) releaseSnapshot(elem *snapshotElement) {
func (db *DB) minSeq() uint64 {
db.snapsMu.Lock()
defer db.snapsMu.Unlock()
elem := db.snapsRoot.prev
if elem != &db.snapsRoot {
return elem.seq
if e := db.snapsList.Front(); e != nil {
return e.Value.(*snapshotElement).seq
}
return db.getSeq()
}

View File

@@ -7,6 +7,9 @@
package leveldb
import (
"container/list"
crand "crypto/rand"
"encoding/binary"
"fmt"
"math/rand"
"os"
@@ -1125,6 +1128,44 @@ func TestDb_Snapshot(t *testing.T) {
})
}
func TestDb_SnapshotList(t *testing.T) {
db := &DB{snapsList: list.New()}
e0a := db.acquireSnapshot()
e0b := db.acquireSnapshot()
db.seq = 1
e1 := db.acquireSnapshot()
db.seq = 2
e2 := db.acquireSnapshot()
if db.minSeq() != 0 {
t.Fatalf("invalid sequence number, got=%d", db.minSeq())
}
db.releaseSnapshot(e0a)
if db.minSeq() != 0 {
t.Fatalf("invalid sequence number, got=%d", db.minSeq())
}
db.releaseSnapshot(e2)
if db.minSeq() != 0 {
t.Fatalf("invalid sequence number, got=%d", db.minSeq())
}
db.releaseSnapshot(e0b)
if db.minSeq() != 1 {
t.Fatalf("invalid sequence number, got=%d", db.minSeq())
}
e2 = db.acquireSnapshot()
if db.minSeq() != 1 {
t.Fatalf("invalid sequence number, got=%d", db.minSeq())
}
db.releaseSnapshot(e1)
if db.minSeq() != 2 {
t.Fatalf("invalid sequence number, got=%d", db.minSeq())
}
db.releaseSnapshot(e2)
if db.minSeq() != 2 {
t.Fatalf("invalid sequence number, got=%d", db.minSeq())
}
}
func TestDb_HiddenValuesAreRemoved(t *testing.T) {
trun(t, func(h *dbHarness) {
s := h.db.s
@@ -1577,11 +1618,7 @@ func TestDb_BloomFilter(t *testing.T) {
return fmt.Sprintf("key%06d", i)
}
const (
n = 10000
indexOverhead = 19898
filterOverhead = 19799
)
const n = 10000
// Populate multiple layers
for i := 0; i < n; i++ {
@@ -1605,7 +1642,7 @@ func TestDb_BloomFilter(t *testing.T) {
cnt := int(h.stor.ReadCounter())
t.Logf("lookup of %d present keys yield %d sstable I/O reads", n, cnt)
if min, max := n+indexOverhead+filterOverhead, n+indexOverhead+filterOverhead+2*n/100; cnt < min || cnt > max {
if min, max := n, n+2*n/100; cnt < min || cnt > max {
t.Errorf("num of sstable I/O reads of present keys not in range of %d - %d, got %d", min, max, cnt)
}
@@ -1616,7 +1653,7 @@ func TestDb_BloomFilter(t *testing.T) {
}
cnt = int(h.stor.ReadCounter())
t.Logf("lookup of %d missing keys yield %d sstable I/O reads", n, cnt)
if max := 3*n/100 + indexOverhead + filterOverhead; cnt > max {
if max := 3 * n / 100; cnt > max {
t.Errorf("num of sstable I/O reads of missing keys was more than %d, got %d", max, cnt)
}
@@ -1888,3 +1925,244 @@ func TestDb_LeveldbIssue200(t *testing.T) {
iter.Next()
assertBytes(t, []byte("5"), iter.Key())
}
func TestDb_GoleveldbIssue74(t *testing.T) {
h := newDbHarnessWopt(t, &opt.Options{
WriteBuffer: 1 * opt.MiB,
})
defer h.close()
const n, dur = 10000, 5 * time.Second
runtime.GOMAXPROCS(runtime.NumCPU())
until := time.Now().Add(dur)
wg := new(sync.WaitGroup)
wg.Add(2)
var done uint32
go func() {
var i int
defer func() {
t.Logf("WRITER DONE #%d", i)
atomic.StoreUint32(&done, 1)
wg.Done()
}()
b := new(Batch)
for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
iv := fmt.Sprintf("VAL%010d", i)
for k := 0; k < n; k++ {
key := fmt.Sprintf("KEY%06d", k)
b.Put([]byte(key), []byte(key+iv))
b.Put([]byte(fmt.Sprintf("PTR%06d", k)), []byte(key))
}
h.write(b)
b.Reset()
snap := h.getSnapshot()
iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil)
var k int
for ; iter.Next(); k++ {
ptrKey := iter.Key()
key := iter.Value()
if _, err := snap.Get(ptrKey, nil); err != nil {
t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, ptrKey, err)
}
if value, err := snap.Get(key, nil); err != nil {
t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, key, err)
} else if string(value) != string(key)+iv {
t.Fatalf("WRITER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+iv, value)
}
b.Delete(key)
b.Delete(ptrKey)
}
h.write(b)
iter.Release()
snap.Release()
if k != n {
t.Fatalf("#%d %d != %d", i, k, n)
}
}
}()
go func() {
var i int
defer func() {
t.Logf("READER DONE #%d", i)
atomic.StoreUint32(&done, 1)
wg.Done()
}()
for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
snap := h.getSnapshot()
iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil)
var prevValue string
var k int
for ; iter.Next(); k++ {
ptrKey := iter.Key()
key := iter.Value()
if _, err := snap.Get(ptrKey, nil); err != nil {
t.Fatalf("READER #%d snapshot.Get %q: %v", i, ptrKey, err)
}
if value, err := snap.Get(key, nil); err != nil {
t.Fatalf("READER #%d snapshot.Get %q: %v", i, key, err)
} else if prevValue != "" && string(value) != string(key)+prevValue {
t.Fatalf("READER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+prevValue, value)
} else {
prevValue = string(value[len(key):])
}
}
iter.Release()
snap.Release()
if k > 0 && k != n {
t.Fatalf("#%d %d != %d", i, k, n)
}
}
}()
wg.Wait()
}
func TestDb_GetProperties(t *testing.T) {
h := newDbHarness(t)
defer h.close()
_, err := h.db.GetProperty("leveldb.num-files-at-level")
if err == nil {
t.Error("GetProperty() failed to detect missing level")
}
_, err = h.db.GetProperty("leveldb.num-files-at-level0")
if err != nil {
t.Error("got unexpected error", err)
}
_, err = h.db.GetProperty("leveldb.num-files-at-level0x")
if err == nil {
t.Error("GetProperty() failed to detect invalid level")
}
}
func TestDb_GoleveldbIssue72and83(t *testing.T) {
h := newDbHarnessWopt(t, &opt.Options{
WriteBuffer: 1 * opt.MiB,
CachedOpenFiles: 3,
})
defer h.close()
const n, wn, dur = 10000, 100, 30 * time.Second
runtime.GOMAXPROCS(runtime.NumCPU())
randomData := func(prefix byte, i int) []byte {
data := make([]byte, 1+4+32+64+32)
_, err := crand.Reader.Read(data[1 : len(data)-4])
if err != nil {
panic(err)
}
data[0] = prefix
binary.LittleEndian.PutUint32(data[len(data)-4:], uint32(i))
return data
}
keys := make([][]byte, n)
for i := range keys {
keys[i] = randomData(1, 0)
}
until := time.Now().Add(dur)
wg := new(sync.WaitGroup)
wg.Add(3)
var done uint32
go func() {
i := 0
defer func() {
t.Logf("WRITER DONE #%d", i)
wg.Done()
}()
b := new(Batch)
for ; i < wn && atomic.LoadUint32(&done) == 0; i++ {
b.Reset()
for _, k1 := range keys {
k2 := randomData(2, i)
b.Put(k2, randomData(42, i))
b.Put(k1, k2)
}
if err := h.db.Write(b, h.wo); err != nil {
atomic.StoreUint32(&done, 1)
t.Fatalf("WRITER #%d db.Write: %v", i, err)
}
}
}()
go func() {
var i int
defer func() {
t.Logf("READER0 DONE #%d", i)
atomic.StoreUint32(&done, 1)
wg.Done()
}()
for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
snap := h.getSnapshot()
seq := snap.elem.seq
if seq == 0 {
snap.Release()
continue
}
iter := snap.NewIterator(util.BytesPrefix([]byte{1}), nil)
writei := int(snap.elem.seq/(n*2) - 1)
var k int
for ; iter.Next(); k++ {
k1 := iter.Key()
k2 := iter.Value()
kwritei := int(binary.LittleEndian.Uint32(k2[len(k2)-4:]))
if writei != kwritei {
t.Fatalf("READER0 #%d.%d W#%d invalid write iteration num: %d", i, k, writei, kwritei)
}
if _, err := snap.Get(k2, nil); err != nil {
t.Fatalf("READER0 #%d.%d W#%d snap.Get: %v\nk1: %x\n -> k2: %x", i, k, writei, err, k1, k2)
}
}
if err := iter.Error(); err != nil {
t.Fatalf("READER0 #%d.%d W#%d snap.Iterator: %v", i, k, err)
}
iter.Release()
snap.Release()
if k > 0 && k != n {
t.Fatalf("READER0 #%d W#%d short read, got=%d want=%d", i, writei, k, n)
}
}
}()
go func() {
var i int
defer func() {
t.Logf("READER1 DONE #%d", i)
atomic.StoreUint32(&done, 1)
wg.Done()
}()
for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
iter := h.db.NewIterator(nil, nil)
seq := iter.(*dbIter).seq
if seq == 0 {
iter.Release()
continue
}
writei := int(seq/(n*2) - 1)
var k int
for ok := iter.Last(); ok; ok = iter.Prev() {
k++
}
if err := iter.Error(); err != nil {
t.Fatalf("READER1 #%d.%d W#%d db.Iterator: %v", i, k, writei, err)
}
iter.Release()
if m := (writei+1)*n + n; k != m {
t.Fatalf("READER1 #%d W#%d short read, got=%d want=%d", i, writei, k, m)
}
}
}()
wg.Wait()
}

View File

@@ -127,21 +127,24 @@ func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) {
b.init(wo.GetSync())
// The write happen synchronously.
retry:
select {
case db.writeC <- b:
if <-db.writeMergedC {
return <-db.writeAckC
}
goto retry
case db.writeLockC <- struct{}{}:
case _, _ = <-db.closeC:
return ErrClosed
}
merged := 0
danglingMerge := false
defer func() {
<-db.writeLockC
if danglingMerge {
db.writeMergedC <- false
} else {
<-db.writeLockC
}
for i := 0; i < merged; i++ {
db.writeAckC <- err
}
@@ -170,7 +173,7 @@ drain:
db.writeMergedC <- true
merged++
} else {
db.writeMergedC <- false
danglingMerge = true
break drain
}
default:
@@ -262,6 +265,7 @@ func (db *DB) CompactRange(r util.Range) error {
return err
}
// Lock writer.
select {
case db.writeLockC <- struct{}{}:
case _, _ = <-db.closeC:

View File

@@ -40,13 +40,19 @@ type basicArrayIterator struct {
util.BasicReleaser
array BasicArray
pos int
err error
}
func (i *basicArrayIterator) Valid() bool {
return i.pos >= 0 && i.pos < i.array.Len()
return i.pos >= 0 && i.pos < i.array.Len() && !i.Released()
}
func (i *basicArrayIterator) First() bool {
if i.Released() {
i.err = ErrIterReleased
return false
}
if i.array.Len() == 0 {
i.pos = -1
return false
@@ -56,6 +62,11 @@ func (i *basicArrayIterator) First() bool {
}
func (i *basicArrayIterator) Last() bool {
if i.Released() {
i.err = ErrIterReleased
return false
}
n := i.array.Len()
if n == 0 {
i.pos = 0
@@ -66,6 +77,11 @@ func (i *basicArrayIterator) Last() bool {
}
func (i *basicArrayIterator) Seek(key []byte) bool {
if i.Released() {
i.err = ErrIterReleased
return false
}
n := i.array.Len()
if n == 0 {
i.pos = 0
@@ -79,6 +95,11 @@ func (i *basicArrayIterator) Seek(key []byte) bool {
}
func (i *basicArrayIterator) Next() bool {
if i.Released() {
i.err = ErrIterReleased
return false
}
i.pos++
if n := i.array.Len(); i.pos >= n {
i.pos = n
@@ -88,6 +109,11 @@ func (i *basicArrayIterator) Next() bool {
}
func (i *basicArrayIterator) Prev() bool {
if i.Released() {
i.err = ErrIterReleased
return false
}
i.pos--
if i.pos < 0 {
i.pos = -1
@@ -96,7 +122,7 @@ func (i *basicArrayIterator) Prev() bool {
return true
}
func (i *basicArrayIterator) Error() error { return nil }
func (i *basicArrayIterator) Error() error { return i.err }
type arrayIterator struct {
basicArrayIterator

View File

@@ -26,9 +26,10 @@ type indexedIterator struct {
strict bool
strictGet bool
data Iterator
err error
errf func(err error)
data Iterator
err error
errf func(err error)
closed bool
}
func (i *indexedIterator) setData() {
@@ -50,6 +51,15 @@ func (i *indexedIterator) clearData() {
i.data = nil
}
func (i *indexedIterator) indexErr() {
if err := i.index.Error(); err != nil {
if i.errf != nil {
i.errf(err)
}
i.err = err
}
}
func (i *indexedIterator) dataErr() bool {
if i.errf != nil {
if err := i.data.Error(); err != nil {
@@ -72,9 +82,13 @@ func (i *indexedIterator) Valid() bool {
func (i *indexedIterator) First() bool {
if i.err != nil {
return false
} else if i.Released() {
i.err = ErrIterReleased
return false
}
if !i.index.First() {
i.indexErr()
i.clearData()
return false
}
@@ -85,9 +99,13 @@ func (i *indexedIterator) First() bool {
func (i *indexedIterator) Last() bool {
if i.err != nil {
return false
} else if i.Released() {
i.err = ErrIterReleased
return false
}
if !i.index.Last() {
i.indexErr()
i.clearData()
return false
}
@@ -105,9 +123,13 @@ func (i *indexedIterator) Last() bool {
func (i *indexedIterator) Seek(key []byte) bool {
if i.err != nil {
return false
} else if i.Released() {
i.err = ErrIterReleased
return false
}
if !i.index.Seek(key) {
i.indexErr()
i.clearData()
return false
}
@@ -125,6 +147,9 @@ func (i *indexedIterator) Seek(key []byte) bool {
func (i *indexedIterator) Next() bool {
if i.err != nil {
return false
} else if i.Released() {
i.err = ErrIterReleased
return false
}
switch {
@@ -136,6 +161,7 @@ func (i *indexedIterator) Next() bool {
fallthrough
case i.data == nil:
if !i.index.Next() {
i.indexErr()
return false
}
i.setData()
@@ -147,6 +173,9 @@ func (i *indexedIterator) Next() bool {
func (i *indexedIterator) Prev() bool {
if i.err != nil {
return false
} else if i.Released() {
i.err = ErrIterReleased
return false
}
switch {
@@ -158,6 +187,7 @@ func (i *indexedIterator) Prev() bool {
fallthrough
case i.data == nil:
if !i.index.Prev() {
i.indexErr()
return false
}
i.setData()

View File

@@ -14,6 +14,10 @@ import (
"github.com/syndtr/goleveldb/leveldb/util"
)
var (
ErrIterReleased = errors.New("leveldb/iterator: iterator released")
)
// IteratorSeeker is the interface that wraps the 'seeks method'.
type IteratorSeeker interface {
// First moves the iterator to the first key/value pair. If the iterator
@@ -100,28 +104,13 @@ type ErrorCallbackSetter interface {
}
type emptyIterator struct {
releaser util.Releaser
released bool
err error
util.BasicReleaser
err error
}
func (i *emptyIterator) rErr() {
if i.err == nil && i.released {
i.err = errors.New("leveldb/iterator: iterator released")
}
}
func (i *emptyIterator) Release() {
if i.releaser != nil {
i.releaser.Release()
i.releaser = nil
}
i.released = true
}
func (i *emptyIterator) SetReleaser(releaser util.Releaser) {
if !i.released {
i.releaser = releaser
if i.err == nil && i.Released() {
i.err = ErrIterReleased
}
}

View File

@@ -7,16 +7,10 @@
package iterator
import (
"errors"
"github.com/syndtr/goleveldb/leveldb/comparer"
"github.com/syndtr/goleveldb/leveldb/util"
)
var (
ErrIterReleased = errors.New("leveldb/iterator: iterator released")
)
type dir int
const (
@@ -274,9 +268,13 @@ func (i *mergedIterator) Release() {
}
func (i *mergedIterator) SetReleaser(releaser util.Releaser) {
if i.dir != dirReleased {
i.releaser = releaser
if i.dir == dirReleased {
panic(util.ErrReleased)
}
if i.releaser != nil && releaser != nil {
panic(util.ErrHasReleaser)
}
i.releaser = releaser
}
func (i *mergedIterator) Error() error {

View File

@@ -8,6 +8,7 @@
package memdb
import (
"errors"
"math/rand"
"sync"
@@ -17,7 +18,8 @@ import (
)
var (
ErrNotFound = util.ErrNotFound
ErrNotFound = util.ErrNotFound
ErrIterReleased = errors.New("leveldb/memdb: iterator released")
)
const tMaxHeight = 12
@@ -29,6 +31,7 @@ type dbIter struct {
node int
forward bool
key, value []byte
err error
}
func (i *dbIter) fill(checkStart, checkLimit bool) bool {
@@ -59,6 +62,11 @@ func (i *dbIter) Valid() bool {
}
func (i *dbIter) First() bool {
if i.Released() {
i.err = ErrIterReleased
return false
}
i.forward = true
i.p.mu.RLock()
defer i.p.mu.RUnlock()
@@ -71,9 +79,11 @@ func (i *dbIter) First() bool {
}
func (i *dbIter) Last() bool {
if i.p == nil {
if i.Released() {
i.err = ErrIterReleased
return false
}
i.forward = false
i.p.mu.RLock()
defer i.p.mu.RUnlock()
@@ -86,9 +96,11 @@ func (i *dbIter) Last() bool {
}
func (i *dbIter) Seek(key []byte) bool {
if i.p == nil {
if i.Released() {
i.err = ErrIterReleased
return false
}
i.forward = true
i.p.mu.RLock()
defer i.p.mu.RUnlock()
@@ -100,9 +112,11 @@ func (i *dbIter) Seek(key []byte) bool {
}
func (i *dbIter) Next() bool {
if i.p == nil {
if i.Released() {
i.err = ErrIterReleased
return false
}
if i.node == 0 {
if !i.forward {
return i.First()
@@ -117,9 +131,11 @@ func (i *dbIter) Next() bool {
}
func (i *dbIter) Prev() bool {
if i.p == nil {
if i.Released() {
i.err = ErrIterReleased
return false
}
if i.node == 0 {
if i.forward {
return i.Last()
@@ -141,10 +157,10 @@ func (i *dbIter) Value() []byte {
return i.value
}
func (i *dbIter) Error() error { return nil }
func (i *dbIter) Error() error { return i.err }
func (i *dbIter) Release() {
if i.p != nil {
if !i.Released() {
i.p = nil
i.node = 0
i.key = nil

View File

@@ -92,7 +92,7 @@ const (
// DefaultStrict is the default strict flags. Specify any strict flags
// will override default strict flags as whole (i.e. not OR'ed).
DefaultStrict = StrictJournalChecksum | StrictBlockChecksum
DefaultStrict = StrictJournalChecksum | StrictIterator | StrictBlockChecksum
// NoStrict disables all strict flags. Override default strict flags.
NoStrict = ^StrictAll

View File

@@ -147,7 +147,7 @@ func (s *session) fillRecord(r *sessionRecord, snapshot bool) {
}
}
// Mark if record has been commited, this will update session state;
// Mark if record has been committed, this will update session state;
// need external synchronization.
func (s *session) recordCommited(r *sessionRecord) {
if r.has(recJournalNum) {

View File

@@ -28,11 +28,12 @@ var (
)
var (
tsFSEnv = os.Getenv("GOLEVELDB_USEFS")
tsKeepFS = tsFSEnv == "2"
tsFS = tsKeepFS || tsFSEnv == "" || tsFSEnv == "1"
tsMU = &sync.Mutex{}
tsNum = 0
tsFSEnv = os.Getenv("GOLEVELDB_USEFS")
tsTempdir = os.Getenv("GOLEVELDB_TEMPDIR")
tsKeepFS = tsFSEnv == "2"
tsFS = tsKeepFS || tsFSEnv == "" || tsFSEnv == "1"
tsMU = &sync.Mutex{}
tsNum = 0
)
type tsLock struct {
@@ -413,7 +414,11 @@ func newTestStorage(t *testing.T) *testStorage {
num := tsNum
tsNum++
tsMU.Unlock()
path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
tempdir := tsTempdir
if tempdir == "" {
tempdir = os.TempDir()
}
path := filepath.Join(tempdir, fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
if _, err := os.Stat(path); err != nil {
stor, err = storage.OpenFile(path)
if err != nil {

View File

@@ -19,13 +19,18 @@ import (
"github.com/syndtr/goleveldb/leveldb/util"
)
func (b *block) TestNewIterator(slice *util.Range) iterator.Iterator {
return b.newIterator(slice, false, nil)
type blockTesting struct {
tr *Reader
b *block
}
func (t *blockTesting) TestNewIterator(slice *util.Range) iterator.Iterator {
return t.tr.newBlockIter(t.b, nil, slice, false)
}
var _ = testutil.Defer(func() {
Describe("Block", func() {
Build := func(kv *testutil.KeyValue, restartInterval int) *block {
Build := func(kv *testutil.KeyValue, restartInterval int) *blockTesting {
// Building the block.
bw := &blockWriter{
restartInterval: restartInterval,
@@ -39,11 +44,13 @@ var _ = testutil.Defer(func() {
// Opening the block.
data := bw.buf.Bytes()
restartsLen := int(binary.LittleEndian.Uint32(data[len(data)-4:]))
return &block{
tr: &Reader{cmp: comparer.DefaultComparer},
data: data,
restartsLen: restartsLen,
restartsOffset: len(data) - (restartsLen+1)*4,
return &blockTesting{
tr: &Reader{cmp: comparer.DefaultComparer},
b: &block{
data: data,
restartsLen: restartsLen,
restartsOffset: len(data) - (restartsLen+1)*4,
},
}
}
@@ -102,11 +109,11 @@ var _ = testutil.Defer(func() {
for restartInterval := 1; restartInterval <= 5; restartInterval++ {
Describe(fmt.Sprintf("with restart interval of %d", restartInterval), func() {
// Make block.
br := Build(kv, restartInterval)
bt := Build(kv, restartInterval)
Test := func(r *util.Range) func(done Done) {
return func(done Done) {
iter := br.newIterator(r, false, nil)
iter := bt.TestNewIterator(r)
Expect(iter.Error()).ShouldNot(HaveOccurred())
t := testutil.IteratorTesting{

View File

@@ -13,6 +13,7 @@ import (
"io"
"sort"
"strings"
"sync"
"code.google.com/p/snappy-go/snappy"
@@ -25,8 +26,9 @@ import (
)
var (
ErrNotFound = util.ErrNotFound
ErrIterReleased = errors.New("leveldb/table: iterator released")
ErrNotFound = util.ErrNotFound
ErrReaderReleased = errors.New("leveldb/table: reader released")
ErrIterReleased = errors.New("leveldb/table: iterator released")
)
func max(x, y int) int {
@@ -37,7 +39,7 @@ func max(x, y int) int {
}
type block struct {
tr *Reader
bpool *util.BufferPool
data []byte
restartsLen int
restartsOffset int
@@ -45,14 +47,14 @@ type block struct {
checksum bool
}
func (b *block) seek(rstart, rlimit int, key []byte) (index, offset int, err error) {
func (b *block) seek(cmp comparer.Comparer, rstart, rlimit int, key []byte) (index, offset int, err error) {
index = sort.Search(b.restartsLen-rstart-(b.restartsLen-rlimit), func(i int) bool {
offset := int(binary.LittleEndian.Uint32(b.data[b.restartsOffset+4*(rstart+i):]))
offset += 1 // shared always zero, since this is a restart point
v1, n1 := binary.Uvarint(b.data[offset:]) // key length
_, n2 := binary.Uvarint(b.data[offset+n1:]) // value length
m := offset + n1 + n2
return b.tr.cmp.Compare(b.data[m:m+int(v1)], key) > 0
return cmp.Compare(b.data[m:m+int(v1)], key) > 0
}) + rstart - 1
if index < rstart {
// The smallest key is greater-than key sought.
@@ -94,50 +96,9 @@ func (b *block) entry(offset int) (key, value []byte, nShared, n int, err error)
return
}
func (b *block) newIterator(slice *util.Range, inclLimit bool, cache util.Releaser) *blockIter {
bi := &blockIter{
block: b,
cache: cache,
// Valid key should never be nil.
key: make([]byte, 0),
dir: dirSOI,
riStart: 0,
riLimit: b.restartsLen,
offsetStart: 0,
offsetRealStart: 0,
offsetLimit: b.restartsOffset,
}
if slice != nil {
if slice.Start != nil {
if bi.Seek(slice.Start) {
bi.riStart = b.restartIndex(bi.restartIndex, b.restartsLen, bi.prevOffset)
bi.offsetStart = b.restartOffset(bi.riStart)
bi.offsetRealStart = bi.prevOffset
} else {
bi.riStart = b.restartsLen
bi.offsetStart = b.restartsOffset
bi.offsetRealStart = b.restartsOffset
}
}
if slice.Limit != nil {
if bi.Seek(slice.Limit) && (!inclLimit || bi.Next()) {
bi.offsetLimit = bi.prevOffset
bi.riLimit = bi.restartIndex + 1
}
}
bi.reset()
if bi.offsetStart > bi.offsetLimit {
bi.sErr(errors.New("leveldb/table: Reader: invalid slice range"))
}
}
return bi
}
func (b *block) Release() {
if b.tr.bpool != nil {
b.tr.bpool.Put(b.data)
}
b.tr = nil
b.bpool.Put(b.data)
b.bpool = nil
b.data = nil
}
@@ -152,10 +113,12 @@ const (
)
type blockIter struct {
block *block
cache, releaser util.Releaser
key, value []byte
offset int
tr *Reader
block *block
blockReleaser util.Releaser
releaser util.Releaser
key, value []byte
offset int
// Previous offset, only filled by Next.
prevOffset int
prevNode []int
@@ -252,7 +215,7 @@ func (i *blockIter) Seek(key []byte) bool {
return false
}
ri, offset, err := i.block.seek(i.riStart, i.riLimit, key)
ri, offset, err := i.block.seek(i.tr.cmp, i.riStart, i.riLimit, key)
if err != nil {
i.sErr(err)
return false
@@ -263,7 +226,7 @@ func (i *blockIter) Seek(key []byte) bool {
i.dir = dirForward
}
for i.Next() {
if i.block.tr.cmp.Compare(i.key, key) >= 0 {
if i.tr.cmp.Compare(i.key, key) >= 0 {
return true
}
}
@@ -439,16 +402,17 @@ func (i *blockIter) Value() []byte {
}
func (i *blockIter) Release() {
if i.dir > dirReleased {
if i.dir != dirReleased {
i.tr = nil
i.block = nil
i.prevNode = nil
i.prevKeys = nil
i.key = nil
i.value = nil
i.dir = dirReleased
if i.cache != nil {
i.cache.Release()
i.cache = nil
if i.blockReleaser != nil {
i.blockReleaser.Release()
i.blockReleaser = nil
}
if i.releaser != nil {
i.releaser.Release()
@@ -458,9 +422,13 @@ func (i *blockIter) Release() {
}
func (i *blockIter) SetReleaser(releaser util.Releaser) {
if i.dir > dirReleased {
i.releaser = releaser
if i.dir == dirReleased {
panic(util.ErrReleased)
}
if i.releaser != nil && releaser != nil {
panic(util.ErrHasReleaser)
}
i.releaser = releaser
}
func (i *blockIter) Valid() bool {
@@ -472,21 +440,21 @@ func (i *blockIter) Error() error {
}
type filterBlock struct {
tr *Reader
bpool *util.BufferPool
data []byte
oOffset int
baseLg uint
filtersNum int
}
func (b *filterBlock) contains(offset uint64, key []byte) bool {
func (b *filterBlock) contains(filter filter.Filter, offset uint64, key []byte) bool {
i := int(offset >> b.baseLg)
if i < b.filtersNum {
o := b.data[b.oOffset+i*4:]
n := int(binary.LittleEndian.Uint32(o))
m := int(binary.LittleEndian.Uint32(o[4:]))
if n < m && m <= b.oOffset {
return b.tr.filter.Contains(b.data[n:m], key)
return filter.Contains(b.data[n:m], key)
} else if n == m {
return false
}
@@ -495,15 +463,14 @@ func (b *filterBlock) contains(offset uint64, key []byte) bool {
}
func (b *filterBlock) Release() {
if b.tr.bpool != nil {
b.tr.bpool.Put(b.data)
}
b.tr = nil
b.bpool.Put(b.data)
b.bpool = nil
b.data = nil
}
type indexIter struct {
*blockIter
tr *Reader
slice *util.Range
// Options
checksum bool
@@ -519,15 +486,17 @@ func (i *indexIter) Get() iterator.Iterator {
if n == 0 {
return iterator.NewEmptyIterator(errors.New("leveldb/table: Reader: invalid table (bad data block handle)"))
}
var slice *util.Range
if i.slice != nil && (i.blockIter.isFirst() || i.blockIter.isLast()) {
slice = i.slice
}
return i.blockIter.block.tr.getDataIter(dataBH, slice, i.checksum, i.fillCache)
return i.tr.getDataIterErr(dataBH, slice, i.checksum, i.fillCache)
}
// Reader is a table reader.
type Reader struct {
mu sync.RWMutex
reader io.ReaderAt
cache cache.Namespace
err error
@@ -540,6 +509,8 @@ type Reader struct {
dataEnd int64
indexBH, filterBH blockHandle
indexBlock *block
filterBlock *filterBlock
}
func verifyChecksum(data []byte) bool {
@@ -588,7 +559,7 @@ func (r *Reader) readBlock(bh blockHandle, checksum bool) (*block, error) {
}
restartsLen := int(binary.LittleEndian.Uint32(data[len(data)-4:]))
b := &block{
tr: r,
bpool: r.bpool,
data: data,
restartsLen: restartsLen,
restartsOffset: len(data) - (restartsLen+1)*4,
@@ -649,7 +620,7 @@ func (r *Reader) readFilterBlock(bh blockHandle) (*filterBlock, error) {
return nil, errors.New("leveldb/table: Reader: invalid filter block (invalid offset)")
}
b := &filterBlock{
tr: r,
bpool: r.bpool,
data: data,
oOffset: oOffset,
baseLg: uint(data[n-1]),
@@ -688,12 +659,77 @@ func (r *Reader) readFilterBlockCached(bh blockHandle, fillCache bool) (*filterB
return b, b, err
}
func (r *Reader) getIndexBlock(fillCache bool) (b *block, rel util.Releaser, err error) {
if r.indexBlock == nil {
return r.readBlockCached(r.indexBH, true, fillCache)
}
return r.indexBlock, util.NoopReleaser{}, nil
}
func (r *Reader) getFilterBlock(fillCache bool) (*filterBlock, util.Releaser, error) {
if r.filterBlock == nil {
return r.readFilterBlockCached(r.filterBH, fillCache)
}
return r.filterBlock, util.NoopReleaser{}, nil
}
func (r *Reader) getDataIter(dataBH blockHandle, slice *util.Range, checksum, fillCache bool) iterator.Iterator {
b, rel, err := r.readBlockCached(dataBH, checksum, fillCache)
if err != nil {
return iterator.NewEmptyIterator(err)
}
return b.newIterator(slice, false, rel)
return r.newBlockIter(b, rel, slice, false)
}
func (r *Reader) getDataIterErr(dataBH blockHandle, slice *util.Range, checksum, fillCache bool) iterator.Iterator {
r.mu.RLock()
defer r.mu.RUnlock()
if r.err != nil {
return iterator.NewEmptyIterator(r.err)
}
return r.getDataIter(dataBH, slice, checksum, fillCache)
}
func (r *Reader) newBlockIter(b *block, bReleaser util.Releaser, slice *util.Range, inclLimit bool) *blockIter {
bi := &blockIter{
tr: r,
block: b,
blockReleaser: bReleaser,
// Valid key should never be nil.
key: make([]byte, 0),
dir: dirSOI,
riStart: 0,
riLimit: b.restartsLen,
offsetStart: 0,
offsetRealStart: 0,
offsetLimit: b.restartsOffset,
}
if slice != nil {
if slice.Start != nil {
if bi.Seek(slice.Start) {
bi.riStart = b.restartIndex(bi.restartIndex, b.restartsLen, bi.prevOffset)
bi.offsetStart = b.restartOffset(bi.riStart)
bi.offsetRealStart = bi.prevOffset
} else {
bi.riStart = b.restartsLen
bi.offsetStart = b.restartsOffset
bi.offsetRealStart = b.restartsOffset
}
}
if slice.Limit != nil {
if bi.Seek(slice.Limit) && (!inclLimit || bi.Next()) {
bi.offsetLimit = bi.prevOffset
bi.riLimit = bi.restartIndex + 1
}
}
bi.reset()
if bi.offsetStart > bi.offsetLimit {
bi.sErr(errors.New("leveldb/table: Reader: invalid slice range"))
}
}
return bi
}
// NewIterator creates an iterator from the table.
@@ -708,22 +744,26 @@ func (r *Reader) getDataIter(dataBH blockHandle, slice *util.Range, checksum, fi
//
// Also read Iterator documentation of the leveldb/iterator package.
func (r *Reader) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
r.mu.RLock()
defer r.mu.RUnlock()
if r.err != nil {
return iterator.NewEmptyIterator(r.err)
}
fillCache := !ro.GetDontFillCache()
b, rel, err := r.readBlockCached(r.indexBH, true, fillCache)
indexBlock, rel, err := r.getIndexBlock(fillCache)
if err != nil {
return iterator.NewEmptyIterator(err)
}
index := &indexIter{
blockIter: b.newIterator(slice, true, rel),
blockIter: r.newBlockIter(indexBlock, rel, slice, true),
tr: r,
slice: slice,
checksum: ro.GetStrict(opt.StrictBlockChecksum),
fillCache: !ro.GetDontFillCache(),
}
return iterator.NewIndexedIterator(index, r.strictIter || ro.GetStrict(opt.StrictIterator), false)
return iterator.NewIndexedIterator(index, r.strictIter || ro.GetStrict(opt.StrictIterator), true)
}
// Find finds key/value pair whose key is greater than or equal to the
@@ -733,18 +773,21 @@ func (r *Reader) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.It
// The caller should not modify the contents of the returned slice, but
// it is safe to modify the contents of the argument after Find returns.
func (r *Reader) Find(key []byte, ro *opt.ReadOptions) (rkey, value []byte, err error) {
r.mu.RLock()
defer r.mu.RUnlock()
if r.err != nil {
err = r.err
return
}
indexBlock, rel, err := r.readBlockCached(r.indexBH, true, true)
indexBlock, rel, err := r.getIndexBlock(true)
if err != nil {
return
}
defer rel.Release()
index := indexBlock.newIterator(nil, true, nil)
index := r.newBlockIter(indexBlock, nil, nil, true)
defer index.Release()
if !index.Seek(key) {
err = index.Error()
@@ -759,9 +802,9 @@ func (r *Reader) Find(key []byte, ro *opt.ReadOptions) (rkey, value []byte, err
return
}
if r.filter != nil {
filterBlock, rel, ferr := r.readFilterBlockCached(r.filterBH, true)
filterBlock, rel, ferr := r.getFilterBlock(true)
if ferr == nil {
if !filterBlock.contains(dataBH.offset, key) {
if !filterBlock.contains(r.filter, dataBH.offset, key) {
rel.Release()
return nil, nil, ErrNotFound
}
@@ -779,9 +822,13 @@ func (r *Reader) Find(key []byte, ro *opt.ReadOptions) (rkey, value []byte, err
}
// Don't use block buffer, no need to copy the buffer.
rkey = data.Key()
// Use block buffer, and since the buffer will be recycled, the buffer
// need to be copied.
value = append([]byte{}, data.Value()...)
if r.bpool == nil {
value = data.Value()
} else {
// Use block buffer, and since the buffer will be recycled, the buffer
// need to be copied.
value = append([]byte{}, data.Value()...)
}
return
}
@@ -791,6 +838,9 @@ func (r *Reader) Find(key []byte, ro *opt.ReadOptions) (rkey, value []byte, err
// The caller should not modify the contents of the returned slice, but
// it is safe to modify the contents of the argument after Get returns.
func (r *Reader) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) {
r.mu.RLock()
defer r.mu.RUnlock()
if r.err != nil {
err = r.err
return
@@ -808,6 +858,9 @@ func (r *Reader) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error)
//
// It is safe to modify the contents of the argument after Get returns.
func (r *Reader) OffsetOf(key []byte) (offset int64, err error) {
r.mu.RLock()
defer r.mu.RUnlock()
if r.err != nil {
err = r.err
return
@@ -819,7 +872,7 @@ func (r *Reader) OffsetOf(key []byte) (offset int64, err error) {
}
defer rel.Release()
index := indexBlock.newIterator(nil, true, nil)
index := r.newBlockIter(indexBlock, nil, nil, true)
defer index.Release()
if index.Seek(key) {
dataBH, n := decodeBlockHandle(index.Value())
@@ -840,12 +893,24 @@ func (r *Reader) OffsetOf(key []byte) (offset int64, err error) {
// Release implements util.Releaser.
// It also close the file if it is an io.Closer.
func (r *Reader) Release() {
r.mu.Lock()
defer r.mu.Unlock()
if closer, ok := r.reader.(io.Closer); ok {
closer.Close()
}
if r.indexBlock != nil {
r.indexBlock.Release()
r.indexBlock = nil
}
if r.filterBlock != nil {
r.filterBlock.Release()
r.filterBlock = nil
}
r.reader = nil
r.cache = nil
r.bpool = nil
r.err = ErrReaderReleased
}
// NewReader creates a new initialized table reader for the file.
@@ -853,9 +918,6 @@ func (r *Reader) Release() {
//
// The returned table reader instance is goroutine-safe.
func NewReader(f io.ReaderAt, size int64, cache cache.Namespace, bpool *util.BufferPool, o *opt.Options) *Reader {
if bpool == nil {
bpool = util.NewBufferPool(o.GetBlockSize() + blockTrailerLen)
}
r := &Reader{
reader: f,
cache: cache,
@@ -900,7 +962,7 @@ func NewReader(f io.ReaderAt, size int64, cache cache.Namespace, bpool *util.Buf
}
// Set data end.
r.dataEnd = int64(metaBH.offset)
metaIter := metaBlock.newIterator(nil, false, nil)
metaIter := r.newBlockIter(metaBlock, nil, nil, false)
for metaIter.Next() {
key := string(metaIter.Key())
if !strings.HasPrefix(key, "filter.") {
@@ -930,5 +992,22 @@ func NewReader(f io.ReaderAt, size int64, cache cache.Namespace, bpool *util.Buf
}
metaIter.Release()
metaBlock.Release()
// Cache index and filter block locally, since we don't have global cache.
if cache == nil {
r.indexBlock, r.err = r.readBlock(r.indexBH, true)
if r.err != nil {
return r
}
if r.filter != nil {
r.filterBlock, err = r.readFilterBlock(r.filterBH)
if err != nil {
// Don't use filter then.
r.filter = nil
r.filterBH = blockHandle{}
}
}
}
return r
}

View File

@@ -54,6 +54,10 @@ func (p *BufferPool) poolNum(n int) int {
// Get returns buffer with length of n.
func (p *BufferPool) Get(n int) []byte {
if p == nil {
return make([]byte, n)
}
atomic.AddUint32(&p.get, 1)
poolNum := p.poolNum(n)
@@ -145,9 +149,16 @@ func (p *BufferPool) Get(n int) []byte {
// Put adds given buffer to the pool.
func (p *BufferPool) Put(b []byte) {
if p == nil {
return
}
atomic.AddUint32(&p.put, 1)
pool := p.pool[p.poolNum(cap(b))]
defer func() {
recover()
}()
select {
case pool <- b:
default:
@@ -156,6 +167,10 @@ func (p *BufferPool) Put(b []byte) {
}
func (p *BufferPool) Close() {
if p == nil {
return
}
select {
case p.close <- struct{}{}:
default:
@@ -163,6 +178,10 @@ func (p *BufferPool) Close() {
}
func (p *BufferPool) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("BufferPool{B·%d Z·%v Zm·%v Zh·%v G·%d P·%d H·%d <·%d =·%d >·%d M·%d}",
p.baseline0, p.size, p.sizeMiss, p.sizeHalf, p.get, p.put, p.half, p.less, p.equal, p.greater, p.miss)
}

View File

@@ -12,7 +12,9 @@ import (
)
var (
ErrNotFound = errors.New("leveldb: not found")
ErrNotFound = errors.New("leveldb: not found")
ErrReleased = errors.New("leveldb: resource already relesed")
ErrHasReleaser = errors.New("leveldb: releaser already defined")
)
// Releaser is the interface that wraps the basic Release method.
@@ -27,23 +29,46 @@ type ReleaseSetter interface {
// SetReleaser associates the given releaser to the resources. The
// releaser will be called once coresponding resources released.
// Calling SetReleaser with nil will clear the releaser.
//
// This will panic if a releaser already present or coresponding
// resource is already released. Releaser should be cleared first
// before assigned a new one.
SetReleaser(releaser Releaser)
}
// BasicReleaser provides basic implementation of Releaser and ReleaseSetter.
type BasicReleaser struct {
releaser Releaser
released bool
}
// Released returns whether Release method already called.
func (r *BasicReleaser) Released() bool {
return r.released
}
// Release implements Releaser.Release.
func (r *BasicReleaser) Release() {
if r.releaser != nil {
r.releaser.Release()
r.releaser = nil
if !r.released {
if r.releaser != nil {
r.releaser.Release()
r.releaser = nil
}
r.released = true
}
}
// SetReleaser implements ReleaseSetter.SetReleaser.
func (r *BasicReleaser) SetReleaser(releaser Releaser) {
if r.released {
panic(ErrReleased)
}
if r.releaser != nil && releaser != nil {
panic(ErrHasReleaser)
}
r.releaser = releaser
}
type NoopReleaser struct{}
func (NoopReleaser) Release() {}

687
LICENSE
View File

@@ -1,19 +1,674 @@
Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
- The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
Preamble
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -3,14 +3,14 @@ syncthing
[![Latest Build](http://img.shields.io/jenkins/s/http/build.syncthing.net/syncthing.svg?style=flat-square)](http://build.syncthing.net/job/syncthing/lastBuild/)
[![API Documentation](http://img.shields.io/badge/api-Godoc-blue.svg?style=flat-square)](http://godoc.org/github.com/syncthing/syncthing)
[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](http://opensource.org/licenses/MIT)
[![GPL License](http://img.shields.io/badge/license-GPL-blue.svg?style=flat-square)](http://opensource.org/licenses/GPL-3.0)
This is the `syncthing` project. The following are the project goals:
1. Define a protocol for synchronization of a file repository between a
number of collaborating nodes. The protocol should be well defined,
unambiguous, easily understood, free to use, efficient, secure and
language neutral. This is the [Block Exchange
1. Define a protocol for synchronization of a folder between a number of
collaborating devices. The protocol should be well defined, unambiguous,
easily understood, free to use, efficient, secure and language neutral.
This is the [Block Exchange
Protocol](https://github.com/syncthing/syncthing/blob/master/protocol/PROTOCOL.md).
2. Provide the reference implementation to demonstrate the usability of
@@ -56,5 +56,6 @@ All documentation and protocol specifications are licensed
under the [Creative Commons Attribution 4.0 International
License](http://creativecommons.org/licenses/by/4.0/).
All code is licensed under the [MIT
License](https://github.com/syncthing/syncthing/blob/master/LICENSE).
All code is licensed under the
[GPL](https://github.com/syncthing/syncthing/blob/master/LICENSE), v3 or
later.

172
build.go
View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build ignore
@@ -24,6 +35,7 @@ import (
"runtime"
"strconv"
"strings"
"time"
)
var (
@@ -31,6 +43,7 @@ var (
goarch string
goos string
noupgrade bool
version string
)
const minGoVersion = 1.3
@@ -53,6 +66,7 @@ func main() {
flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH")
flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS")
flag.BoolVar(&noupgrade, "no-upgrade", false, "Disable upgrade functionality")
flag.StringVar(&version, "version", getVersion(), "Set compiled in version string")
flag.Parse()
switch goarch {
@@ -67,75 +81,62 @@ func main() {
checkRequiredGoVersion()
if check() != nil {
setup()
}
if flag.NArg() == 0 {
install("./cmd/...")
return
}
switch flag.Arg(0) {
case "install":
pkg := "./cmd/..."
if flag.NArg() > 2 {
pkg = flag.Arg(1)
for _, cmd := range flag.Args() {
switch cmd {
case "setup":
setup()
case "install":
pkg := "./cmd/..."
install(pkg)
case "build":
pkg := "./cmd/syncthing"
var tags []string
if noupgrade {
tags = []string{"noupgrade"}
}
build(pkg, tags)
case "test":
pkg := "./..."
test(pkg)
case "assets":
assets()
case "xdr":
xdr()
case "translate":
translate()
case "transifex":
transifex()
case "deps":
deps()
case "tar":
buildTar()
case "zip":
buildZip()
case "clean":
clean()
default:
log.Fatalf("Unknown command %q", cmd)
}
install(pkg)
case "build":
pkg := "./cmd/syncthing"
if flag.NArg() > 2 {
pkg = flag.Arg(1)
}
var tags []string
if noupgrade {
tags = []string{"noupgrade"}
}
build(pkg, tags)
case "test":
pkg := "./..."
if flag.NArg() > 2 {
pkg = flag.Arg(1)
}
test(pkg)
case "assets":
assets()
case "xdr":
xdr()
case "translate":
translate()
case "transifex":
transifex()
case "deps":
deps()
case "tar":
buildTar()
case "zip":
buildZip()
case "clean":
clean()
default:
log.Fatalf("Unknown command %q", flag.Arg(0))
}
}
func check() error {
_, err := exec.LookPath("godep")
return err
}
func checkRequiredGoVersion() {
ver := run("go", "version")
re := regexp.MustCompile(`go version go(\d+\.\d+)`)
@@ -163,24 +164,25 @@ func setup() {
}
func test(pkg string) {
runPrint("godep", "go", "test", "-short", "-timeout", "10s", pkg)
setBuildEnv()
runPrint("go", "test", "-short", "-timeout", "10s", pkg)
}
func install(pkg string) {
os.Setenv("GOBIN", "./bin")
setBuildEnv()
runPrint("godep", "go", "install", "-ldflags", ldflags(), pkg)
runPrint("go", "install", "-v", "-ldflags", ldflags(), pkg)
}
func build(pkg string, tags []string) {
rmr("syncthing", "syncthing.exe")
args := []string{"go", "build", "-ldflags", ldflags()}
args := []string{"build", "-ldflags", ldflags()}
if len(tags) > 0 {
args = append(args, "-tags", strings.Join(tags, ","))
}
args = append(args, pkg)
setBuildEnv()
runPrint("godep", args...)
runPrint("go", args...)
}
func buildTar() {
@@ -230,10 +232,18 @@ func setBuildEnv() {
if goarch == "386" {
os.Setenv("GO386", "387")
}
wd, err := os.Getwd()
if err != nil {
log.Println("Warning: can't determine current dir:", err)
log.Println("Build might not work as expected")
}
os.Setenv("GOPATH", fmt.Sprintf("%s%c%s", filepath.Join(wd, "Godeps", "_workspace"), os.PathListSeparator, os.Getenv("GOPATH")))
log.Println("GOPATH=" + os.Getenv("GOPATH"))
}
func assets() {
runPipe("internal/auto/gui.files.go", "godep", "go", "run", "cmd/genassets/main.go", "gui")
setBuildEnv()
runPipe("internal/auto/gui.files.go", "go", "run", "cmd/genassets/main.go", "gui")
}
func xdr() {
@@ -273,7 +283,7 @@ func clean() {
func ldflags() string {
var b bytes.Buffer
b.WriteString("-w")
b.WriteString(fmt.Sprintf(" -X main.Version %s", version()))
b.WriteString(fmt.Sprintf(" -X main.Version %s", version))
b.WriteString(fmt.Sprintf(" -X main.BuildStamp %d", buildStamp()))
b.WriteString(fmt.Sprintf(" -X main.BuildUser %s", buildUser()))
b.WriteString(fmt.Sprintf(" -X main.BuildHost %s", buildHost()))
@@ -291,8 +301,11 @@ func rmr(paths ...string) {
}
}
func version() string {
v := run("git", "describe", "--always", "--dirty")
func getVersion() string {
v, err := runError("git", "describe", "--always", "--dirty")
if err != nil {
return "unknown-dev"
}
v = versionRe.ReplaceAllFunc(v, func(s []byte) []byte {
s[0] = '+'
return s
@@ -301,7 +314,10 @@ func version() string {
}
func buildStamp() int64 {
bs := run("git", "show", "-s", "--format=%ct")
bs, err := runError("git", "show", "-s", "--format=%ct")
if err != nil {
return time.Now().Unix()
}
s, _ := strconv.ParseInt(string(bs), 10, 64)
return s
}
@@ -338,12 +354,11 @@ func buildArch() string {
}
func archiveName() string {
return fmt.Sprintf("syncthing-%s-%s", buildArch(), version())
return fmt.Sprintf("syncthing-%s-%s", buildArch(), version)
}
func run(cmd string, args ...string) []byte {
ecmd := exec.Command(cmd, args...)
bs, err := ecmd.CombinedOutput()
bs, err := runError(cmd, args...)
if err != nil {
log.Println(cmd, strings.Join(args, " "))
log.Println(string(bs))
@@ -352,6 +367,15 @@ func run(cmd string, args ...string) []byte {
return bytes.TrimSpace(bs)
}
func runError(cmd string, args ...string) ([]byte, error) {
ecmd := exec.Command(cmd, args...)
bs, err := ecmd.CombinedOutput()
if err != nil {
return nil, err
}
return bytes.TrimSpace(bs), nil
}
func runPrint(cmd string, args ...string) {
log.Println(cmd, strings.Join(args, " "))
ecmd := exec.Command(cmd, args...)

View File

@@ -57,6 +57,9 @@ case "${1:-default}" in
go run build.go -goos freebsd -goarch amd64 tar
go run build.go -goos freebsd -goarch 386 tar
go run build.go -goos openbsd -goarch amd64 tar
go run build.go -goos openbsd -goarch 386 tar
go run build.go -goos darwin -goarch amd64 tar
go run build.go -goos windows -goarch amd64 zip

View File

@@ -8,6 +8,8 @@ missing-contribs() {
no-docs-typos() {
# Commits that are known to not change code
grep -v 63bd0136fb40a91efaa279cb4b4159d82e8e6904 |\
grep -v 4e2feb6fbc791bb8a2daf0ab8efb10775d66343e |\
grep -v f2459ef3319b2f060dbcdacd0c35a1788a94b8bd |\
grep -v b61f418bf2d1f7d5a9d7088a20a2a448e5e66801 |\
grep -v f0621207e3953711f9ab86d99724f1d0faac45b1 |\
@@ -24,6 +26,19 @@ print-missing-copyright() {
find . -name \*.go | xargs grep -L 'Copyright (C)' | grep -v Godeps
}
print-line-blame() {
for f in $(find . -name \*.go | grep -v Godep) gui/app.js gui/index.html ; do
git blame --line-porcelain $f | grep author-mail
done | sort | uniq -c | sort -n
}
echo Author emails missing in CONTRIBUTORS:
print-missing-contribs
print-missing-copyright
echo
echo Files missing copyright notice:
print-missing-copyright
echo
echo Blame lines per author:
print-line-blame

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build ignore

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main
@@ -19,8 +30,8 @@ func main() {
log.SetFlags(0)
log.SetOutput(os.Stdout)
repo := flag.String("repo", "default", "Repository ID")
node := flag.String("node", "", "Node ID (blank for global)")
folder := flag.String("folder", "default", "Folder ID")
device := flag.String("device", "", "Device ID (blank for global)")
flag.Parse()
db, err := leveldb.OpenFile(flag.Arg(0), nil)
@@ -28,10 +39,10 @@ func main() {
log.Fatal(err)
}
fs := files.NewSet(*repo, db)
fs := files.NewSet(*folder, db)
if *node == "" {
log.Printf("*** Global index for repo %q", *repo)
if *device == "" {
log.Printf("*** Global index for folder %q", *folder)
fs.WithGlobalTruncated(func(fi protocol.FileIntf) bool {
f := fi.(protocol.FileInfoTruncated)
fmt.Println(f)
@@ -39,11 +50,11 @@ func main() {
return true
})
} else {
n, err := protocol.NodeIDFromString(*node)
n, err := protocol.DeviceIDFromString(*device)
if err != nil {
log.Fatal(err)
}
log.Printf("*** Have index for repo %q node %q", *repo, n)
log.Printf("*** Have index for folder %q device %q", *folder, n)
fs.WithHaveTruncated(n, func(fi protocol.FileIntf) bool {
f := fi.(protocol.FileInfoTruncated)
fmt.Println(f)

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main
@@ -21,11 +32,13 @@ import (
"time"
"code.google.com/p/go.crypto/bcrypt"
"github.com/calmh/logger"
"github.com/syncthing/syncthing/internal/auto"
"github.com/syncthing/syncthing/internal/config"
"github.com/syncthing/syncthing/internal/discover"
"github.com/syncthing/syncthing/internal/events"
"github.com/syncthing/syncthing/internal/logger"
"github.com/syncthing/syncthing/internal/model"
"github.com/syncthing/syncthing/internal/osutil"
"github.com/syncthing/syncthing/internal/protocol"
"github.com/syncthing/syncthing/internal/upgrade"
"github.com/vitrun/qart/qr"
@@ -87,14 +100,13 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro
getRestMux.HandleFunc("/rest/ignores", withModel(m, restGetIgnores))
getRestMux.HandleFunc("/rest/lang", restGetLang)
getRestMux.HandleFunc("/rest/model", withModel(m, restGetModel))
getRestMux.HandleFunc("/rest/model/version", withModel(m, restGetModelVersion))
getRestMux.HandleFunc("/rest/need", withModel(m, restGetNeed))
getRestMux.HandleFunc("/rest/nodeid", restGetNodeID)
getRestMux.HandleFunc("/rest/deviceid", restGetDeviceID)
getRestMux.HandleFunc("/rest/report", withModel(m, restGetReport))
getRestMux.HandleFunc("/rest/system", restGetSystem)
getRestMux.HandleFunc("/rest/upgrade", restGetUpgrade)
getRestMux.HandleFunc("/rest/version", restGetVersion)
getRestMux.HandleFunc("/rest/stats/node", withModel(m, restGetNodeStats))
getRestMux.HandleFunc("/rest/stats/device", withModel(m, restGetDeviceStats))
// Debug endpoints, not for general use
getRestMux.HandleFunc("/rest/debug/peerCompletion", withModel(m, restGetPeerCompletion))
@@ -143,8 +155,13 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro
handler = redirectToHTTPSMiddleware(handler)
}
srv := http.Server{
Handler: handler,
ReadTimeout: 2 * time.Second,
}
go func() {
err := http.Serve(listener, handler)
err := srv.Serve(listener)
if err != nil {
panic(err)
}
@@ -221,59 +238,43 @@ func restGetVersion(w http.ResponseWriter, r *http.Request) {
func restGetCompletion(m *model.Model, w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var repo = qs.Get("repo")
var nodeStr = qs.Get("node")
var folder = qs.Get("folder")
var deviceStr = qs.Get("device")
node, err := protocol.NodeIDFromString(nodeStr)
device, err := protocol.DeviceIDFromString(deviceStr)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
res := map[string]float64{
"completion": m.Completion(node, repo),
"completion": m.Completion(device, folder),
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(res)
}
func restGetModelVersion(m *model.Model, w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var repo = qs.Get("repo")
var res = make(map[string]interface{})
res["version"] = m.LocalVersion(repo)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(res)
}
func restGetModel(m *model.Model, w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var repo = qs.Get("repo")
var folder = qs.Get("folder")
var res = make(map[string]interface{})
for _, cr := range cfg.Repositories {
if cr.ID == repo {
res["invalid"] = cr.Invalid
break
}
}
res["invalid"] = cfg.Folders()[folder].Invalid
globalFiles, globalDeleted, globalBytes := m.GlobalSize(repo)
globalFiles, globalDeleted, globalBytes := m.GlobalSize(folder)
res["globalFiles"], res["globalDeleted"], res["globalBytes"] = globalFiles, globalDeleted, globalBytes
localFiles, localDeleted, localBytes := m.LocalSize(repo)
localFiles, localDeleted, localBytes := m.LocalSize(folder)
res["localFiles"], res["localDeleted"], res["localBytes"] = localFiles, localDeleted, localBytes
needFiles, needBytes := m.NeedSize(repo)
needFiles, needBytes := m.NeedSize(folder)
res["needFiles"], res["needBytes"] = needFiles, needBytes
res["inSyncFiles"], res["inSyncBytes"] = globalFiles-needFiles, globalBytes-needBytes
res["state"], res["stateChanged"] = m.State(repo)
res["version"] = m.LocalVersion(repo)
res["state"], res["stateChanged"] = m.State(folder)
res["version"] = m.CurrentLocalVersion(folder) + m.RemoteLocalVersion(folder)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(res)
@@ -281,15 +282,15 @@ func restGetModel(m *model.Model, w http.ResponseWriter, r *http.Request) {
func restPostOverride(m *model.Model, w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var repo = qs.Get("repo")
go m.Override(repo)
var folder = qs.Get("folder")
go m.Override(folder)
}
func restGetNeed(m *model.Model, w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var repo = qs.Get("repo")
var folder = qs.Get("folder")
files := m.NeedFilesRepoLimited(repo, 100, 2500) // max 100 files or 2500 blocks
files := m.NeedFolderFilesLimited(folder, 100, 2500) // max 100 files or 2500 blocks
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(files)
@@ -301,15 +302,15 @@ func restGetConnections(m *model.Model, w http.ResponseWriter, r *http.Request)
json.NewEncoder(w).Encode(res)
}
func restGetNodeStats(m *model.Model, w http.ResponseWriter, r *http.Request) {
var res = m.NodeStatistics()
func restGetDeviceStats(m *model.Model, w http.ResponseWriter, r *http.Request) {
var res = m.DeviceStatistics()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(res)
}
func restGetConfig(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(cfg)
json.NewEncoder(w).Encode(cfg.Raw())
}
func restPostConfig(m *model.Model, w http.ResponseWriter, r *http.Request) {
@@ -320,7 +321,7 @@ func restPostConfig(m *model.Model, w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), 500)
return
} else {
if newCfg.GUI.Password != cfg.GUI.Password {
if newCfg.GUI.Password != cfg.GUI().Password {
if newCfg.GUI.Password != "" {
hash, err := bcrypt.GenerateFromPassword([]byte(newCfg.GUI.Password), 0)
if err != nil {
@@ -335,7 +336,7 @@ func restPostConfig(m *model.Model, w http.ResponseWriter, r *http.Request) {
// Start or stop usage reporting as appropriate
if newCfg.Options.URAccepted > cfg.Options.URAccepted {
if curAcc := cfg.Options().URAccepted; newCfg.Options.URAccepted > curAcc {
// UR was enabled
newCfg.Options.URAccepted = usageReportVersion
err := sendUsageReport(m)
@@ -343,7 +344,7 @@ func restPostConfig(m *model.Model, w http.ResponseWriter, r *http.Request) {
l.Infoln("Usage report:", err)
}
go usageReportingLoop(m)
} else if newCfg.Options.URAccepted < cfg.Options.URAccepted {
} else if newCfg.Options.URAccepted < curAcc {
// UR was disabled
newCfg.Options.URAccepted = -1
stopUsageReporting()
@@ -351,10 +352,9 @@ func restPostConfig(m *model.Model, w http.ResponseWriter, r *http.Request) {
// Activate and save
configInSync = !config.ChangeRequiresRestart(cfg, newCfg)
newCfg.Location = cfg.Location
newCfg.Save()
cfg = newCfg
configInSync = !config.ChangeRequiresRestart(cfg.Raw(), newCfg)
cfg.Replace(newCfg)
cfg.Save()
}
}
@@ -369,8 +369,8 @@ func restPostRestart(w http.ResponseWriter, r *http.Request) {
}
func restPostReset(w http.ResponseWriter, r *http.Request) {
flushResponse(`{"ok": "resetting repos"}`, w)
resetRepositories()
flushResponse(`{"ok": "resetting folders"}`, w)
resetFolders()
go restart()
}
@@ -392,13 +392,14 @@ func restGetSystem(w http.ResponseWriter, r *http.Request) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
tilde, _ := osutil.ExpandTilde("~")
res := make(map[string]interface{})
res["myID"] = myID.String()
res["goroutines"] = runtime.NumGoroutine()
res["alloc"] = m.Alloc
res["sys"] = m.Sys - m.HeapReleased
res["tilde"] = expandTilde("~")
if cfg.Options.GlobalAnnEnabled && discoverer != nil {
res["tilde"] = tilde
if cfg.Options().GlobalAnnEnabled && discoverer != nil {
res["extAnnounceOK"] = discoverer.ExtAnnounceOK()
}
cpuUsageLock.RLock()
@@ -443,15 +444,27 @@ func showGuiError(l logger.LogLevel, err string) {
func restPostDiscoveryHint(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var node = qs.Get("node")
var device = qs.Get("device")
var addr = qs.Get("addr")
if len(node) != 0 && len(addr) != 0 && discoverer != nil {
discoverer.Hint(node, []string{addr})
if len(device) != 0 && len(addr) != 0 && discoverer != nil {
discoverer.Hint(device, []string{addr})
}
}
func restGetDiscovery(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(discoverer.All())
w.Header().Set("Content-Type", "application/json; charset=utf-8")
devices := map[string][]discover.CacheEntry{}
if discoverer != nil {
// Device ids can't be marshalled as keys so we need to manually
// rebuild this map using strings. Discoverer may be nil if discovery
// has not started yet.
for device, entries := range discoverer.All() {
devices[device.String()] = entries
}
}
json.NewEncoder(w).Encode(devices)
}
func restGetReport(m *model.Model, w http.ResponseWriter, r *http.Request) {
@@ -463,7 +476,7 @@ func restGetIgnores(m *model.Model, w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
ignores, err := m.GetIgnores(qs.Get("repo"))
ignores, err := m.GetIgnores(qs.Get("folder"))
if err != nil {
http.Error(w, err.Error(), 500)
return
@@ -485,7 +498,7 @@ func restPostIgnores(m *model.Model, w http.ResponseWriter, r *http.Request) {
return
}
err = m.SetIgnores(qs.Get("repo"), data["ignore"])
err = m.SetIgnores(qs.Get("folder"), data["ignore"])
if err != nil {
http.Error(w, err.Error(), 500)
return
@@ -531,10 +544,10 @@ func restGetUpgrade(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(res)
}
func restGetNodeID(w http.ResponseWriter, r *http.Request) {
func restGetDeviceID(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
idStr := qs.Get("id")
id, err := protocol.NodeIDFromString(idStr)
id, err := protocol.DeviceIDFromString(idStr)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
if err == nil {
json.NewEncoder(w).Encode(map[string]string{
@@ -582,9 +595,9 @@ func restPostUpgrade(w http.ResponseWriter, r *http.Request) {
func restPostScan(m *model.Model, w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
repo := qs.Get("repo")
folder := qs.Get("folder")
sub := qs.Get("sub")
err := m.ScanRepoSub(repo, sub)
err := m.ScanFolderSub(folder, sub)
if err != nil {
http.Error(w, err.Error(), 500)
}
@@ -607,21 +620,21 @@ func restGetPeerCompletion(m *model.Model, w http.ResponseWriter, r *http.Reques
tot := map[string]float64{}
count := map[string]float64{}
for _, repo := range cfg.Repositories {
for _, node := range repo.NodeIDs() {
nodeStr := node.String()
if m.ConnectedTo(node) {
tot[nodeStr] += m.Completion(node, repo.ID)
for _, folder := range cfg.Folders() {
for _, device := range folder.DeviceIDs() {
deviceStr := device.String()
if m.ConnectedTo(device) {
tot[deviceStr] += m.Completion(device, folder.ID)
} else {
tot[nodeStr] = 0
tot[deviceStr] = 0
}
count[nodeStr]++
count[deviceStr]++
}
}
comp := map[string]int{}
for node := range tot {
comp[node] = int(tot[node] / count[node])
for device := range tot {
comp[device] = int(tot[device] / count[device])
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
//+build solaris

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
//+build !windows,!solaris

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
//+build windows

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,119 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main_test
package main
// Empty test file to generate 0% coverage rather than no coverage
import (
"os"
"testing"
"github.com/syncthing/syncthing/internal/config"
"github.com/syncthing/syncthing/internal/files"
"github.com/syncthing/syncthing/internal/model"
"github.com/syncthing/syncthing/internal/protocol"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"
)
func TestSanityCheck(t *testing.T) {
fcfg := config.FolderConfiguration{
ID: "folder",
Path: "testdata/testfolder",
}
cfg := config.Wrap("/tmp/test", config.Configuration{
Folders: []config.FolderConfiguration{fcfg},
})
for _, file := range []string{".stfolder", "testfolder", "testfolder/.stfolder"} {
_, err := os.Stat("testdata/" + file)
if err == nil {
t.Error("Found unexpected file")
}
}
db, _ := leveldb.Open(storage.NewMemStorage(), nil)
// Case 1 - new folder, directory and marker created
m := model.NewModel(cfg, "device", "syncthing", "dev", db)
sanityCheckFolders(cfg, m)
if cfg.Folders()["folder"].Invalid != "" {
t.Error("Unexpected error", cfg.Folders()["folder"].Invalid)
}
s, err := os.Stat("testdata/testfolder")
if err != nil || !s.IsDir() {
t.Error(err)
}
_, err = os.Stat("testdata/testfolder/.stfolder")
if err != nil {
t.Error(err)
}
os.Remove("testdata/testfolder/.stfolder")
os.Remove("testdata/testfolder/")
// Case 2 - new folder, marker created
fcfg.Path = "testdata/"
cfg = config.Wrap("/tmp/test", config.Configuration{
Folders: []config.FolderConfiguration{fcfg},
})
m = model.NewModel(cfg, "device", "syncthing", "dev", db)
sanityCheckFolders(cfg, m)
if cfg.Folders()["folder"].Invalid != "" {
t.Error("Unexpected error", cfg.Folders()["folder"].Invalid)
}
_, err = os.Stat("testdata/.stfolder")
if err != nil {
t.Error(err)
}
os.Remove("testdata/.stfolder")
// Case 3 - marker missing
set := files.NewSet("folder", db)
set.Update(protocol.LocalDeviceID, []protocol.FileInfo{
{Name: "dummyfile"},
})
m = model.NewModel(cfg, "device", "syncthing", "dev", db)
sanityCheckFolders(cfg, m)
if cfg.Folders()["folder"].Invalid != "folder marker missing" {
t.Error("Incorrect error")
}
// Case 4 - path missing
fcfg.Path = "testdata/testfolder"
cfg = config.Wrap("/tmp/test", config.Configuration{
Folders: []config.FolderConfiguration{fcfg},
})
m = model.NewModel(cfg, "device", "syncthing", "dev", db)
sanityCheckFolders(cfg, m)
if cfg.Folders()["folder"].Invalid != "folder path missing" {
t.Error("Incorrect error")
}
}

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build solaris

View File

@@ -1,8 +1,19 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build freebsd
// +build freebsd openbsd
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main
@@ -11,10 +22,13 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"sync"
"syscall"
"time"
"github.com/syncthing/syncthing/internal/osutil"
)
var (
@@ -30,8 +44,35 @@ const (
func monitorMain() {
os.Setenv("STNORESTART", "yes")
os.Setenv("STMONITORED", "yes")
l.SetPrefix("[monitor] ")
var err error
var dst io.Writer = os.Stdout
if logFile != "" {
var fileDst io.Writer
fileDst, err = os.Create(logFile)
if err != nil {
l.Fatalln("log file:", err)
}
if runtime.GOOS == "windows" {
// Translate line breaks to Windows standard
fileDst = osutil.ReplacingWriter{
Writer: fileDst,
From: '\n',
To: []byte{'\r', '\n'},
}
}
// Log to both stdout and file.
dst = io.MultiWriter(dst, fileDst)
l.Infof(`Log output saved to file "%s"`, logFile)
}
args := os.Args
var restarts [countRestarts]time.Time
@@ -52,12 +93,12 @@ func monitorMain() {
stderr, err := cmd.StderrPipe()
if err != nil {
l.Fatalln(err)
l.Fatalln("stderr:", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
l.Fatalln(err)
l.Fatalln("stdout:", err)
}
l.Infoln("Starting syncthing")
@@ -66,13 +107,17 @@ func monitorMain() {
l.Fatalln(err)
}
// Let the next child process know that this is not the first time
// it's starting up.
os.Setenv("STRESTART", "yes")
stdoutMut.Lock()
stdoutFirstLines = make([]string, 0, 10)
stdoutLastLines = make([]string, 0, 50)
stdoutMut.Unlock()
go copyStderr(stderr)
go copyStdout(stdout)
go copyStderr(stderr, dst)
go copyStdout(stdout, dst)
exit := make(chan error)
@@ -111,14 +156,10 @@ func monitorMain() {
l.Infoln("Syncthing exited:", err)
time.Sleep(1 * time.Second)
// Let the next child process know that this is not the first time
// it's starting up.
os.Setenv("STRESTART", "yes")
}
}
func copyStderr(stderr io.ReadCloser) {
func copyStderr(stderr io.ReadCloser, dst io.Writer) {
br := bufio.NewReader(stderr)
var panicFd *os.File
@@ -129,7 +170,7 @@ func copyStderr(stderr io.ReadCloser) {
}
if panicFd == nil {
os.Stderr.WriteString(line)
dst.Write([]byte(line))
if strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:") {
panicFd, err = os.Create(filepath.Join(confDir, time.Now().Format("panic-20060102-150405.log")))
@@ -141,7 +182,6 @@ func copyStderr(stderr io.ReadCloser) {
l.Warnf("Panic detected, writing to \"%s\"", panicFd.Name())
l.Warnln("Please create an issue at https://github.com/syncthing/syncthing/issues/ with the panic log attached")
panicFd.WriteString("Panic at " + time.Now().Format(time.RFC1123) + "\n")
stdoutMut.Lock()
for _, line := range stdoutFirstLines {
panicFd.WriteString(line)
@@ -150,7 +190,10 @@ func copyStderr(stderr io.ReadCloser) {
for _, line := range stdoutLastLines {
panicFd.WriteString(line)
}
stdoutMut.Unlock()
}
panicFd.WriteString("Panic at " + time.Now().Format(time.RFC3339) + "\n")
}
if panicFd != nil {
@@ -159,8 +202,8 @@ func copyStderr(stderr io.ReadCloser) {
}
}
func copyStdout(stderr io.ReadCloser) {
br := bufio.NewReader(stderr)
func copyStdout(stdout io.ReadCloser, dst io.Writer) {
br := bufio.NewReader(stdout)
for {
line, err := br.ReadString('\n')
if err != nil {
@@ -170,13 +213,14 @@ func copyStdout(stderr io.ReadCloser) {
stdoutMut.Lock()
if len(stdoutFirstLines) < cap(stdoutFirstLines) {
stdoutFirstLines = append(stdoutFirstLines, line)
} else {
if l := len(stdoutLastLines); l == cap(stdoutLastLines) {
stdoutLastLines = stdoutLastLines[:l-1]
}
stdoutLastLines = append(stdoutLastLines, line)
}
if l := len(stdoutLastLines); l == cap(stdoutLastLines) {
stdoutLastLines = stdoutLastLines[:l-1]
}
stdoutLastLines = append(stdoutLastLines, line)
stdoutMut.Unlock()
os.Stdout.WriteString(line)
dst.Write([]byte(line))
}
}

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build !windows

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build windows

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build !solaris,!windows

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main
@@ -36,9 +47,8 @@ func usageFor(fs *flag.FlagSet, usage string, extra string) func() {
var opt = " -" + f.Name
if f.DefValue != "false" {
opt += "=" + fmt.Sprintf("%q", f.DefValue)
opt += "=" + fmt.Sprintf(`"%s"`, f.DefValue)
}
options = append(options, []string{opt, f.Usage})
})

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package main
@@ -31,13 +42,13 @@ func reportData(m *model.Model) map[string]interface{} {
res["version"] = Version
res["longVersion"] = LongVersion
res["platform"] = runtime.GOOS + "-" + runtime.GOARCH
res["numRepos"] = len(cfg.Repositories)
res["numNodes"] = len(cfg.Nodes)
res["numFolders"] = len(cfg.Folders())
res["numDevices"] = len(cfg.Devices())
var totFiles, maxFiles int
var totBytes, maxBytes int64
for _, repo := range cfg.Repositories {
files, _, bytes := m.GlobalSize(repo.ID)
for folderID := range cfg.Folders() {
files, _, bytes := m.GlobalSize(folderID)
totFiles += files
totBytes += bytes
if files > maxFiles {
@@ -49,9 +60,9 @@ func reportData(m *model.Model) map[string]interface{} {
}
res["totFiles"] = totFiles
res["repoMaxFiles"] = maxFiles
res["folderMaxFiles"] = maxFiles
res["totMiB"] = totBytes / 1024 / 1024
res["repoMaxMiB"] = maxBytes / 1024 / 1024
res["folderMaxMiB"] = maxBytes / 1024 / 1024
var mem runtime.MemStats
runtime.ReadMemStats(&mem)

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build ignore

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build ignore
@@ -52,12 +63,11 @@ func main() {
var langs []string
for code, stat := range stats {
code = strings.Replace(code, "_", "-", 1)
if !curValidLangs[code] {
if pct := 100 * stat.Translated / (stat.Translated + stat.Untranslated); pct < 95 {
log.Printf("Skipping language %q (too low completion ratio %d%%)", code, pct)
os.Remove("lang-" + code + ".json")
continue
}
pct := 100 * stat.Translated / (stat.Translated + stat.Untranslated)
if pct < 75 || !curValidLangs[code] && pct < 95 {
log.Printf("Skipping language %q (too low completion ratio %d%%)", code, pct)
os.Remove("lang-" + code + ".json")
continue
}
langs = append(langs, code)

View File

@@ -1,6 +1,17 @@
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
// +build ignore

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,19 @@
<!DOCTYPE html>
<!--
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<html lang="en" ng-app="syncthing" ng-controller="SyncthingCtrl" class="ng-cloak">
<head>
@@ -13,7 +24,7 @@
<meta name="author" content="">
<link rel="shortcut icon" href="img/favicon.png">
<title>Syncthing | {{thisNodeName()}}</title>
<title>Syncthing | {{thisDeviceName()}}</title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="font/raleway.css" rel="stylesheet">
<link href="overrides.css" rel="stylesheet">
@@ -27,9 +38,9 @@
<nav class="navbar navbar-top navbar-default" role="navigation">
<div class="container">
<span class="navbar-brand"><img class="logo" src="img/logo-text-64.png" height="32" width="117"/></span>
<p class="navbar-text hidden-xs">{{thisNodeName()}}</p>
<p class="navbar-text hidden-xs">{{thisDeviceName()}}</p>
<ul class="nav navbar-nav navbar-right">
<li ng-if="upgradeInfo.newer">
<li ng-if="upgradeInfo && upgradeInfo.newer">
<button type="button" class="btn navbar-btn btn-primary btn-sm" href="" ng-click="upgrade()">
<span class="glyphicon glyphicon-chevron-up"></span>&emsp;
<span translate translate-value-version="{{upgradeInfo.latest}}">Upgrade To {%version%}</span>
@@ -39,7 +50,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-cog"></span></a>
<ul class="dropdown-menu">
<li><a href="" ng-click="editSettings()"><span class="glyphicon glyphicon-cog"></span>&emsp;<span translate>Settings</span></a></li>
<li><a href="" ng-click="idNode()"><span class="glyphicon glyphicon-qrcode"></span>&emsp;<span translate>Show ID</span></a></li>
<li><a href="" ng-click="idDevice()"><span class="glyphicon glyphicon-qrcode"></span>&emsp;<span translate>Show ID</span></a></li>
<li class="divider"></li>
<li><a href="" ng-click="shutdown()"><span class="glyphicon glyphicon-off"></span>&emsp;<span translate>Shutdown</span></a></li>
<li><a href="" ng-click="restart()"><span class="glyphicon glyphicon-refresh"></span>&emsp;<span translate>Restart</span></a></li>
@@ -74,90 +85,90 @@
<div class="row">
<!-- Repository list (top left) -->
<!-- Folder list (top left) -->
<div class="col-md-6">
<div class="panel-group" id="repositories">
<div class="panel panel-{{repoClass(repo.ID)}}" ng-repeat="repo in repoList()">
<div class="panel-heading" data-toggle="collapse" data-parent="#repositories" href="#repo-{{$index}}" style="cursor: pointer">
<div class="panel-group" id="folders">
<div class="panel panel-{{folderClass(folder.ID)}}" ng-repeat="folder in folderList()">
<div class="panel-heading" data-toggle="collapse" data-parent="#folders" href="#folder-{{$index}}" style="cursor: pointer">
<h3 class="panel-title">
<span class="glyphicon glyphicon-hdd"></span>&emsp;{{repo.ID}}
<span class="pull-right hidden-xs" ng-switch="repoStatus(repo.ID)">
<span class="glyphicon glyphicon-hdd"></span>&emsp;{{folder.ID}}
<span class="pull-right hidden-xs" ng-switch="folderStatus(folder.ID)">
<span translate ng-switch-when="unknown">Unknown</span>
<span translate ng-switch-when="stopped">Stopped</span>
<span translate ng-switch-when="scanning">Scanning</span>
<span ng-switch-when="syncing">
<span translate>Syncing</span>
({{syncPercentage(repo.ID)}}%)
({{syncPercentage(folder.ID)}}%)
</span>
<span ng-switch-when="idle">
<span translate>Idle</span>
({{syncPercentage(repo.ID)}}%)
({{syncPercentage(folder.ID)}}%)
</span>
</span>
</h3>
</div>
<div id="repo-{{$index}}" class="panel-collapse collapse" ng-class="{in: $index === 0}">
<div id="folder-{{$index}}" class="panel-collapse collapse" ng-class="{in: $index === 0}">
<div class="panel-body">
<table class="table table-condensed table-striped">
<tbody>
<tr>
<th><span class="glyphicon glyphicon-tag"></span>&emsp;<span translate>Repository ID</span></th>
<td class="text-right">{{repo.ID}}</td>
<th><span class="glyphicon glyphicon-tag"></span>&emsp;<span translate>Folder ID</span></th>
<td class="text-right">{{folder.ID}}</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-folder-open"></span>&emsp;<span translate>Folder</span></th>
<td class="text-right">{{repo.Directory}}</td>
<th><span class="glyphicon glyphicon-folder-open"></span>&emsp;<span translate>Folder Path</span></th>
<td class="text-right">{{folder.Path}}</td>
</tr>
<tr ng-if="model[repo.ID].invalid">
<tr ng-if="model[folder.ID].invalid">
<th><span class="glyphicon glyphicon-warning-sign"></span>&emsp;<span translate>Error</span></th>
<td class="text-right">{{model[repo.ID].invalid}}</td>
<td class="text-right">{{model[folder.ID].invalid}}</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-globe"></span>&emsp;<span translate>Global Repository</span></th>
<td class="text-right">{{model[repo.ID].globalFiles | alwaysNumber}} <span translate>items</span>, ~{{model[repo.ID].globalBytes | binary}}B</td>
<th><span class="glyphicon glyphicon-globe"></span>&emsp;<span translate>Global State</span></th>
<td class="text-right">{{model[folder.ID].globalFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.ID].globalBytes | binary}}B</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-home"></span>&emsp;<span translate>Local Repository</span></th>
<td class="text-right">{{model[repo.ID].localFiles | alwaysNumber}} <span translate>items</span>, ~{{model[repo.ID].localBytes | binary}}B</td>
<th><span class="glyphicon glyphicon-home"></span>&emsp;<span translate>Local State</span></th>
<td class="text-right">{{model[folder.ID].localFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.ID].localBytes | binary}}B</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-cloud-download"></span>&emsp;<span translate>Out Of Sync</span></th>
<td class="text-right">
<a ng-if="model[repo.ID].needFiles > 0" ng-click="showNeed(repo.ID)" href="">{{model[repo.ID].needFiles | alwaysNumber}} <span translate>items</span>, ~{{model[repo.ID].needBytes | binary}}B</a>
<span ng-if="model[repo.ID].needFiles == 0">0 <span translate>items</span>, 0 B</span>
<a ng-if="model[folder.ID].needFiles > 0" ng-click="showNeed(folder.ID)" href="">{{model[folder.ID].needFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.ID].needBytes | binary}}B</a>
<span ng-if="model[folder.ID].needFiles == 0">0 <span translate>items</span>, 0 B</span>
</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-lock"></span>&emsp;<span translate>Master Repo</span></th>
<th><span class="glyphicon glyphicon-lock"></span>&emsp;<span translate>Folder Master</span></th>
<td class="text-right">
<span translate ng-if="repo.ReadOnly">Yes</span>
<span translate ng-if="!repo.ReadOnly">No</span>
<span translate ng-if="folder.ReadOnly">Yes</span>
<span translate ng-if="!folder.ReadOnly">No</span>
</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-unchecked"></span>&emsp;<span translate>Ignore Permissions</span></th>
<td class="text-right">
<span translate ng-if="repo.IgnorePerms">Yes</span>
<span translate ng-if="!repo.IgnorePerms">No</span>
<span translate ng-if="folder.IgnorePerms">Yes</span>
<span translate ng-if="!folder.IgnorePerms">No</span>
</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-refresh"></span>&emsp;<span translate>Rescan Interval</span></th>
<td class="text-right">{{repo.RescanIntervalS}} s</td>
<td class="text-right">{{folder.RescanIntervalS}} s</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-share-alt"></span>&emsp;<span translate>Shared With</span></th>
<td class="text-right">{{sharesRepo(repo)}}</td>
<td class="text-right">{{sharesFolder(folder)}}</td>
</tr>
</tbody>
</table>
</div>
<div class="panel-footer">
<button class="btn btn-sm btn-danger" ng-if="repo.ReadOnly && model[repo.ID].needFiles > 0" ng-click="override(repo.ID)" href=""><span class="glyphicon glyphicon-upload"></span>&emsp;<span translate>Override Changes</span></button>
<button class="btn btn-sm btn-danger" ng-if="folder.ReadOnly && model[folder.ID].needFiles > 0" ng-click="override(folder.ID)" href=""><span class="glyphicon glyphicon-upload"></span>&emsp;<span translate>Override Changes</span></button>
<span class="pull-right">
<button class="btn btn-sm btn-default" href="" ng-show="repoStatus(repo.ID) == 'idle'" ng-click="rescanRepo(repo.ID)"><span class="glyphicon glyphicon-refresh"></span>&emsp;<span translate>Rescan</span></button>
<button class="btn btn-sm btn-default" href="" ng-click="editRepo(repo)"><span class="glyphicon glyphicon-pencil"></span>&emsp;<span translate>Edit</span></button>
<button class="btn btn-sm btn-default" href="" ng-show="folderStatus(folder.ID) == 'idle'" ng-click="rescanFolder(folder.ID)"><span class="glyphicon glyphicon-refresh"></span>&emsp;<span translate>Rescan</span></button>
<button class="btn btn-sm btn-default" href="" ng-click="editFolder(folder)"><span class="glyphicon glyphicon-pencil"></span>&emsp;<span translate>Edit</span></button>
</span>
<div class="clearfix"></div>
</div>
@@ -165,24 +176,24 @@
</div>
</div>
<div class="form-group">
<button class="btn btn-sm btn-default pull-right" ng-click="addRepo()"><span class="glyphicon glyphicon-plus"></span>&emsp;<span translate>Add Repository</span></button>
<button class="btn btn-sm btn-default pull-right" ng-click="addFolder()"><span class="glyphicon glyphicon-plus"></span>&emsp;<span translate>Add Folder</span></button>
<div class="clearfix"></div>
</div>
<hr class="visible-sm"/>
</div>
<!-- Node list (top right) -->
<!-- Device list (top right) -->
<!-- This node -->
<!-- This device -->
<div class="col-md-6">
<div class="panel panel-default" ng-repeat="nodeCfg in [thisNode()]">
<div class="panel-heading" data-toggle="collapse" href="#node-this" style="cursor: pointer">
<div class="panel panel-default" ng-repeat="deviceCfg in [thisDevice()]">
<div class="panel-heading" data-toggle="collapse" href="#device-this" style="cursor: pointer">
<h3 class="panel-title">
<span class="glyphicon glyphicon-home"></span>&emsp;{{nodeName(nodeCfg)}}
<identicon data-value="deviceCfg.DeviceID"></identicon>&emsp;{{deviceName(deviceCfg)}}
</h3>
</div>
<div id="node-this" class="panel-collapse collapse in">
<div id="device-this" class="panel-collapse collapse in">
<div class="panel-body">
<table class="table table-condensed table-striped">
<tbody>
@@ -219,75 +230,75 @@
</div>
</div>
<!-- Remote nodes -->
<!-- Remote devices -->
<div class="panel-group" id="nodes">
<div class="panel panel-{{nodeClass(nodeCfg)}}" ng-repeat="nodeCfg in otherNodes()">
<div class="panel-heading" data-toggle="collapse" data-parent="#nodes" href="#node-{{$index}}" style="cursor: pointer">
<div class="panel-group" id="devices">
<div class="panel panel-{{deviceClass(deviceCfg)}}" ng-repeat="deviceCfg in otherDevices()">
<div class="panel-heading" data-toggle="collapse" data-parent="#devices" href="#device-{{$index}}" style="cursor: pointer">
<h3 class="panel-title">
<span class="glyphicon glyphicon-retweet"></span>&emsp;{{nodeName(nodeCfg)}}
<identicon data-value="deviceCfg.DeviceID"></identicon>&emsp;{{deviceName(deviceCfg)}}
<span class="pull-right hidden-xs">
<span ng-if="connections[nodeCfg.NodeID] && completion[nodeCfg.NodeID]._total == 100">
<span ng-if="connections[deviceCfg.DeviceID] && completion[deviceCfg.DeviceID]._total == 100">
<span translate>Up to Date</span> (100%)
</span>
<span ng-if="connections[nodeCfg.NodeID] && completion[nodeCfg.NodeID]._total < 100">
<span translate>Syncing</span> ({{completion[nodeCfg.NodeID]._total | number:0}}%)
<span ng-if="connections[deviceCfg.DeviceID] && completion[deviceCfg.DeviceID]._total < 100">
<span translate>Syncing</span> ({{completion[deviceCfg.DeviceID]._total | number:0}}%)
</span>
<span translate ng-if="!connections[nodeCfg.NodeID]">Disconnected</span>
<span translate ng-if="!connections[deviceCfg.DeviceID]">Disconnected</span>
</span>
</h3>
</div>
<div id="node-{{$index}}" class="panel-collapse collapse">
<div id="device-{{$index}}" class="panel-collapse collapse">
<div class="panel-body">
<table class="table table-condensed table-striped">
<tbody>
<tr ng-if="connections[nodeCfg.NodeID]">
<tr ng-if="connections[deviceCfg.DeviceID]">
<th><span class="glyphicon glyphicon-cloud-download"></span>&emsp;<span translate>Download Rate</span></th>
<td class="text-right">{{connections[nodeCfg.NodeID].inbps | metric}}bps ({{connections[nodeCfg.NodeID].InBytesTotal | binary}}B)</td>
<td class="text-right">{{connections[deviceCfg.DeviceID].inbps | metric}}bps ({{connections[deviceCfg.DeviceID].InBytesTotal | binary}}B)</td>
</tr>
<tr ng-if="connections[nodeCfg.NodeID]">
<tr ng-if="connections[deviceCfg.DeviceID]">
<th><span class="glyphicon glyphicon-cloud-upload"></span>&emsp;<span translate>Upload Rate</span></th>
<td class="text-right">{{connections[nodeCfg.NodeID].outbps | metric}}bps ({{connections[nodeCfg.NodeID].OutBytesTotal | binary}}B)</td>
<td class="text-right">{{connections[deviceCfg.DeviceID].outbps | metric}}bps ({{connections[deviceCfg.DeviceID].OutBytesTotal | binary}}B)</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-link"></span>&emsp;<span translate>Address</span></th>
<td class="text-right">{{nodeAddr(nodeCfg)}}</td>
<td class="text-right">{{deviceAddr(deviceCfg)}}</td>
</tr>
<tr ng-if="connections[nodeCfg.NodeID]">
<tr ng-if="connections[deviceCfg.DeviceID]">
<th><span class="glyphicon glyphicon-comment"></span>&emsp;<span translate>Synchronization</span></th>
<td class="text-right">{{completion[nodeCfg.NodeID]._total | alwaysNumber | number:0}}%</td>
<td class="text-right">{{completion[deviceCfg.DeviceID]._total | alwaysNumber | number:0}}%</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-compressed"></span>&emsp;<span translate>Use Compression</span></th>
<td translate ng-if="nodeCfg.Compression" class="text-right">Yes</td>
<td translate ng-if="!nodeCfg.Compression" class="text-right">No</td>
<td translate ng-if="deviceCfg.Compression" class="text-right">Yes</td>
<td translate ng-if="!deviceCfg.Compression" class="text-right">No</td>
</tr>
<tr>
<th><span class="glyphicon glyphicon-thumbs-up"></span>&emsp;<span translate>Introducer</span></th>
<td translate ng-if="nodeCfg.Introducer" class="text-right">Yes</td>
<td translate ng-if="!nodeCfg.Introducer" class="text-right">No</td>
<td translate ng-if="deviceCfg.Introducer" class="text-right">Yes</td>
<td translate ng-if="!deviceCfg.Introducer" class="text-right">No</td>
</tr>
<tr ng-if="connections[nodeCfg.NodeID]">
<tr ng-if="connections[deviceCfg.DeviceID]">
<th><span class="glyphicon glyphicon-tag"></span>&emsp;<span translate>Version</span></th>
<td class="text-right">{{connections[nodeCfg.NodeID].ClientVersion}}</td>
<td class="text-right">{{connections[deviceCfg.DeviceID].ClientVersion}}</td>
</tr>
<tr ng-if="!connections[nodeCfg.NodeID]">
<tr ng-if="!connections[deviceCfg.DeviceID]">
<th><span class="glyphicon glyphicon-eye-open"></span>&emsp;<span translate>Last seen</span></th>
<td translate ng-if="!stats[nodeCfg.NodeID].LastSeenDays || stats[nodeCfg.NodeID].LastSeenDays >= 365" class="text-right">Never</td>
<td ng-if="stats[nodeCfg.NodeID].LastSeenDays < 365" class="text-right">{{stats[nodeCfg.NodeID].LastSeen | date:"yyyy-MM-dd HH:mm"}}</td>
<td translate ng-if="!stats[deviceCfg.DeviceID].LastSeenDays || stats[deviceCfg.DeviceID].LastSeenDays >= 365" class="text-right">Never</td>
<td ng-if="stats[deviceCfg.DeviceID].LastSeenDays < 365" class="text-right">{{stats[deviceCfg.DeviceID].LastSeen | date:"yyyy-MM-dd HH:mm"}}</td>
</tr>
</tbody>
</table>
</div>
<div class="panel-footer">
<span class="pull-right"><a class="btn btn-sm btn-default" href="" ng-click="editNode(nodeCfg)"><span class="glyphicon glyphicon-pencil"></span>&emsp;<span translate>Edit</span></a></span>
<span class="pull-right"><a class="btn btn-sm btn-default" href="" ng-click="editDevice(deviceCfg)"><span class="glyphicon glyphicon-pencil"></span>&emsp;<span translate>Edit</span></a></span>
<div class="clearfix"></div>
</div>
</div>
</div>
</div>
<div class="form-group">
<button class="btn btn-sm btn-default pull-right" ng-click="addNode()"><span class="glyphicon glyphicon-plus"></span>&emsp;<span translate>Add Node</span></button>
<button class="btn btn-sm btn-default pull-right" ng-click="addDevice()"><span class="glyphicon glyphicon-plus"></span>&emsp;<span translate>Add Device</span></button>
<div class="clearfix"></div>
</div>
</div>
@@ -300,7 +311,7 @@
<div class="panel panel-warning">
<div class="panel-heading"><h3 class="panel-title"><span translate>Notice</span></h3></div>
<div class="panel-body">
<p ng-repeat="err in errorList()"><small>{{err.Time | date:"H:mm:ss"}}:</small> {{friendlyNodes(err.Error)}}</p>
<p ng-repeat="err in errorList()"><small>{{err.Time | date:"H:mm:ss"}}:</small> {{friendlyDevices(err.Error)}}</p>
</div>
<div class="panel-footer">
<button type="button" class="pull-right btn btn-sm btn-default" ng-click="clearErrors()"><span class="glyphicon glyphicon-ok"></span>&emsp;<span translate>OK</span></button>
@@ -354,48 +365,51 @@
<!-- ID modal -->
<modal id="idqr" large="yes" status="info" close="yes" icon="qrcode" title="{{'Node Identification' | translate}} &mdash; {{nodeName(thisNode())}}">
<modal id="idqr" large="yes" status="info" close="yes" icon="qrcode" title="{{'Device Identification' | translate}} &mdash; {{deviceName(thisDevice())}}">
<div class="well well-sm text-monospace text-center">{{myID}}</div>
<img ng-if="myID" class="center-block img-thumbnail" src="qr/?text={{myID}}"/>
</modal>
<!-- Node editor modal -->
<!-- Device editor modal -->
<div id="editNode" class="modal fade" tabindex="-1">
<div id="editDevice" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 translate ng-show="!editingExisting" class="modal-title">Add Node</h4>
<h4 translate ng-show="editingExisting" class="modal-title">Edit Node</h4>
<h4 translate ng-show="!editingExisting" class="modal-title">Add Device</h4>
<h4 translate ng-show="editingExisting" class="modal-title">Edit Device</h4>
</div>
<div class="modal-body">
<form role="form" name="nodeEditor">
<div class="form-group" ng-class="{'has-error': nodeEditor.nodeID.$invalid && nodeEditor.nodeID.$dirty}">
<label translate for="nodeID">Node ID</label>
<input ng-if="!editingExisting" name="nodeID" id="nodeID" class="form-control text-monospace" type="text" ng-model="currentNode.NodeID" required valid-nodeid></input>
<div ng-if="editingExisting" class="well well-sm text-monospace">{{currentNode.NodeID}}</div>
<form role="form" name="deviceEditor">
<div class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}">
<label translate for="deviceID">Device ID</label>
<input ng-if="!editingExisting" name="deviceID" id="deviceID" class="form-control text-monospace" type="text" ng-model="currentDevice.DeviceID" required valid-deviceid list="discovery-list" />
<datalist id="discovery-list" ng-if="!editingExisting">
<option ng-repeat="(id,address) in discovery" value="{{ id }}" />
</datalist>
<div ng-if="editingExisting" class="well well-sm text-monospace">{{currentDevice.DeviceID}}</div>
<p class="help-block">
<span translate ng-if="nodeEditor.nodeID.$valid || nodeEditor.nodeID.$pristine">The node ID to enter here can be found in the "Edit > Show ID" dialog on the other node. Spaces and dashes are optional (ignored).</span>
<span translate ng-show="!editingExisting && (nodeEditor.nodeID.$valid || nodeEditor.nodeID.$pristine)">When adding a new node, keep in mind that this node must be added on the other side too.</span>
<span translate ng-if="nodeEditor.nodeID.$error.required && nodeEditor.nodeID.$dirty">The node ID cannot be blank.</span>
<span translate ng-if="nodeEditor.nodeID.$error.validNodeid && nodeEditor.nodeID.$dirty">The entered node 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.</span>
<span translate ng-if="deviceEditor.deviceID.$valid || deviceEditor.deviceID.$pristine">The device ID to enter here can be found in the "Edit > Show ID" dialog on the other device. Spaces and dashes are optional (ignored).</span>
<span translate ng-show="!editingExisting && (deviceEditor.deviceID.$valid || deviceEditor.deviceID.$pristine)">When adding a new device, keep in mind that this device must be added on the other side too.</span>
<span translate ng-if="deviceEditor.deviceID.$error.required && deviceEditor.deviceID.$dirty">The device ID cannot be blank.</span>
<span translate ng-if="deviceEditor.deviceID.$error.validDeviceid && deviceEditor.deviceID.$dirty">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.</span>
</p>
</div>
<div class="form-group">
<label translate for="name">Node Name</label>
<input placeholder="Home Server" id="name" class="form-control" type="text" ng-model="currentNode.Name"></input>
<p translate ng-if="currentNode.NodeID == myID" class="help-block">Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.</p>
<p translate ng-if="currentNode.NodeID != myID" class="help-block">Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.</p>
<label translate for="name">Device Name</label>
<input id="name" class="form-control" type="text" ng-model="currentDevice.Name"></input>
<p translate ng-if="currentDevice.DeviceID == myID" class="help-block">Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.</p>
<p translate ng-if="currentDevice.DeviceID != myID" class="help-block">Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.</p>
</div>
<div class="form-group">
<label translate for="addresses">Addresses</label>
<input placeholder="dynamic" ng-disabled="currentNode.NodeID == myID" id="addresses" class="form-control" type="text" ng-model="currentNode.AddressesStr"></input>
<input ng-disabled="currentDevice.DeviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice.AddressesStr"></input>
<p translate class="help-block">Enter comma separated "ip:port" addresses or "dynamic" to perform automatic discovery of the address.</p>
</div>
<div ng-if="!editingSelf" class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentNode.Compression"> <span translate>Use Compression</span>
<input type="checkbox" ng-model="currentDevice.Compression"> <span translate>Use Compression</span>
</label>
<p translate class="help-block">Compression is recommended in most setups.</p>
</div>
@@ -403,58 +417,58 @@
<div ng-if="!editingSelf" class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentNode.Introducer"> <span translate>Introducer</span>
<input type="checkbox" ng-model="currentDevice.Introducer"> <span translate>Introducer</span>
</label>
<p translate class="help-block">Any nodes configured on an introducer node will be added to this node as well.</p>
<p translate class="help-block">Any devices configured on an introducer device will be added to this device as well.</p>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveNode()" ng-disabled="nodeEditor.$invalid"><span class="glyphicon glyphicon-ok"></span>&emsp;<span translate>Save</span></button>
<button type="button" class="btn btn-primary btn-sm" ng-click="saveDevice()" ng-disabled="deviceEditor.$invalid"><span class="glyphicon glyphicon-ok"></span>&emsp;<span translate>Save</span></button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;<span translate>Close</span></button>
<button ng-if="editingExisting && !editingSelf" type="button" class="btn btn-danger pull-left btn-sm" ng-click="deleteNode()"><span class="glyphicon glyphicon-minus"></span>&emsp;<span translate>Delete</span></button>
<button ng-if="editingExisting && !editingSelf" type="button" class="btn btn-danger pull-left btn-sm" ng-click="deleteDevice()"><span class="glyphicon glyphicon-minus"></span>&emsp;<span translate>Delete</span></button>
</div>
</div>
</div>
</div>
<!-- Repo editor modal -->
<!-- Folder editor modal -->
<div id="editRepo" class="modal fade" tabindex="-1">
<div id="editFolder" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 ng-show="!editingExisting" class="modal-title"><span translate>Add Repository</span></h4>
<h4 ng-show="editingExisting" class="modal-title"><span translate>Edit Repository</span></h4>
<h4 ng-show="!editingExisting" class="modal-title"><span translate>Add Folder</span></h4>
<h4 ng-show="editingExisting" class="modal-title"><span translate>Edit Folder</span></h4>
</div>
<div class="modal-body">
<form role="form" name="repoEditor">
<form role="form" name="folderEditor">
<div class="row">
<div class="col-md-12">
<div class="form-group" ng-class="{'has-error': repoEditor.repoID.$invalid && repoEditor.repoID.$dirty}">
<label for="repoID"><span translate>Repository ID</span></label>
<input name="repoID" placeholder="documents" ng-disabled="editingExisting" id="repoID" class="form-control" type="text" ng-model="currentRepo.ID" required unique-repo ng-pattern="/^[a-zA-Z0-9-_.]{1,64}$/"></input>
<div class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<label for="folderID"><span translate>Folder ID</span></label>
<input name="folderID" ng-readonly="editingExisting" id="folderID" class="form-control" type="text" ng-model="currentFolder.ID" required unique-folder ng-pattern="/^[a-zA-Z0-9-_.]{1,64}$/"></input>
<p class="help-block">
<span translate ng-if="repoEditor.repoID.$valid || repoEditor.repoID.$pristine">Short identifier for the repository. Must be the same on all cluster nodes.</span>
<span translate ng-if="repoEditor.repoID.$error.uniqueRepo">The repository ID must be unique.</span>
<span translate ng-if="repoEditor.repoID.$error.required && repoEditor.repoID.$dirty">The repository ID cannot be blank.</span>
<span translate ng-if="repoEditor.repoID.$error.pattern && repoEditor.repoID.$dirty">The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.</span>
<span translate ng-if="folderEditor.folderID.$valid || folderEditor.folderID.$pristine">Short identifier for the folder. Must be the same on all cluster devices.</span>
<span translate ng-if="folderEditor.folderID.$error.uniqueFolder">The folder ID must be unique.</span>
<span translate ng-if="folderEditor.folderID.$error.required && folderEditor.folderID.$dirty">The folder ID cannot be blank.</span>
<span translate ng-if="folderEditor.folderID.$error.pattern && folderEditor.folderID.$dirty">The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': repoEditor.repoPath.$invalid && repoEditor.repoPath.$dirty}">
<label translate for="repoPath">Repository Path</label>
<input name="repoPath" placeholder="~/Documents" ng-disabled="editingExisting" id="repoPath" class="form-control" type="text" ng-model="currentRepo.Directory" required></input>
<div class="form-group" ng-class="{'has-error': folderEditor.folderPath.$invalid && folderEditor.folderPath.$dirty}">
<label translate for="folderPath">Folder Path</label>
<input name="folderPath" ng-readonly="editingExisting" id="folderPath" class="form-control" type="text" ng-model="currentFolder.Path" required></input>
<p class="help-block">
<span translate ng-if="repoEditor.repoPath.$valid || repoEditor.repoPath.$pristine">Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for</span> <code>{{system.tilde}}</code>.
<span translate ng-if="repoEditor.repoPath.$error.required && repoEditor.repoPath.$dirty">The repository path cannot be blank.</span>
<span translate ng-if="folderEditor.folderPath.$valid || folderEditor.folderPath.$pristine">Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for</span> <code>{{system.tilde}}</code>.
<span translate ng-if="folderEditor.folderPath.$error.required && folderEditor.folderPath.$dirty">The folder path cannot be blank.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': repoEditor.rescanIntervalS.$invalid && repoEditor.rescanIntervalS.$dirty}">
<div class="form-group" ng-class="{'has-error': folderEditor.rescanIntervalS.$invalid && folderEditor.rescanIntervalS.$dirty}">
<label for="rescanIntervalS"><span translate>Rescan Interval</span> (s)</label>
<input name="rescanIntervalS" placeholder="60" id="rescanIntervalS" class="form-control" type="number" ng-model="currentRepo.RescanIntervalS" required min="5"></input>
<input name="rescanIntervalS" id="rescanIntervalS" class="form-control" type="number" ng-model="currentFolder.RescanIntervalS" required min="0"></input>
<p class="help-block">
<span translate ng-if="!repoEditor.rescanIntervalS.$valid && repoEditor.rescanIntervalS.$dirty">The rescan interval must be at least 5 seconds.</span>
<span translate ng-if="!folderEditor.rescanIntervalS.$valid && folderEditor.rescanIntervalS.$dirty">The rescan interval must be a non-negative number of seconds.</span>
</p>
</div>
</div>
@@ -464,27 +478,27 @@
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentRepo.ReadOnly"> <span translate>Repository Master</span>
<input type="checkbox" ng-model="currentFolder.ReadOnly"> <span translate>Folder Master</span>
</label>
</div>
<p translate class="help-block">Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.</p>
<p translate class="help-block">Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.</p>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentRepo.IgnorePerms"> <span translate>Ignore Permissions</span>
<input type="checkbox" ng-model="currentFolder.IgnorePerms"> <span translate>Ignore Permissions</span>
</label>
</div>
<p translate class="help-block">File permission bits are ignored when looking for changes. Use on FAT filesystems.</p>
</div>
<div class="form-group">
<label translate for="nodes">Share With Nodes</label>
<div class="checkbox" ng-repeat="node in otherNodes()">
<label translate for="devices">Share With Devices</label>
<div class="checkbox" ng-repeat="device in otherDevices()">
<label>
<input type="checkbox" ng-model="currentRepo.selectedNodes[node.NodeID]"> {{nodeName(node)}}
<input type="checkbox" ng-model="currentFolder.selectedDevices[device.DeviceID]"> {{deviceName(device)}}
</label>
</div>
<p translate class="help-block">Select the nodes to share this repository with.</p>
<p translate class="help-block">Select the devices to share this folder with.</p>
</div>
</div>
<div class="col-md-6">
@@ -492,54 +506,54 @@
<label translate>File Versioning</label>
<div class="radio">
<label>
<input type="radio" ng-model="currentRepo.FileVersioningSelector" value="none"> <span translate>No File Versioning</span>
<input type="radio" ng-model="currentFolder.FileVersioningSelector" value="none"> <span translate>No File Versioning</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" ng-model="currentRepo.FileVersioningSelector" value="simple"> <span translate>Simple File Versioning</span>
<input type="radio" ng-model="currentFolder.FileVersioningSelector" value="simple"> <span translate>Simple File Versioning</span>
</label>
</div>
<div class="radio">
<label>
<input type="radio" ng-model="currentRepo.FileVersioningSelector" value="staggered"> <span translate>Staggered File Versioning</span>
<input type="radio" ng-model="currentFolder.FileVersioningSelector" value="staggered"> <span translate>Staggered File Versioning</span>
</label>
</div>
</div>
<div class="form-group" ng-if="currentRepo.FileVersioningSelector=='simple'" ng-class="{'has-error': repoEditor.simpleKeep.$invalid && repoEditor.simpleKeep.$dirty}">
<div class="form-group" ng-if="currentFolder.FileVersioningSelector=='simple'" ng-class="{'has-error': folderEditor.simpleKeep.$invalid && folderEditor.simpleKeep.$dirty}">
<p translate class="help-block">Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.</p>
<label translate for="simpleKeep">Keep Versions</label>
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentRepo.simpleKeep" required min="1"></input>
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentFolder.simpleKeep" required min="1"></input>
<p class="help-block">
<span translate ng-if="repoEditor.simpleKeep.$valid || repoEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="repoEditor.simpleKeep.$error.required && repoEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="repoEditor.simpleKeep.$error.min && repoEditor.simpleKeep.$dirty">You must keep at least one version.</span>
<span translate ng-if="folderEditor.simpleKeep.$valid || folderEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.required && folderEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.min && folderEditor.simpleKeep.$dirty">You must keep at least one version.</span>
</p>
</div>
<div class="form-group" ng-if="currentRepo.FileVersioningSelector=='staggered'" ng-class="{'has-error': repoEditor.staggeredMaxAge.$invalid && repoEditor.staggeredMaxAge.$dirty}">
<div class="form-group" ng-if="currentFolder.FileVersioningSelector=='staggered'" ng-class="{'has-error': folderEditor.staggeredMaxAge.$invalid && folderEditor.staggeredMaxAge.$dirty}">
<p class="help-block"><span translate>Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.</span> <span translate>Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.</span></p>
<p translate class="help-block">The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.</p>
<label translate for="staggeredMaxAge">Maximum Age</label>
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentRepo.staggeredMaxAge" required></input>
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentFolder.staggeredMaxAge" required></input>
<p class="help-block">
<span translate ng-if="repoEditor.staggeredMaxAge.$valid || repoEditor.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="repoEditor.staggeredMaxAge.$error.required && repoEditor.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$valid || folderEditor.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.required && folderEditor.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
</p>
</div>
<div class="form-group" ng-if="currentRepo.FileVersioningSelector == 'staggered'">
<div class="form-group" ng-if="currentFolder.FileVersioningSelector == 'staggered'">
<label translate for="staggeredVersionsPath">Versions Path</label>
<input name="staggeredVersionsPath" placeholder="" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentRepo.staggeredVersionsPath"></input>
<p translate class="help-block">Path where versions should be stored (leave empty for the default .stversions folder in the repository).</p>
<input name="staggeredVersionsPath" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentFolder.staggeredVersionsPath"></input>
<p translate class="help-block">Path where versions should be stored (leave empty for the default .stversions folder in the folder).</p>
</div>
</div>
</div>
</form>
<div translate ng-show="!editingExisting">When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.</div>
<div translate ng-show="!editingExisting">When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveRepo()" ng-disabled="repoEditor.$invalid"><span class="glyphicon glyphicon-ok"></span>&emsp;<span translate>Save</span></button>
<button type="button" class="btn btn-primary btn-sm" ng-click="saveFolder()" ng-disabled="folderEditor.$invalid"><span class="glyphicon glyphicon-ok"></span>&emsp;<span translate>Save</span></button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;<span translate>Close</span></button>
<button ng-if="editingExisting" type="button" class="btn btn-danger pull-left btn-sm" ng-click="deleteRepo()"><span class="glyphicon glyphicon-minus"></span>&emsp;<span translate>Delete</span></button>
<button ng-if="editingExisting" type="button" class="btn btn-danger pull-left btn-sm" ng-click="deleteFolder()"><span class="glyphicon glyphicon-minus"></span>&emsp;<span translate>Delete</span></button>
<button id="editIgnoresButton" ng-if="editingExisting" type="button" class="btn btn-default pull-left btn-sm" ng-click="editIgnores()"><span class="glyphicon glyphicon-eye-close"></span>&emsp;<span translate>Ignore Patterns</span></button>
</div>
</div>
@@ -569,7 +583,7 @@
</dl>
</div>
<div class="modal-footer">
<div class="pull-left"><span translate>Editing</span> <code>{{currentRepo.Directory}}/.stignore</code></div>
<div class="pull-left"><span translate>Editing</span> <code>{{currentFolder.Path}}/.stignore</code></div>
<button type="button" class="btn btn-primary btn-sm" data-dismiss="modal" ng-click="saveIgnores()"><span class="glyphicon glyphicon-ok"></span>&emsp;<span translate>Save</span></button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;<span translate>Close</span></button>
</div>
@@ -591,8 +605,8 @@
<div class="col-md-6">
<div class="form-group">
<label translate for="NodeName">Node Name</label>
<input id="NodeName" class="form-control" type="text" ng-model="tmpOptions.NodeName">
<label translate for="DeviceName">Device Name</label>
<input id="DeviceName" class="form-control" type="text" ng-model="tmpOptions.DeviceName">
</div>
<div class="form-group">
<label translate for="ListenStr">Sync Protocol Listen Addresses</label>
@@ -606,26 +620,36 @@
<label translate for="MaxSendKbps">Outgoing Rate Limit (KiB/s)</label>
<input id="MaxSendKbps" class="form-control" type="number" ng-model="tmpOptions.MaxSendKbps">
</div>
<div class="form-group">
<div class="checkbox">
<label>
<span translate>Enable UPnP</span> <input id="UPnPEnabled" type="checkbox" ng-model="tmpOptions.UPnPEnabled">
</label>
<div class="col-md-6">
<div class="form-group">
<div class="checkbox">
<label>
<span translate>Enable UPnP</span> <input id="UPnPEnabled" type="checkbox" ng-model="tmpOptions.UPnPEnabled">
</label>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<span translate>Global Discovery</span> <input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.GlobalAnnEnabled">
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<span translate>Local Discovery</span> <input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.LocalAnnEnabled">
</label>
<div class="col-md-6">
<div class="form-group">
<div class="checkbox">
<label ng-if="upgradeInfo">
<span translate>Automatic upgrades</span> <input id="AutoUpgradeEnabled" type="checkbox" ng-model="tmpOptions.AutoUpgradeEnabled">
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<span translate>Global Discovery</span> <input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.GlobalAnnEnabled">
</label>
<div class="form-group">
<div class="checkbox">
<label>
<span translate>Local Discovery</span> <input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.LocalAnnEnabled">
</label>
</div>
</div>
</div>
<div class="form-group">
@@ -698,7 +722,7 @@
<h4 translate class="modal-title">Allow Anonymous Usage Reporting?</h4>
</div>
<div class="modal-body">
<p translate>The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.</p>
<p translate>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.</p>
<p translate translate-value-url="https://data.syncthing.net">The aggregated statistics are publicly available at {%url%}.</p>
<button translate type="button" class="btn btn-default btn-sm" ng-show="!reportPreview" ng-click="showReportPreview()">Preview Usage Report</button>
<pre ng-if="reportPreview"><small>{{reportData | json}}</small></pre>
@@ -720,7 +744,7 @@
<h4 translate class="modal-title">Anonymous Usage Reporting</h4>
</div>
<div class="modal-body">
<p translate>The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.</p>
<p translate>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.</p>
<p translate translate-value-url="https://data.syncthing.net">The aggregated statistics are publicly available at {%url%}.</p>
<pre><small>{{reportData | json}}</small></pre>
</div>
@@ -760,20 +784,28 @@
<li>Audrius Butkevicius</li>
<li>Ben Sidhom</li>
<li>Brandon Philips</li>
<li>Caleb Callaway</li>
<li>Chris Joel</li>
<li>Daniel Martí</li>
<li>Felix Ableitner</li>
<li>Felix Unterpaintner</li>
<li>Gilli Sigurdsson</li>
<li>James Patterson</li>
</ul>
</div>
<div class="col-md-6">
<ul>
<li>James Patterson</li>
<li>Jens Diemer</li>
<li>Jochen Voss</li>
<li>Lode Hoste</li>
<li>Marcin Dziadus</li>
<li>Michael Tilli</li>
<li>Philippe Schommers</li>
<li>Phill Luby</li>
<li>Ryan Sullivan</li>
<li>Tully Robinson</li>
<li>Veeti Paananen</li>
<li>Vil Brekin</li>
</ul>
</div>
</div>
@@ -793,7 +825,6 @@
</ul>
</modal>
<script src="angular/angular.min.js"></script>
<script src="angular/angular-translate.min.js"></script>
<script src="angular/angular-translate-loader.min.js"></script>

140
gui/lang/lang-be.json Normal file
View File

@@ -0,0 +1,140 @@
{
"API Key": "Ключ API",
"About": "Аб праграме",
"Add Device": "Дадаць прыладу",
"Add Folder": "Дадаць каталёг",
"Address": "Адрас",
"Addresses": "Адрасы",
"Allow Anonymous Usage Reporting?": "Allow Anonymous Usage Reporting?",
"Anonymous Usage Reporting": "Anonymous Usage Reporting",
"Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.",
"Bugs": "Bugs",
"CPU Utilization": "CPU Utilization",
"Close": "Close",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Connection Error": "Connection Error",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg and the following Contributors:",
"Delete": "Delete",
"Device ID": "Device ID",
"Device Identification": "Device Identification",
"Device Name": "Device Name",
"Disconnected": "Disconnected",
"Documentation": "Documentation",
"Download Rate": "Download Rate",
"Edit": "Edit",
"Edit Device": "Edit Device",
"Edit Folder": "Edit Folder",
"Editing": "Editing",
"Enable UPnP": "Enable UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Error",
"File Versioning": "File Versioning",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "File permission bits are ignored when looking for changes. Use on FAT filesystems.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.",
"Folder ID": "Folder ID",
"Folder Master": "Folder Master",
"Folder Path": "Folder Path",
"GUI Authentication Password": "GUI Authentication Password",
"GUI Authentication User": "GUI Authentication User",
"GUI Listen Addresses": "GUI Listen Addresses",
"Generate": "Generate",
"Global Discovery": "Global Discovery",
"Global Discovery Server": "Global Discovery Server",
"Global State": "Global State",
"Idle": "Idle",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "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": "Keep Versions",
"Last seen": "Last seen",
"Latest Release": "Latest Release",
"Local Discovery": "Local Discovery",
"Local State": "Local State",
"Maximum Age": "Maximum Age",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Never",
"No": "No",
"No File Versioning": "No File Versioning",
"Notice": "Notice",
"OK": "OK",
"Offline": "Offline",
"Online": "Online",
"Out Of Sync": "Out Of Sync",
"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",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Path where versions should be stored (leave empty for the default .stversions folder in the folder).",
"Please wait": "Please wait",
"Preview": "Preview",
"Preview Usage Report": "Preview Usage Report",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "RAM Utilization",
"Rescan": "Rescan",
"Rescan Interval": "Rescan Interval",
"Restart": "Restart",
"Restart Needed": "Restart Needed",
"Restarting": "Restarting",
"Save": "Save",
"Scanning": "Scanning",
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
"Settings": "Settings",
"Share With Devices": "Share With Devices",
"Shared With": "Shared With",
"Short identifier for the folder. Must be the same on all cluster devices.": "Short identifier for the folder. Must be the same on all cluster devices.",
"Show ID": "Show 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",
"Simple File Versioning": "Simple File Versioning",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Source Code": "Source Code",
"Staggered File Versioning": "Staggered File Versioning",
"Start Browser": "Start Browser",
"Stopped": "Stopped",
"Support / Forum": "Support / Forum",
"Sync Protocol Listen Addresses": "Sync Protocol Listen Addresses",
"Synchronization": "Synchronization",
"Syncing": "Syncing",
"Syncthing has been shut down.": "Syncthing has been shut down.",
"Syncthing includes the following software or portions thereof:": "Syncthing includes the following software or portions thereof:",
"Syncthing is restarting.": "Syncthing is restarting.",
"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 aggregated statistics are publicly available at {%url%}.": "The aggregated statistics are publicly available at {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.",
"The device ID cannot be blank.": "The device ID cannot be blank.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.",
"The folder ID cannot be blank.": "The folder ID cannot be blank.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"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 old versions to keep, per file.",
"The number of versions must be a number and cannot be blank.": "The number of versions must be a number and cannot be blank.",
"The rescan interval must be at least 5 seconds.": "The rescan interval must be at least 5 seconds.",
"Unknown": "Unknown",
"Up to Date": "Up to Date",
"Upgrade To {%version%}": "Upgrade To {{version}}",
"Upgrading": "Upgrading",
"Upload Rate": "Upload Rate",
"Use Compression": "Use Compression",
"Use HTTPS for GUI": "Use HTTPS for GUI",
"Version": "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": "Yes",
"You must keep at least one version.": "You must keep at least one version.",
"full documentation": "full documentation",
"items": "items"
}

View File

@@ -1,68 +1,65 @@
{
"API Key": "API Ключ",
"About": "За Програмата",
"Add Node": "Добави Машина",
"Add Repository": "Добави Папка",
"Add Device": "Add Device",
"Add Folder": "Add Folder",
"Address": "Адрес",
"Addresses": "Адреси",
"Allow Anonymous Usage Reporting?": "Разреши анонимен доклад за ползване на програмата?",
"Announce Server": "Announce Server",
"Anonymous Usage Reporting": "Анонимен Доклад",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.",
"Bugs": "Бъгове",
"CPU Utilization": "Натоварване на Процесора",
"Close": "Затвори",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Comment, when used at the start of a line": "Коментар, използван в началото на реда",
"Compression is recommended in most setups.": "Компресията е препоръчителна в повечето конфигурации.",
"Connection Error": "Грешка при Свързването",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Правата запазени © 2014 Jakob Borg и следните Сътрудници:",
"Delete": "Изтрий",
"Device ID": "Device ID",
"Device Identification": "Device Identification",
"Device Name": "Device Name",
"Disconnected": "Прекрати Връзката",
"Documentation": "Документация",
"Download Rate": "Скорост на Теглене",
"Edit": "Промени",
"Edit Node": "Промени Машината",
"Edit Repository": "Промени Папката",
"Editing": "Editing",
"Edit Device": "Edit Device",
"Edit Folder": "Edit Folder",
"Editing": "Променяне",
"Enable UPnP": "Включи UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Въведи \"ip:port\" адреси разделени със запетая или \"dynamic\", за да извършиш автоматична връзка на адреси.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Enter ignore patterns, one per line.": "Добави шаблони за игнориране, по един на ред.",
"Error": "Грешка",
"File Versioning": "Файлови Версии",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Битовете за права за достъп са игнорирани, когато се проверява за промени. Използвай с файлови системи тип FAT.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Когато syncthing замени или изтрие файл той се премества в .stversions и преименува с дабавени дата и час.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Файловете са защитени от промени направени на други машини, но промени направени на тази машина ще бъдат синхронизирани до другите машини.",
"Folder": "Папка",
"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": "Folder ID",
"Folder Master": "Folder Master",
"Folder Path": "Folder Path",
"GUI Authentication Password": "Парола за Потребителския Интерфейс",
"GUI Authentication User": "Потребител за Потребителския Интерфейс",
"GUI Listen Addresses": "Адрес за Свързване с Потребителския Интерфейс",
"Generate": "Генерирай",
"Global Discovery": "Глобавно Откриване",
"Global Discovery Server": "Сървър за Глобално Откриване",
"Global Repository": "Глобална Папка",
"Global State": "Global State",
"Idle": "Без Работа",
"Ignore Patterns": "Ignore Patterns",
"Ignore Patterns": "Шаблони за Игнориране",
"Ignore Permissions": "Игнорирай Права за Достъп",
"Incoming Rate Limit (KiB/s)": "Входящ Лимит на Скороста(KiB/s)",
"Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Inversion of the given condition (i.e. do not exclude)": "Обратното на даденото условие (пр. не изключвай)",
"Keep Versions": "Пази Версии",
"Last seen": "Последно видян",
"Latest Release": "Най-новата Версия",
"Local Discovery": "Локално Откриване",
"Local Discovery Port": "Порт за Локално Откриване",
"Local Repository": "Локална Папка",
"Master Repo": "Главна Папка",
"Max File Change Rate (KiB/s)": "Макс. Скорост на Промяна (KiB/s)",
"Max Outstanding Requests": "Макс. Неизпълени Заявки",
"Local State": "Local State",
"Maximum Age": "Максимална Възраст",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Multi level wildcard (matches multiple directory levels)": "Маска на много нива (покрива папки с много нива)",
"Never": "Никога",
"No": "Не",
"No File Versioning": "Няма Файлови Версии",
"Node ID": "Код на Машината",
"Node Identification": "Идентификация на Машината",
"Node Name": "Име на Машината",
"Notice": "Известие",
"OK": "ОК",
"Offline": "Не е на линия",
@@ -70,37 +67,31 @@
"Out Of Sync": "Не Синхронизиран",
"Outgoing Rate Limit (KiB/s)": "Лимит на Изходящата Скорост (KiB/s)",
"Override Changes": "Замени Промените",
"Path to the repository 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 folder in the repository).": "Пътят, където версиите да бъдат складирани(остави празно за папката .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 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 folder in the folder).": "Path where versions should be stored (leave empty for the default .stversions folder in the folder).",
"Please wait": "Моля изчакай",
"Preview": "Preview",
"Preview": "Преглед",
"Preview Usage Report": "Разгледай Доклада за Използване",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"Quick guide to supported patterns": "Бърз наръчник към поддържаните шаблони",
"RAM Utilization": "RAM Натоварване",
"Reconnect Interval (s)": "Интервал(и) на Свързване",
"Repository ID": "Идентификатор на Папката",
"Repository Master": "Главна Папка",
"Repository Path": "Път до Папката",
"Rescan": "Повторно Сканиране",
"Rescan Interval": "Интервал за Повторно Сканиране",
"Rescan Interval (s)": "Интеравал(и) на Сканиране",
"Restart": "Рестартирай",
"Restart Needed": "Изискава се Рестартиране",
"Restarting": "Рестартиране",
"Save": "Запази",
"Scanning": "Сканиране",
"Select the nodes to share this repository with.": "Избери компютрите, с които да споделиш тази папка.",
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
"Settings": "Настройки",
"Share With Nodes": "Сподели с Компютри",
"Share With Devices": "Share With Devices",
"Shared With": "Сподел С",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Кратък идентификатор на папката. Трябва да бъде същият на всички компютри.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Short identifier for the folder. Must be the same on all cluster devices.",
"Show ID": "Покажи Идентификатора",
"Shown instead of Node ID in the cluster status.": "Покажи вмест ID-то на Компютъра в статус на клъстъра.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Покажи вмест ID-то на Компютъра в статус на клъстъра. Ще бъде предлагано на други комютри като име по подразбиране.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Покажи вмест 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": "Спри Програмата",
"Simple File Versioning": "Просто Файлови Версии",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Single level wildcard (matches within a directory only)": "Маска на едно ниво (покрива само в папка)",
"Source Code": "Сорс Код",
"Staggered File Versioning": "Наслагващи се Файлови Версии",
"Start Browser": "Стартирай Браузъра",
@@ -116,37 +107,34 @@
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing изглежда не е включен, или има проблем с интерент връзката. Повторен опит...",
"The aggregated statistics are publicly available at {%url%}.": "Сумарната статистика е публично достъпна на {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Конфигурацията е запазена, но не е активирана. Syncthing трябва да рестартира, за да се активира новата конфигурация.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Криптираният доклад се изпраща дневно. Използва се, за да следи общи платформи, размери на папки и версии на приложението. Ако събираните данни се променят, ще бъдете информиран с подобен на този диалог.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Въведни код на машината не е валиден. Трябва да бъде 52 символа и да се състои от букви, цифри като интервалите и тиретата са пожелание.",
"The entered node 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 cannot be blank.": "The device ID cannot be blank.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.",
"The folder ID cannot be blank.": "The folder ID cannot be blank.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"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.": "Използва се следния интервал: за първия час се пази версия всеки 30 секунди, за първия ден се пази версия всеки час, за първите 30 дена се пази версия всеки ден, до максимума се пази една версия всяка седмица.",
"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 node ID cannot be blank.": "Кодът на машината не може да бъде празен.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Кодът на машината, който си въвел може да бъде намерен в \"Промени > Покажи Идентификатора\". Интервалите и тиретата са пожелание(биват прескачани).",
"The number of old versions to keep, per file.": "Броят стари версии, които да бъдат пазени за всеки файл.",
"The number of versions must be a number and cannot be blank.": "Броят версии трябва да бъде число и не може да бъде празно.",
"The repository ID cannot be blank.": "Полето идентификатор на папка не може д абъде празно.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Идентификаторът на папка трябва да бъде къс(64 символа или по-малко) състоящ се само от букви, цифри, точка(.), тире(-) и подчерта (_).",
"The repository ID must be unique.": "Идентификаторът на папката тряба да бъде уникален.",
"The repository path cannot be blank.": "Пътят до папката не може да бъде празен.",
"The rescan interval must be at least 5 seconds.": "Интервала за повторно сканиране трябва да бъде поне 5 секунди.",
"Unknown": "Неясен",
"Up to Date": "Актуален",
"Upgrade To {%version%}": "Обновен До {{version}}",
"Upgrading": "Обновяване",
"Upload Rate": "Скорост на Качване",
"Usage": "Употреба",
"Use Compression": "Използвай Компресиране",
"Use HTTPS for GUI": "Използвай HTTPS за Потребителския Интерфейс",
"Version": "Версия",
"Versions Path": "Път до Версиите",
"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 node, keep in mind that this node must be added on the other side too.": "Когато добавяш нова машина помни, че твоята машина също трябва да бъде добавена от другата страна.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Когато добавяш нов идентификатор на папка помни, че той се използва за свързване на папките на различни машини. Главни/малки букви са от значение и трябва да са еднакви на всички машини.",
"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.": "Трябва да пазиш поне една версия.",
"full documentation": "full documentation",
"full documentation": "пълна документация",
"items": "артикула"
}

View File

@@ -1,152 +0,0 @@
{
"API Key": "Clau API",
"About": "Sobre",
"Add Node": "Afegir Node",
"Add Repository": "Afegir Repositori",
"Address": "Adreça",
"Addresses": "Adreces",
"Allow Anonymous Usage Reporting?": "Permetre l'enviament anònim d'informes d'ús?",
"Announce Server": "Servidor d'anunciament",
"Anonymous Usage Reporting": "Informe anònim d'ús",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Bugs": "Bugs",
"CPU Utilization": "Utilització del CPU",
"Close": "Tancar",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Connection Error": "Error de connexió",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg i els següents contribuïdors",
"Delete": "Esborrar",
"Disconnected": "Desconnectat",
"Documentation": "Documentació",
"Download Rate": "Tasa de descarrega",
"Edit": "Editar",
"Edit Node": "Editar Node",
"Edit Repository": "Editar Repositori",
"Editing": "Editing",
"Enable UPnP": "Habilitat UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduir, separat per comes, adreces \"ip:port\" o \"dynamic\" per descobrir automàticament les adreces.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Error",
"File Versioning": "Versionat de Fitxers",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Els bits de permisos dels fitxers son ignorats quan es cerquen canvis. Utilitzar en sistemes de fitxers FAT.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Els fitxers es mouen amb l'estampat de la data a la carpeta .stversions quan son substituïts o esborrats per syncthing.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Els fitxers estan protegits de canvis fets per altres nodes, però els canvis fets en aquest node seran enviats a la resta del cluster.",
"Folder": "Carpeta",
"GUI Authentication Password": "Contrasenya d'autenticació GUI",
"GUI Authentication User": "Usuari d'autenticació GUI",
"GUI Listen Addresses": "Adreça d'escolta del GUI",
"Generate": "Generar",
"Global Discovery": "Descobriment Global",
"Global Discovery Server": "Servidor de Descobriment Global",
"Global Repository": "Repositori Global",
"Idle": "Inactiu",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Ignora Permisos",
"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": "Mantenir Versions",
"Last seen": "Vist per última vegada",
"Latest Release": "Última publicació",
"Local Discovery": "Descobriment Local",
"Local Discovery Port": "Port de Descobriment Local",
"Local Repository": "Repositori Local",
"Master Repo": "Rep Master",
"Max File Change Rate (KiB/s)": "Tasa Màxima d'intercanvi de fitxer (KiB/s)",
"Max Outstanding Requests": "Màxim de Peticions Pendents",
"Maximum Age": "Antiguitat Màxima",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Mai",
"No": "No",
"No File Versioning": "Sense Versionat de Fitxer",
"Node ID": "ID del Node",
"Node Identification": "Identificació del Node",
"Node Name": "Nom Del Node",
"Notice": "Avís",
"OK": "OK",
"Offline": "Desconnectat",
"Online": "Connectat",
"Out Of Sync": "Fora de la Sincronització",
"Outgoing Rate Limit (KiB/s)": "Tasa Límit de Sortida (KiB/s)",
"Override Changes": "Sobreescriure Canvis",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Ruta del repositori 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 folder in the repository).": "Ruta on les versions s'haurien de guardar (deixa-ho buit per fer servir el directori .stversions per defecte al repositori)",
"Please wait": "Si-us-plau espera",
"Preview": "Preview",
"Preview Usage Report": "Vista Prèvia de l'Informe d'Ús",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "Utilització de la RAM",
"Reconnect Interval (s)": "Interval de Reconnexió (s)",
"Repository ID": "ID del Repositori",
"Repository Master": "Repositori Mestre",
"Repository Path": "Ruta del Repositori",
"Rescan": "Re-escanejar",
"Rescan Interval": "Interval de re-escaneig",
"Rescan Interval (s)": "Interval de re-escaneig (s)",
"Restart": "Reiniciar",
"Restart Needed": "És Necessari Reiniciar",
"Restarting": "Reiniciant",
"Save": "Guardar",
"Scanning": "Escanejant",
"Select the nodes to share this repository with.": "Seleccionar els nodes amb els que es comparteix el repositori.",
"Settings": "Preferències",
"Share With Nodes": "Compartir Amb Els Nodes",
"Shared With": "Compartir Amb",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Identificador curt pel repositori. Ha de ser el mateix per tots els nodes del cluster.",
"Show ID": "Mostrar ID",
"Shown instead of Node ID in the cluster status.": "Mostrat en comptes del ID del Node en l'estat del cluster.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Mostrat en comptes del ID del Node en l'estat del cluster. Serà advertit als altres nodes com un nom opcional per defecte.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Mostrat en comptes del ID del Node en l'estat del cluster. S'actualitzara al nom del node si es deixa buit.",
"Shutdown": "Apagar",
"Simple File Versioning": "Versionat de Fitxers Senzill",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Source Code": "Codi Font",
"Staggered File Versioning": "Versionat de Fitxers Esglaonat",
"Start Browser": "Arrancar Navegador",
"Stopped": "Aturat",
"Support / Forum": "Suport / Fòrum",
"Sync Protocol Listen Addresses": "Adreça d'escolta del Protocol Sync",
"Synchronization": "Sincronització",
"Syncing": "Synthing",
"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 restarting.": "Reiniciant syncthing.",
"Syncthing is upgrading.": "Actualitzant syncthing.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Synthing sembla parat, o hi ha algun problema amb la connexió a Internet. Reintentant...",
"The aggregated statistics are publicly available at {%url%}.": "Les estadístiques agregades estan públicament disponibles a {{url}}.",
"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 encrypted usage report is sent daily. It is used to track common platforms, repo 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 repositoris i versions de l'aplicació. Si es canvia el conjunt de dades reportades es demanarà amb aquest diàleg de nou.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "El ID del Node introduït no sembla vàlid. Hauria de tenir 52 caràcters amb lletres i números, els espais i les barres son opcionals.",
"The entered node 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 Node 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 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 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 node ID cannot be blank.": "El ID del node no pot estar en blanc.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "El ID del node per introduir aquí es pot trobar al diàleg \"Editar > Mostrar ID\" en l'altre node. Els espais i les barres son opcionals (s'ignoren).",
"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 repository ID cannot be blank.": "El ID del repositori no pot estar en blanc.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "El ID del repositori ha de ser un identificador curt (64 caràcters o menys) format només per lletres, nombres i el punt (.), barra (-) i barra baixa (_).",
"The repository ID must be unique.": "El ID del repositori ha de ser únic",
"The repository path cannot be blank.": "La carpeta del repositori no pot estar en blanc.",
"The rescan interval must be at least 5 seconds.": "El interval de re-escaneig ha de ser com a mínim de 5 segons.",
"Unknown": "Desconegut",
"Up to Date": "Actualitzat",
"Upgrade To {%version%}": "Actualitzar a {{version}}",
"Upgrading": "Actualitzant",
"Upload Rate": "Tasa de Pujada",
"Usage": "Ús",
"Use Compression": "Utilitza compressió",
"Use HTTPS for GUI": "Utilitzar HTTPS pel GUI",
"Version": "Versió",
"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.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Quan s'afegeix un nou node recorda que aquest node s'ha d'afegir tambe a l'altre banda.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Quan s'afegeix un nou repositori recorda que el ID del repositori s'utilitza per lligar repositoris entre nodes. Es distingeix entre majúscules i minúscules i ha de ser exactament iguals entre tots els nodes.",
"Yes": "Si",
"You must keep at least one version.": "Has de mantenir com a mínim una versió.",
"full documentation": "full documentation",
"items": "Elements"
}

View File

@@ -1,152 +0,0 @@
{
"API Key": "API-nøgle",
"About": "Om",
"Add Node": "Tilføj node",
"Add Repository": "Tilføj lager",
"Address": "Adresse",
"Addresses": "Adresser",
"Allow Anonymous Usage Reporting?": "Tillad anonym brugerstatistik?",
"Announce Server": "Opslagsserver",
"Anonymous Usage Reporting": "Anonym brugerstatistik",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Bugs": "Fejl",
"CPU Utilization": "CPU-forbrug",
"Close": "Luk",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Connection Error": "Tilslutnings fejl",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg og følgende bidragsydere:",
"Delete": "Slet",
"Disconnected": "Ikke tilsluttet",
"Documentation": "Dokumentation",
"Download Rate": "Downloadhastighed",
"Edit": "Rediger",
"Edit Node": "Rediger node",
"Edit Repository": "Rediger lager",
"Editing": "Editing",
"Enable UPnP": "Anvend UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Angiv kommaseparerat \"ip:port\"-adresser eller ordet \"dynamic\" for at benytte automatisk opslag.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Fejl",
"File Versioning": "Filversionering",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Filrettigheder tages der ikke hensyn til ved synkronisering. Anvend på FAT-filsystemer.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Filer flyttes til et datostemplet versionsnavn i et .stversions-bibliotek, når de bliver opdateret eller slettet af syncthing.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Filer beskyttes mod ændringer fra andre noder, men ændringer på denne node bliver sendt til hele clusteret.",
"Folder": "Bibliotek",
"GUI Authentication Password": "GUI-kodeord",
"GUI Authentication User": "GUI-brugernavn",
"GUI Listen Addresses": "GUI-lytteadresse",
"Generate": "Opret",
"Global Discovery": "Globalt opslag",
"Global Discovery Server": "Global opslagsserver",
"Global Repository": "Global lagring",
"Idle": "Inaktiv",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Ignorér filrettigheder",
"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": "Behold versioner",
"Last seen": "Last seen",
"Latest Release": "Seneste udgivelse",
"Local Discovery": "Lokal opslag",
"Local Discovery Port": "Lokal opslagsport",
"Local Repository": "Lokal lagring",
"Master Repo": "Hovedlagring",
"Max File Change Rate (KiB/s)": "Højeste filændringshastighed (KiB/s)",
"Max Outstanding Requests": "Parallelitet",
"Maximum Age": "Maximum Age",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Never",
"No": "Nej",
"No File Versioning": "No File Versioning",
"Node ID": "Node ID",
"Node Identification": "Node identifikation",
"Node Name": "Nodenavn",
"Notice": "OBS",
"OK": "OK",
"Offline": "Offline",
"Online": "Online",
"Out Of Sync": "Ude af sync",
"Outgoing Rate Limit (KiB/s)": "Udgående hastighedsbegrænsning (KiB/s)",
"Override Changes": "Overskriv ændringer",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Sti til lagring på din lokale computer. Hvis biblioteket ikke findes vil det blive oprettet. Tegnet tilde (~) kan bruges som genvej til",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Path where versions should be stored (leave empty for the default .stversions folder in the repository).",
"Please wait": "Vent venligst",
"Preview": "Preview",
"Preview Usage Report": "Forhåndsvisning af forbrugsrapport",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "RAM-forbrug",
"Reconnect Interval (s)": "Gentilslutningsinterval (s)",
"Repository ID": "Lagrings-ID",
"Repository Master": "Hovedlagring",
"Repository Path": "Sti til lagring",
"Rescan": "Rescan",
"Rescan Interval": "Rescan Interval",
"Rescan Interval (s)": "Genscanningsinterval (s)",
"Restart": "Genstart",
"Restart Needed": "Programmet kræver genstart",
"Restarting": "Genstarter",
"Save": "Gem",
"Scanning": "Opdaterer",
"Select the nodes to share this repository with.": "Vælg hvilke noder denne lagring skal deles med.",
"Settings": "Indstillinger",
"Share With Nodes": "Del med noderne",
"Shared With": "Delt med",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Kort identifikation for denne lagring. Skal være ens på alle noder i clusteret.",
"Show ID": "Vis ID",
"Shown instead of Node ID in the cluster status.": "Vises i stedet for node-ID under clusterstatus.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.",
"Shutdown": "Luk ned",
"Simple File Versioning": "Simple File Versioning",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Source Code": "Kildekode",
"Staggered File Versioning": "Staggered File Versioning",
"Start Browser": "Start browser",
"Stopped": "Stoppet",
"Support / Forum": "Support / Forum",
"Sync Protocol Listen Addresses": "Lytteadresser for indgående forbindelser",
"Synchronization": "Synkronisering",
"Syncing": "Synkroniserer",
"Syncthing has been shut down.": "Syncthing er blevet lukket ned.",
"Syncthing includes the following software or portions thereof:": "Syncthing indeholder følgende software eller dele heraf:",
"Syncthing is restarting.": "Syncthing genstarter",
"Syncthing is upgrading.": "Syncthing opgradere",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ud til at være stoppet eller oplever problemer med din internetforbindels. Prøver igen...",
"The aggregated statistics are publicly available at {%url%}.": "Samlet statistik er offentligt tilgængelig på {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Konfigurationen er gemt, men ikke aktiveret. Syncthing skal genstarte for at aktivere den nye konfiguration.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Den krypterede forbrugsrapport sendes dagligt. Den benyttes til at spore anvendte platforme, lagringsstørrelser og versioner. Hvis det typen af opsamlet data ændres på et senere tidspunkt, vil du blive spurgt om tilladelse igen.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Det indtastede node ID ser ikke gyldigt ud. Det skal være en 52 tegn streng, bestående af tal og bogstaver, eventuelt med mellemrum og bindestreger.",
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Det indtastede node ID ser ikke gyldigt ud. Det skal være en 52 eller 56 tegn streng, bestående af tal og bogstaver, eventuelt med mellemrum og bindestreger.",
"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 node ID cannot be blank.": "Node-ID'et kan ikke være blankt.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Node-ID'et som skal bruges her, kan du finde i \"Rediger > Vis ID\"-dialogen på den anden node. Mellemrum og bindestreg er valgfri (ignoreres).",
"The number of old versions to keep, per file.": "Antallet af gamle versioner som gemmes, per fil.",
"The number of versions must be a number and cannot be blank.": "Antallet af versioner skal være et tal, og kan ikke være blankt.",
"The repository ID cannot be blank.": "Lagrings-ID kan ikke være blankt.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Lagrings-ID'et skal være en kort identificierende streng (64 karaktere eller mindre) bestående af bogstav-, tal-, punktum- (.), bindestreg- (-) og understregskaraktere (_).",
"The repository ID must be unique.": "Lagrings-ID'et skal være unikt.",
"The repository path cannot be blank.": "Lagringsstien kan ikke være blank.",
"The rescan interval must be at least 5 seconds.": "The rescan interval must be at least 5 seconds.",
"Unknown": "Ukendt",
"Up to Date": "Fuldt opdateret",
"Upgrade To {%version%}": "Opgradér til {{version}}",
"Upgrading": "Opgradere",
"Upload Rate": "Uploadhastighed",
"Usage": "Forbrug",
"Use Compression": "Anvend komprimering",
"Use HTTPS for GUI": "Anvend HTTPS til GUI adgang",
"Version": "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 node, keep in mind that this node must be added on the other side too.": "Når du tilføjer en ny node skal du huske, at den også skal tilføjes på den anden side.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Når du tilføjer en ny node skal du huske, at lagrings-ID'et bliver brugt til at knytte noder sammen. De er følsomme for store og små bogstaver og skal matche på alle noder.",
"Yes": "Ja",
"You must keep at least one version.": "Du skal beholde mindst én version.",
"full documentation": "full documentation",
"items": "poster"
}

View File

@@ -1,28 +1,30 @@
{
"API Key": "API-Key",
"About": "Über Syncthing",
"Add Node": "Knoten hinzufügen",
"Add Repository": "Verzeichnis hinzufügen",
"Add Device": "Gerät hinzufügen",
"Add Folder": "Verzeichnis hinzufügen",
"Address": "Adresse",
"Addresses": "Adressen",
"Allow Anonymous Usage Reporting?": "Übertragung von anonymen Nutzungsstatistiken erlauben?",
"Announce Server": "Ankündigungs-Server",
"Anonymous Usage Reporting": "Anonymer Nutzungsbericht",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Any devices configured on an introducer device will be added to this device as well.": "Alle Geräte, die beim Verteiler eingetragen sind, werden auch bei diesem Gerät eingetragen",
"Bugs": "Fehler",
"CPU Utilization": "Prozessorauslastung",
"Close": "Schließen",
"Comment, when used at the start of a line": "Kommentar, wenn am Anfang der Zeile benutzt.",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Compression is recommended in most setups.": "Datenkomprimierung ist für die meisten Anwendungen empfohlen",
"Connection Error": "Verbindungsfehler",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg und folgende Unterstützer:",
"Delete": "Löschen",
"Device ID": "Geräte ID",
"Device Identification": "Gerät Identifikation",
"Device Name": "Geräte-Name",
"Disconnected": "Verbindung getrennt",
"Documentation": "Dokumentation",
"Download Rate": "Downloadgeschwindigkeit",
"Edit": "Einstellungen bearbeiten",
"Edit Node": "Knoten bearbeiten",
"Edit Repository": "Verzeichnis ändern",
"Edit Device": "Gerät bearbeiten",
"Edit Folder": "Verzeichnis Bearbeiten",
"Editing": "Bearbeitung",
"Enable UPnP": "UPnP aktivieren",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Trage durch ein Komma getrennte \"IP:Port\" Adressen oder \"dynamic\" ein um automatische Adresserkennung durchzuführen.",
@@ -31,38 +33,33 @@
"File Versioning": "Dateiversionierung",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Dateizugriffsrechte beim Suchen nach Veränderungen ignorieren. Bei FAT-Dateisystemen verwenden.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Dateien werden, bevor syncthing sie löscht oder ersetzt, als datierte Versionen in einen Ordner names .stversions verschoben.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Dateien sind vor Veränderung durch andere Knoten geschützt, auf diesem Knoten durchgeführte Veränderungen werden aber auf den Rest des Netzwerks übertragen.",
"Folder": "Ordner",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Dateien sind vor Veränderung durch andere Geräte geschützt, auf diesem Gerät durchgeführte Veränderungen werden aber auf den Rest des Verbunds übertragen.",
"Folder ID": "Verzeichnis ID",
"Folder Master": "Keine Veränderungen zulassen",
"Folder Path": "Verzeichnis Pfad",
"GUI Authentication Password": "Passwort für Zugang zur Benutzeroberfläche",
"GUI Authentication User": "Nutzername für Zugang zur Benutzeroberfläche.",
"GUI Authentication User": "Nutzername für Zugang zur Benutzeroberfläche",
"GUI Listen Addresses": "Adresse(n) für die Benutzeroberfläche",
"Generate": "Generieren",
"Global Discovery": "Globale Auffindung",
"Global Discovery Server": "Globaler Auffindungsserver",
"Global Repository": "Globales Verzeichnis",
"Global State": "Globaler Status",
"Idle": "Untätig",
"Ignore Patterns": "Ignoriermuster",
"Ignore Permissions": "Berechtigungen ignorieren",
"Incoming Rate Limit (KiB/s)": "Eingehendes Datenratelimit (KiB/s)",
"Introducer": "Introducer",
"Introducer": "Verteilergerät",
"Inversion of the given condition (i.e. do not exclude)": "Umkehrung der angegebenen Bedingung (z.B. schließe nicht aus)",
"Keep Versions": "Versionen erhalten",
"Last seen": "Zuletzt online",
"Latest Release": "Letzte Veröffentlichung",
"Local Discovery": "Lokale Auffindung",
"Local Discovery Port": "Lokaler Aufindungsport",
"Local Repository": "Lokales Verzeichnis",
"Master Repo": "Originalverzeichnis",
"Max File Change Rate (KiB/s)": "Maximale Datenänderungsrate (KiB/s)",
"Max Outstanding Requests": "Max. ausstehende Anfragen",
"Local State": "Lokaler Status",
"Maximum Age": "Höchstalter",
"Multi level wildcard (matches multiple directory levels)": "Verschachteltes Maskenzeichen (wird für verschachtelte Verzeichnisse verwendet)",
"Never": "Nie",
"No": "Nein",
"No File Versioning": "Keine Dateiversionierung",
"Node ID": "Knoten-ID",
"Node Identification": "Knoten Identifikation",
"Node Name": "Knoten-Name",
"Notice": "Benachrichtigung",
"OK": "Ok",
"Offline": "Offline",
@@ -70,34 +67,28 @@
"Out Of Sync": "Nicht synchronisiert",
"Outgoing Rate Limit (KiB/s)": "Ausgehendes Datenratelimit (KiB/s)",
"Override Changes": "Änderungen überschreiben",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Pfad zum Verzeichnis auf dem lokalen Rechner. Wird erzeugt, wenn es nicht existiert. Das Tilden-Zeichen (~) kann als Abkürzung benutzt werden für",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Pfad in dem die Versionen gespeichert werden sollen (ohne Angabe wird der Ordner .stversions im Verzeichnis verwendet).",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Pfad zum Verzeichnis auf dem lokalen Rechner. Wird erzeugt, wenn es nicht existiert. Das Tilden-Zeichen (~) kann als Abkürzung benutzt werden für",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Pfad in dem die Versionen gespeichert werden sollen (ohne Angabe wird der Ordner .stversions im Verzeichnis verwendet).",
"Please wait": "Bitte warten",
"Preview": "Vorschau",
"Preview Usage Report": "Vorschau des Nutzungsberichts",
"Quick guide to supported patterns": "Schnellanleitung zu den unterstützten Suchstrukturen",
"RAM Utilization": "Verwendeter Arbeitsspeicher",
"Reconnect Interval (s)": "Wiederverbindungsintervall (s)",
"Repository ID": "Verzeichnis-ID",
"Repository Master": "Originalverzeichnis",
"Repository Path": "Pfad zum Verzeichnis",
"Rescan": "Überprüfen",
"Rescan Interval": "Suchintervall",
"Rescan Interval (s)": "Suchintervall (s)",
"Restart": "Neustart",
"Restart Needed": "Neustart notwendig",
"Restarting": "Wird neu gestartet",
"Save": "Speichern",
"Scanning": "Sucht",
"Select the nodes to share this repository with.": "Wähle die Knoten aus, mit denen du dieses Verzeichnis teilen willst.",
"Select the devices to share this folder with.": "Wähle die Geträte aus, mit denen du dieses Verzeichnis teilen willst.",
"Settings": "Einstellungen",
"Share With Nodes": "Teile mit diesen Knoten",
"Share With Devices": "Teile mit diesen Geräten",
"Shared With": "Geteilt mit",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Kurze ID für das Verzeichnis. Muss auf allen Verbunds-Knoten gleich sein.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Kurze ID für das Verzeichnis. Muss auf allen Verbunds-Geräten gleich sein.",
"Show ID": "ID anzeigen",
"Shown instead of Node ID in the cluster status.": "Wird anstatt der Knoten-ID im Verbunds-Status angezeigt.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Wird anstatt der Knoten-ID im Verbunds-Status angezeigt. Wird als optionaler Standardname an andere Knoten bekannt gegeben.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Wird anstatt der Knoten-ID im Verbunds-Status angezeigt. Wird auf den Namen aktualisiert, den der Knoten angibt.",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wird anstatt der Geräte-ID im Verbunds-Status angezeigt. Wird als optionaler Standardname an andere Geräte bekannt gegeben.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wird anstatt der Geräte-ID im Verbunds-Status angezeigt. Wird auf den Namen aktualisiert, den das Gerät angibt.",
"Shutdown": "Herunterfahren",
"Simple File Versioning": "Einfache Dateiversionierung",
"Single level wildcard (matches within a directory only)": "Einzelnes Maskenzeichen (wird für ein einzelnes Verzeichnis verwendet)",
@@ -116,35 +107,32 @@
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing scheint nicht erreichbar zu sein oder es gibt ein Problem mit Ihrer Internetverbindung. Versuche erneut...",
"The aggregated statistics are publicly available at {%url%}.": "Die gesammelten Statistiken sind öffentlich verfügbar unter {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Die Konfiguration wurde gespeichert, aber nicht aktiviert. Syncthing muss neugestartet werden um die neue Konfiguration zu aktivieren.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Der verschlüsselte Benutzungsbericht wird täglich gesendet. Er wird benutzt um Statistiken über verwendete Betriebssysteme, Verzeichnis-Größen und Programm-Versionen zu erstellen. Sobald der Bericht in Zukunft weitere Daten erfasst, wird dir dieses Fenster erneut angezeigt.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Die eingegebene Knoten-ID scheint nicht gültig zu sein. Sie sollte eine 52 Stellen lange Zeichenkette aus Buchstaben und Zahlen sein. Leerzeichen und Striche sind optional (werden ignoriert).",
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Die eingegebene Knoten-ID scheint nicht gültig zu sein. Es sollte eine 52 oder 56 stellige Zeichenkette aus Buchstaben und Nummern sein. Leerzeichen und Bindestriche sind optional.",
"The device ID cannot be blank.": "Die Geräte-ID darf nicht leer sein.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Die hier einzutragende Geräte-ID kann im \"Bearbeiten > Zeige ID\"-Dialog auf dem anderen Gerät gefunden werden. Leerzeichen und Striche sind optional (werden ignoriert).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Der verschlüsselte Benutzungsbericht wird täglich gesendet. Er wird benutzt um Statistiken über verwendete Betriebssysteme, Verzeichnis-Größen und Programm-Versionen zu erstellen. Sollte der Bericht in Zukunft weitere Daten erfassen, wird dieses Fenster erneut angezeigt.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Die eingegebene Geräte-ID scheint nicht gültig zu sein. Es sollte eine 52 oder 56 stellige Zeichenkette aus Buchstaben und Nummern sein. Leerzeichen und Bindestriche sind optional.",
"The folder ID cannot be blank.": "Die Verzeichnis-ID darf nicht leer sein.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Die Verzeichnis-ID muss eine kurze Kennung (64 Zeichen oder weniger) sein. Sie kann nur aus Buchstaben, Zahlen und den Punkt- (.), Strich- (-), und Unterstrich- (_) Zeichen bestehen.",
"The folder ID must be unique.": "Die Verzeichnis-ID muss eindeutig sein.",
"The folder path cannot be blank.": "Der Verzeichnis-Pfad kann nicht leer sein",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "Es wird in folgenden Abständen versioniert: in der ersten Stunde wird alle 30 Sekunden eine Version behalten, am ersten Tag eine jede Stunde, in den ersten 30 Tagen eine jeden Tag, danach wird bis zum Höchstalter eine Version pro Woche beibehalten.",
"The maximum age must be a number and cannot be blank.": "Das Höchstalter muss angegeben werden und eine Zahl sein.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Die längste Zeit, die alte Versionen vorgehalten werden (in Tagen, 0 bedeutet, alte Versionen für immer zu behalten).",
"The node ID cannot be blank.": "Die Knoten-ID darf nicht leer sein.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Die hier einzutragende Knoten-ID kann im \"Bearbeiten > Zeige ID\"-Dialog auf dem anderen Knoten gefunden werden. Leerzeichen und Striche sind optional (werden ignoriert).",
"The number of old versions to keep, per file.": "Anzahl der alten Versionen, die von jeder Datei gespeichert werden sollen.",
"The number of versions must be a number and cannot be blank.": "Die Anzahl von Versionen muss eine Zahl und darf nicht leer sein.",
"The repository ID cannot be blank.": "Die Verzeichnis-ID darf nicht leer sein.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Die Verzeichnis-ID muss eine kurze Kennung (64 Zeichen oder weniger) sein. Sie kann nur aus Buchstaben, Zahlen und den Punkt- (.), Strich- (-), und Unterstrich- (_) Zeichen bestehen.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Die Verzeichnis-ID muss eine kurze Kennung (64 Zeichen oder weniger) sein. Sie kann aus Buchstaben, Zahlen und den Punkt- (.), Strich- (-), und Unterstrich- (_) Zeichen bestehen.",
"The repository ID must be unique.": "Die Verzeichnis-ID muss eindeutig sein.",
"The repository path cannot be blank.": "Der Verzeichnis-Pfad kann nicht leer sein",
"The rescan interval must be at least 5 seconds.": "Das Suchintervall muss mindestens 5 Sekunden betragen.",
"Unknown": "Unbekannt",
"Up to Date": "Aktuell",
"Upgrade To {%version%}": "Upgrade auf {{version}}",
"Upgrading": "Wird aktualisiert",
"Upload Rate": "Uploadgeschwindigkeit",
"Usage": "Benutzung",
"Use Compression": "Benutze Komprimierung",
"Use HTTPS for GUI": "Benutze HTTPS für Benutzeroberfläche",
"Version": "Version",
"Versions Path": "Versionierungspfad",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Alte Versionen werden automatisch gelöscht wenn sie älter als das angegebene Höchstalter sind oder die Höchstzahl der Dateien pro Zeitabschnitt überschritten wird.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Beachte beim Hinzufügen eines neuen Knotens, dass dieser Knoten auch auf der Gegenseite hinzugefügt werden muss.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Beim Hinzufügen eines neuen Verzeichnisses, beachte dass die Verzeichnis-ID dazu verwendet wird, Verzeichnisse zwischen Knoten zu verbinden. Die ID muss also auf allen Knoten gleich sein, Groß- und Kleinschreibung muss dabei beachtet werden.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Beachte beim Hinzufügen eines neuen Geträtes, dass dieses Gerät auch auf der Gegenseite hinzugefügt werden muss.",
"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.": "Beim Hinzufügen eines neuen Verzeichnisses, beachte dass die Verzeichnis-ID dazu verwendet wird, Verzeichnisse zwischen Geräten zu verbinden. Die ID muss also auf allen Geräten gleich sein, die Groß- und Kleinschreibung muss dabei beachtet werden.",
"Yes": "Ja",
"You must keep at least one version.": "Du musst mindestens eine Version behalten.",
"full documentation": "Komplette Dokumentation",

View File

@@ -1,152 +0,0 @@
{
"API Key": "Κλειδί API",
"About": "Σχετικά",
"Add Node": "Προσθήκη Κόμβου",
"Add Repository": "Προσθήκη Αποθετηρίου",
"Address": "Διεύθυνση",
"Addresses": "Διευθύνσεις",
"Allow Anonymous Usage Reporting?": "Να επιτρέπεται Ανώνυμη Αποστολή Αναφοράς Χρήσης?",
"Announce Server": "Διακομιστής Αναγγελίας",
"Anonymous Usage Reporting": "Ανώνυμη Αναφορά Χρήσης",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Bugs": "Bugs",
"CPU Utilization": "Χρήση CPU",
"Close": "Τέλος",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Connection Error": "Σφάλμα Σύνδεσης",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg και οι παρακάτω Συνεισφορείς:",
"Delete": "Διαγραφή",
"Disconnected": "Αποσυνδεδεμένος",
"Documentation": "Τεκμηρίωση",
"Download Rate": "Download Rate",
"Edit": "Επεξεργασία",
"Edit Node": "Επεξεργασία Κόμβου",
"Edit Repository": "Επεξεργασία Αποθετηρίου",
"Editing": "Editing",
"Enable UPnP": "Ενεργοποίηση UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Εισήγαγε διαχωρισμένα με κόμμα \"ip:port\" διευθύνσεις ή \"dynamic\", για να πραγματοποιηθεί η αυτόματη εξεύρεση διευθύνσεων.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Σφάλμα",
"File Versioning": "File Versioning",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Τα permission bits των αρχείων αγνοούνται όταν γίνεται αναζήτηση για αλλαγές. Χρήση σε FAT filesystems.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Όταν τα αρχεία αντικατασταθούν ή διαγραφούν από το syncthing, μεταφέρονται σε φάκελο .stversions με χρονική σήμανση.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Τα αρχεία προστατεύονται από αλλαγές που γίνονται σε άλλους κόμβους, αλλά όποιες αλλαγές γίνουν εδώ θα αποσταλούν στο όλο το cluster.",
"Folder": "Κατάλογος",
"GUI Authentication Password": "Κωδικός πιστοποίησης στο GUI",
"GUI Authentication User": "Χρήστης πιστοποίησης στο GUI",
"GUI Listen Addresses": "GUI Listen διευθύνσεις",
"Generate": "Δημιουργία",
"Global Discovery": "Global Discovery",
"Global Discovery Server": "Διακομιστής Ανεύρεσης Κόμβου",
"Global Repository": "Global Repository",
"Idle": "Ανενεργό",
"Ignore Patterns": "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": "Διατήρησε Εκδόσεις",
"Last seen": "Last seen",
"Latest Release": "Τελευταία Έκδοση",
"Local Discovery": "Τοπική Ανεύρεση",
"Local Discovery Port": "Port Τοπικής Ανεύρεσης",
"Local Repository": "Τοπικό Αποθετήριο",
"Master Repo": "Master Repo",
"Max File Change Rate (KiB/s)": "Max File Change Rate (KiB/s)",
"Max Outstanding Requests": "Max Outstanding Requests",
"Maximum Age": "Maximum Age",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Never",
"No": "Αριθμός",
"No File Versioning": "No File Versioning",
"Node ID": "ID Κόμβου",
"Node Identification": "Ταυτοποίηση Κόμβου",
"Node Name": "Όνομα Κόμβου",
"Notice": "Notice",
"OK": "OK",
"Offline": "Ανεργό",
"Online": "Ενεργός",
"Out Of Sync": "Μη Συγχρονισμένα",
"Outgoing Rate Limit (KiB/s)": "Outgoing Rate Limit (KiB/s)",
"Override Changes": "Override Changes",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Μονοπάτι του αποθετηρίου στον τοπικό υπολογιστή. Σε περίπτωση που δεν υπάρχει, θα δημιουργηθεί. Ο χαρακτήρας tilde (~) μπορεί να χρησιμοποιηθεί σαν συντόμευση για",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Path where versions should be stored (leave empty for the default .stversions folder in the repository).",
"Please wait": "Παρακαλώ περιμένετε",
"Preview": "Preview",
"Preview Usage Report": "Προεπισκόπηση αναφοράς χρήσης",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "Χρήση RAM",
"Reconnect Interval (s)": "Χρονικό διάστημα επανασύνδεσης (s)",
"Repository ID": "ID Αποθετηρίου",
"Repository Master": "Repository Master",
"Repository Path": "Μονοπάτι Αποθετηρίου",
"Rescan": "Rescan",
"Rescan Interval": "Rescan Interval",
"Rescan Interval (s)": "Χρονικό διάστημα Επανασάρρωσης (s)",
"Restart": "Επανεκκίνηση",
"Restart Needed": "Απαιτείται Επανεκκίνηση",
"Restarting": "Επανεκκίνηση",
"Save": "Αποθήκευση",
"Scanning": "Σάρρωση",
"Select the nodes to share this repository with.": "Επιλογή των κόμβων με τους οποίους θα διαμοιραστεί αυτό το αποθετήριο.",
"Settings": "Ρυθμίσεις",
"Share With Nodes": "Διαμοιρασμός με Κόμβους",
"Shared With": "Διαμοιρασμός με",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Σύντομη περιγραφή του αποθετηρίου. Θα πρέπει να είναι το ίδιο σε όλους τους κόμβους του cluster.",
"Show ID": "Εμφάνιση ID",
"Shown instead of Node ID in the cluster status.": "Εμφάνιση στη θέση του ID Αποθετηρίου, στην κατάσταση του cluster.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.",
"Shutdown": "Απενεργοποίηση",
"Simple File Versioning": "Simple File Versioning",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Source Code": "Πηγαίος Κώδικας",
"Staggered File Versioning": "Staggered File Versioning",
"Start Browser": "Έναρξη Φυλλομετρητή",
"Stopped": "Απενεργοποιημένο",
"Support / Forum": "Υποστήριξη / Forum",
"Sync Protocol Listen Addresses": "Sync Protocol Listen Addresses",
"Synchronization": "Συγχρονισμός",
"Syncing": "Συγχρονισμός",
"Syncthing has been shut down.": "Το Syncthing έχει απενεργοποιηθεί.",
"Syncthing includes the following software or portions thereof:": "Το Syncthing συμπεριλαμβάνει τα παρακάτω λογισμικά ή μέρη αυτών:",
"Syncthing is restarting.": "Το Syncthing επανεκκινεί.",
"Syncthing is upgrading.": "Το Syncthing αναβαθμίζεται.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Το Syncthing φαίνεται πως είναι απενεργοποιημένο ή υπάρχει πρόβλημα στη σύνδεσή σας στο Internet. Προσπάθεια ξανά…",
"The aggregated statistics are publicly available at {%url%}.": "Τα στατιστικά που έχουν συλλεγεί είναι διαθέσιμα στο κοινό, στο {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Οι ρυθμίσεις έχουν αποθηκευτεί αλλά δεν έχουν ενεργοποιηθεί. Πρέπει να επανεκκινήσετε το Syncthing για να ισχύσουν οι νέες ρυθμίσεις.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Η κρυπτογραφημένη αναφοράς χρήσης στέλνεται καθημερινά. Χρησιμοποιείται ανίχνευση πληροφοριών πλατφόρμας, μεγέθους αποθετηρίων και εκδόσεων της εφαρμογής. Αν τα δεδομένα που αποστέλονται αλλάξουν, θα πληροφορηθείτε ξανά με αυτό το διάλογο.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Το ID Κόμβου που έχει εισαχθεί δεν είναι σωστό. Θα πρέπει να είναι αλφαριθμητικό 52 χαρακτήρων που να αποτελείται από γράμματα και αριθμούς, όπου τα κενά και οι παύλες είναι προαιρετικά.",
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Το ID Κόμβου δεν είναι έγκυρο. Θα πρέπει να είναι αλφαριθμιτικό με 52 ή 56 χαρακτήρες και να αποτελείται από γράμματα και αριθμούς, που προαιρετικά χωρίζονται με κενά και παύλες.",
"The 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 node ID cannot be blank.": "Το ID Κόμβου δε μπορεί να είναι κενό.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Το ID Κόμβου μπορείτε να βρείτε στο μενού \"Επεξεργασία > Εμφάνιση ID\" του άλλου κόμβου. Κενά και παύλες είναι προαιρετικά (αγνοούνται).",
"The number of old versions to keep, per file.": "The number of old versions to keep, per file.",
"The number of versions must be a number and cannot be blank.": "Ο αριθμός εκδόσεων πρέπει να είναι αριθμός και σίγουρα όχι κενό.",
"The repository ID cannot be blank.": "Το ID Αποθετηρίου δε μπορεί να είναι κενό.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be unique.": "Το ID Αποθετηρίου πρέπει να είναι μοναδικό.",
"The repository path cannot be blank.": "Το μονοπάτι του αποθετηρίου δε μπορεί να είναι κενό.",
"The rescan interval must be at least 5 seconds.": "The rescan interval must be at least 5 seconds.",
"Unknown": "Άγνωστο",
"Up to Date": "Ενημερωμένος",
"Upgrade To {%version%}": "Αναβάθμιση στην έκδοση {{version}}",
"Upgrading": "Αναβάθμιση",
"Upload Rate": "Upload Rate",
"Usage": "Usage",
"Use Compression": "Χρήση συμπίεσης",
"Use HTTPS for GUI": "Χρήση HTTPS για το 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 node, keep in mind that this node must be added on the other side too.": "Προσθέτοντας έναν καινούργιο κόμβο, θυμηθείται πως θα πρέπει να προσθέσετε και τον παρόν κόμβο στην άλλη πλευρά.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Κατά την πρόσθεση νέου αποθετηρίου, να γνωρίζεται πως το ID Αποθετηρίου χρησιμοποιείται για να συνδέει Αποθετήρια μεταξύ κόμβων. Τα ID είναι case sensitive και θα πρέπει να είναι ταυτόσημα μεταξύ όλων των κόμβων.",
"Yes": "Ναι",
"You must keep at least one version.": "You must keep at least one version.",
"full documentation": "full documentation",
"items": "items"
}

View File

@@ -1,14 +1,13 @@
{
"API Key": "API Key",
"About": "About",
"Add Node": "Add Node",
"Add Repository": "Add Repository",
"Add Device": "Add Device",
"Add Folder": "Add Folder",
"Address": "Address",
"Addresses": "Addresses",
"Allow Anonymous Usage Reporting?": "Allow Anonymous Usage Reporting?",
"Announce Server": "Announce Server",
"Anonymous Usage Reporting": "Anonymous Usage Reporting",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.",
"Bugs": "Bugs",
"CPU Utilization": "CPU Utilization",
"Close": "Close",
@@ -17,12 +16,15 @@
"Connection Error": "Connection Error",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg and the following Contributors:",
"Delete": "Delete",
"Device ID": "Device ID",
"Device Identification": "Device Identification",
"Device Name": "Device Name",
"Disconnected": "Disconnected",
"Documentation": "Documentation",
"Download Rate": "Download Rate",
"Edit": "Edit",
"Edit Node": "Edit Node",
"Edit Repository": "Edit Repository",
"Edit Device": "Edit Device",
"Edit Folder": "Edit Folder",
"Editing": "Editing",
"Enable UPnP": "Enable UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.",
@@ -31,15 +33,17 @@
"File Versioning": "File Versioning",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "File permission bits are ignored when looking for changes. Use on FAT filesystems.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.",
"Folder": "Folder",
"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": "Folder ID",
"Folder Master": "Folder Master",
"Folder Path": "Folder Path",
"GUI Authentication Password": "GUI Authentication Password",
"GUI Authentication User": "GUI Authentication User",
"GUI Listen Addresses": "GUI Listen Addresses",
"Generate": "Generate",
"Global Discovery": "Global Discovery",
"Global Discovery Server": "Global Discovery Server",
"Global Repository": "Global Repository",
"Global State": "Global State",
"Idle": "Idle",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Ignore Permissions",
@@ -50,19 +54,12 @@
"Last seen": "Last seen",
"Latest Release": "Latest Release",
"Local Discovery": "Local Discovery",
"Local Discovery Port": "Local Discovery Port",
"Local Repository": "Local Repository",
"Master Repo": "Master Repo",
"Max File Change Rate (KiB/s)": "Max File Change Rate (KiB/s)",
"Max Outstanding Requests": "Max Outstanding Requests",
"Local State": "Local State",
"Maximum Age": "Maximum Age",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Never",
"No": "No",
"No File Versioning": "No File Versioning",
"Node ID": "Node ID",
"Node Identification": "Node Identification",
"Node Name": "Node Name",
"Notice": "Notice",
"OK": "OK",
"Offline": "Offline",
@@ -70,34 +67,28 @@
"Out Of Sync": "Out Of Sync",
"Outgoing Rate Limit (KiB/s)": "Outgoing Rate Limit (KiB/s)",
"Override Changes": "Override Changes",
"Path to the repository 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 repository 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 folder in the repository).": "Path where versions should be stored (leave empty for the default .stversions folder in the repository).",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Path where versions should be stored (leave empty for the default .stversions folder in the folder).",
"Please wait": "Please wait",
"Preview": "Preview",
"Preview Usage Report": "Preview Usage Report",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "RAM Utilization",
"Reconnect Interval (s)": "Reconnect Interval (s)",
"Repository ID": "Repository ID",
"Repository Master": "Repository Master",
"Repository Path": "Repository Path",
"Rescan": "Rescan",
"Rescan Interval": "Rescan Interval",
"Rescan Interval (s)": "Rescan Interval (s)",
"Restart": "Restart",
"Restart Needed": "Restart Needed",
"Restarting": "Restarting",
"Save": "Save",
"Scanning": "Scanning",
"Select the nodes to share this repository with.": "Select the nodes to share this repository with.",
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
"Settings": "Settings",
"Share With Nodes": "Share With Nodes",
"Share With Devices": "Share With Devices",
"Shared With": "Shared With",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Short identifier for the repository. Must be the same on all cluster nodes.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Short identifier for the folder. Must be the same on all cluster devices.",
"Show ID": "Show ID",
"Shown instead of Node ID in the cluster status.": "Shown instead of Node ID in the cluster status.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.",
"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",
"Simple File Versioning": "Simple File Versioning",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
@@ -116,35 +107,32 @@
"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 aggregated statistics are publicly available at {%url%}.": "The aggregated statistics are publicly available at {{url}}.",
"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 encrypted usage report is sent daily. It is used to track common platforms, repo 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, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.",
"The entered node 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 node 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 device ID cannot be blank.": "The device ID cannot be blank.",
"The device ID to enter here can be found in the \"Edit \u003e Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "The device ID to enter here can be found in the \"Edit \u003e Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.",
"The folder ID cannot be blank.": "The folder ID cannot be blank.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"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 node ID cannot be blank.": "The node ID cannot be blank.",
"The node ID to enter here can be found in the \"Edit \u003e Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "The node ID to enter here can be found in the \"Edit \u003e Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).",
"The number of old versions to keep, per file.": "The number of old versions to keep, per file.",
"The number of versions must be a number and cannot be blank.": "The number of versions must be a number and cannot be blank.",
"The repository ID cannot be blank.": "The repository ID cannot be blank.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be unique.": "The repository ID must be unique.",
"The repository path cannot be blank.": "The repository path cannot be blank.",
"The rescan interval must be at least 5 seconds.": "The rescan interval must be at least 5 seconds.",
"Unknown": "Unknown",
"Up to Date": "Up to Date",
"Upgrade To {%version%}": "Upgrade To {{version}}",
"Upgrading": "Upgrading",
"Upload Rate": "Upload Rate",
"Usage": "Usage",
"Use Compression": "Use Compression",
"Use HTTPS for GUI": "Use HTTPS for GUI",
"Version": "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 node, keep in mind that this node must be added on the other side too.": "When adding a new node, keep in mind that this node must be added on the other side too.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "When adding a new device, keep in mind that this device must be added on the other side too.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.",
"Yes": "Yes",
"You must keep at least one version.": "You must keep at least one version.",
"full documentation": "full documentation",

View File

@@ -1,152 +0,0 @@
{
"API Key": "Clave API",
"About": "Acerca de",
"Add Node": "Añadir nodo",
"Add Repository": "Añadir repositorio",
"Address": "Dirección",
"Addresses": "Direcciones",
"Allow Anonymous Usage Reporting?": "Permitir reporte anónimo de uso?",
"Announce Server": "Anunciar servidor",
"Anonymous Usage Reporting": "Reporte anónimo de uso",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Bugs": "Errores",
"CPU Utilization": "Uso de la CPU",
"Close": "Cerrar",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Connection Error": "Error de conexión",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Derechos de autor © 2014 Jakob Borg y los siguientes colaboradores:",
"Delete": "Suprimir",
"Disconnected": "Desconectado",
"Documentation": "Documentación",
"Download Rate": "Tasa de descarga",
"Edit": "Editar",
"Edit Node": "Editar nodo",
"Edit Repository": "Editar repositorio",
"Editing": "Editing",
"Enable UPnP": "Permitir UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Ingrese las direcciones \"ip:port\" separadas por coma o \"dynamic\" para descubrir automáticamente las direcciones.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Error",
"File Versioning": "Control de versiones",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Los permisos de archivo son ignorados al buscar cambios. Usar en sistemas de archivos FAT.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Los archivos son movidos al directorio .stversions y renombrados a versiones marcadas por fecha cuando son reemplazados o eliminados por Syncthing,",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Los archivos están protegidos de cambios en otros nodos, pero los cambios realizados en este nodo serán enviados al resto de los nodos.",
"Folder": "Carpeta",
"GUI Authentication Password": "Contraseña de autenticación de la GUI",
"GUI Authentication User": "Usuario de la GUI",
"GUI Listen Addresses": "Direcciones de escucha para la GUI.",
"Generate": "Generar",
"Global Discovery": "Búsqueda en internet",
"Global Discovery Server": "Servidor global de identificación",
"Global Repository": "Repositorio global",
"Idle": "Inactivo",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Ignorar permisos",
"Incoming Rate Limit (KiB/s)": "Límite de velocidad de entrada (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": "Conservar versiones",
"Last seen": "Visto por ultima vez",
"Latest Release": "Última versión",
"Local Discovery": "Búsqueda en red local",
"Local Discovery Port": "Puerto de búsqueda de red local",
"Local Repository": "Repositorio local.",
"Master Repo": "Repositorio maestro",
"Max File Change Rate (KiB/s)": "Tasa máxima de cambios (KiB/s)",
"Max Outstanding Requests": "Cantidad máxima de peticiones pendientes",
"Maximum Age": "Edad máxima",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Nunca",
"No": "No",
"No File Versioning": "Sin control de versiones de archivos",
"Node ID": "Nodo ID",
"Node Identification": "Identificador del nodo",
"Node Name": "Nodo nombre",
"Notice": "Aviso",
"OK": "OK",
"Offline": "Fuera de linea",
"Online": "En linea",
"Out Of Sync": "Fuera de sincronización",
"Outgoing Rate Limit (KiB/s)": "Tasa máxima de envío (KiB/s)",
"Override Changes": "Reemplazar los cambios",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Ruta del repositorio en el equipo local. La carpeta sera creada si no existe. El carácter tilde (~) puede ser utilizado como atajo de ",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Ruta donde se deben almacenar versiones (dejar vacío para la carpeta .stversions predeterminada en el repositorio).",
"Please wait": "Aguarde por favor",
"Preview": "Vista previa",
"Preview Usage Report": "Ver reporte de uso",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "Utilización de RAM",
"Reconnect Interval (s)": "Intervalo de reconexión (s)",
"Repository ID": "ID de repositorio",
"Repository Master": "Repositorio maestro",
"Repository Path": "Ruta del repositorio",
"Rescan": "Rescan",
"Rescan Interval": "Rescan Interval",
"Rescan Interval (s)": "Intervalo de reescaneo (s)",
"Restart": "Reiniciar",
"Restart Needed": "Es necesario reiniciar",
"Restarting": "Reiniciando",
"Save": "Guardar",
"Scanning": "Actualización",
"Select the nodes to share this repository with.": "Seleccione los nodos con los cuales compartir el repositorio.",
"Settings": "Configuración",
"Share With Nodes": "Compartir con los nodos",
"Shared With": "Compartido con",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Identificador corto para el repositorio. Debe ser el mismo en todos los nodos del clúster.",
"Show ID": "Mostrar ID",
"Shown instead of Node ID in the cluster status.": "Mostrar en lugar de ID de nodo en estado de cluster.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.",
"Shutdown": "Apagar",
"Simple File Versioning": "Versiones simple de archivos",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Source Code": "Código fuente",
"Staggered File Versioning": "Versiones del archivo escalonado",
"Start Browser": "Iniciar navegador",
"Stopped": "Parado",
"Support / Forum": "Soporte / Foro",
"Sync Protocol Listen Addresses": "Dirección de escucha del protocolo de sincronización",
"Synchronization": "Sincronización",
"Syncing": "Sincronización",
"Syncthing has been shut down.": "La sincronización esta apagada",
"Syncthing includes the following software or portions thereof:": "Syncthing incluye los siguientes softwares o partes de ellos:",
"Syncthing is restarting.": "Syncthing está reiniciando.",
"Syncthing is upgrading.": "Syncthing se está actualizando.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing parece estar apagado, o hay un problema con su conexión de Internet. Reintentando...",
"The aggregated statistics are publicly available at {%url%}.": "Las estadísticas acumuladas están públicamente disponibles en {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuración ha sido guardada pero no activada.\nSyncthing debe reiniciarse para activar la nueva configuración.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "El reporte de uso se envía encriptado diariamente. Se utiliza para hacer un seguimiento de plataformas comunes, tamaño de repositorios y versión de aplicaciones. Si el conjunto de datos cambia sera notificado mediante este dialogo nuevamente.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "El ID de nodo ingresado no es valido. Debe ser una cadena de al menos 52 caracteres consistente en letras y números, con espacios y guiones opcionales.",
"The entered node 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 de nodo ingresado no es valido. Debe ser una cadena de 52 o de 56 caracteres consistente en letras y números, con espacios y guiones opcionales.",
"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.": "Los siguientes intervalos se utilizan: para la primera hora una versión se mantiene cada 30 segundos, para el primer día de una versión se mantiene cada hora, durante los primeros 30 días de la versión se mantiene todos los días, hasta que la edad máxima de una versión se mantiene cada semana.",
"The maximum age must be a number and cannot be blank.": "La edad máxima debe ser un número y no puede estar en blanco.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "El tiempo máximo para mantener una versión (en días, establece en 0 para mantener versiones para siempre).",
"The node ID cannot be blank.": "El ID de nodo no puede estar vacío.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "El ID de nodo a ingresar aquí puede verse en la opción de menú \"Edición > Mostrar ID\" del otro nodo. Espacios y guiones son opcionales (ignorados).",
"The number of old versions to keep, per file.": "El numero de versiones anteriores a conservar, por archivo.",
"The number of versions must be a number and cannot be blank.": "El número de versiones debe ser un número y no puede estar vacío.",
"The repository ID cannot be blank.": "El ID de repositorio no puede estar vacio.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "El ID de repositorio debe ser una cadena corta (64 caracteres o menos) consistente solamente en letras, números, punto (.), guion (-) y guion bajo (_).",
"The repository ID must be unique.": "El ID de repositorio debe ser único.",
"The repository path cannot be blank.": "La ruta del repositorio no puede estar vacía.",
"The rescan interval must be at least 5 seconds.": "The rescan interval must be at least 5 seconds.",
"Unknown": "Desconocido",
"Up to Date": "Actualizado",
"Upgrade To {%version%}": "Actualizar a {{version}}",
"Upgrading": "Actualizando",
"Upload Rate": "Tasa de subida",
"Usage": "Utilización",
"Use Compression": "Usar compresión",
"Use HTTPS for GUI": "Usar HTTPS para la GUI",
"Version": "Versión",
"Versions Path": "Ruta de versiones",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Las versiones se eliminan automáticamente si son mayores de la edad máxima o mayor que el número de archivos permitidos en un intervalo.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Al agregar un nuevo nodo, recuerde que este nodo debe ser agregado en el otro lado también.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Al agregar un nuevo repositorio, tenga en mente que el ID de repositorio se utiliza para ligar los repositorios entre nodos. Distingue mayúsculas y minúsculas y debe ser exactamente igual en todos los nodos.",
"Yes": "Si",
"You must keep at least one version.": "Debe mantener al menos una versión",
"full documentation": "full documentation",
"items": "Articulos"
}

View File

@@ -1,68 +1,65 @@
{
"API Key": "Clé API",
"About": "À propos",
"Add Node": "Ajouter un nœud",
"Add Repository": "Ajouter un répertoire",
"Add Device": "Ajouter un périphérique",
"Add Folder": "Ajouter un répertoire",
"Address": "Adresse",
"Addresses": "Adresses",
"Allow Anonymous Usage Reporting?": "Autoriser le rapport anonyme de statistiques d'utilisation ?",
"Announce Server": "Serveur d'annonce",
"Anonymous Usage Reporting": "Rapport anonyme de statistiques d'utilisation",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Any devices configured on an introducer device will be added to this device as well.": "Tout appareil ajouté depuis un appareil initiateur sera aussi ajouté sur cet appareil.",
"Bugs": "Bugs",
"CPU Utilization": "Utilisation du CPU",
"Close": "Fermer",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Comment, when used at the start of a line": "Commentaire, lorsque utilisé en début de ligne",
"Compression is recommended in most setups.": "La compression est recommandée pour la plupart des configurations.",
"Connection Error": "Erreur de connexion",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg et les contributeurs suivants :",
"Delete": "Supprimer",
"Device ID": "ID de l'appareil",
"Device Identification": "Identification de l'appareil",
"Device Name": "Nom de l'appareil",
"Disconnected": "Déconnecté",
"Documentation": "Documentation",
"Download Rate": "Débit de réception",
"Edit": "Éditer",
"Edit Node": "Éditer le nœud",
"Edit Repository": "Éditer le répertoire",
"Editing": "Editing",
"Edit Device": "Éditer l'appareil",
"Edit Folder": "Éditer le répertoire",
"Editing": "Édition",
"Enable UPnP": "Activer l'UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Entrer les adresses \"ip:port\" séparées par une virgule ou \"dynamic\" afin d'activer la recherche automatique de l'adresse.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Enter ignore patterns, one per line.": "Entrer les modèles à ignorer, un par ligne.",
"Error": "Erreur",
"File Versioning": "Versions de fichier",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Les permissions de fichier sont ignorées lors de la recherche de changements. À utiliser sur les systèmes de fichiers de type FAT.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Les fichiers sont datés et déplacés dans le dossier .stversions lors de leur remplacement ou suppression par syncthing.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Les fichiers sont protégés des changements réalisés sur les autres nœuds, mais les changements réalisés sur ce nœud seront transférés au reste du cluster.",
"Folder": "Dossier",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Les fichiers sont protégés des changements réalisés sur les autres appareils, mais les changements réalisés sur cet appareil seront transférés au reste du groupe.",
"Folder ID": "ID du répertoire",
"Folder Master": "Répertoire maître",
"Folder Path": "Chemin du répertoire",
"GUI Authentication Password": "Mot de passe d'authentification GUI",
"GUI Authentication User": "Utilistateur autorisé GUI",
"GUI Listen Addresses": "Adresse du GUI",
"Generate": "Générer",
"Global Discovery": "Recherche globale",
"Global Discovery Server": "Serveur global de recherche",
"Global Repository": "Répertoire global",
"Global State": "État global",
"Idle": "Au repos",
"Ignore Patterns": "Ignore Patterns",
"Ignore Patterns": "Modèles à éviter",
"Ignore Permissions": "Ignorer les permissions",
"Incoming Rate Limit (KiB/s)": "Limite du débit entrant (KiB/s)",
"Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Introducer": "Initiateur",
"Inversion of the given condition (i.e. do not exclude)": "Inverser la condition donnée (i.e. ne pas exclure)",
"Keep Versions": "Conserver les versions",
"Last seen": "Dernière apparition",
"Latest Release": "Dernière version",
"Local Discovery": "Recherche locale",
"Local Discovery Port": "Port de recherche locale",
"Local Repository": "Dossier local",
"Master Repo": "Dossier maître",
"Max File Change Rate (KiB/s)": "Débit maximum de changement de fichier (KiB/s)",
"Max Outstanding Requests": "Nombre maximum de demandes concurrentes de blocs de fichier",
"Local State": "État local",
"Maximum Age": "Ancienneté maximum",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Multi level wildcard (matches multiple directory levels)": "Astérisque à plusieurs niveaux (correspond aux répertoires et sous-répertoires)",
"Never": "Jamais",
"No": "Non",
"No File Versioning": "Pas de version de fichier",
"Node ID": "ID du nœud",
"Node Identification": "Identification du nœud",
"Node Name": "Nom du nœud",
"Notice": "Notification",
"OK": "OK",
"Offline": "Offline",
@@ -70,37 +67,31 @@
"Out Of Sync": "Non synchronisé",
"Outgoing Rate Limit (KiB/s)": "Limite du débit sortant (KiB/s)",
"Override Changes": "Écraser les changements",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Chemin du répertoire sur l'ordinateur local. Il sera créé si il n'existe pas. Le caractère tilde (~) peut être utilisé comme raccourci vers",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Chemin où les versions doivent être conservées (laisser vide pour le chemin par défaut de .stversions dans le répertoire)",
"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": "Chemin du répertoire sur l'ordinateur local. Il sera créé si il n'existe pas. Le caractère tilde (~) peut être utilisé comme raccourci vers",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Chemin où les versions doivent être conservées (laisser vide pour le chemin par défaut de .stversions dans le répertoire)",
"Please wait": "Merci de patienter",
"Preview": "Aperçu",
"Preview Usage Report": "Aperçu du rapport de statistiques d'utilisation",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"Quick guide to supported patterns": "Guide rapide des modèles supportés",
"RAM Utilization": "Utilisation de la RAM",
"Reconnect Interval (s)": "Intervalle de reconnexion (s)",
"Repository ID": "ID du répertoire",
"Repository Master": "Répertoire maître",
"Repository Path": "Chemin du répertoire",
"Rescan": "Rescanner",
"Rescan Interval": "Intervalle de scan",
"Rescan Interval (s)": "Intervalle de rescan (s)",
"Restart": "Redémarrer",
"Restart Needed": "Redémarrage nécessaire",
"Restarting": "Redémarrage",
"Save": "Sauver",
"Scanning": "En cours de scan",
"Select the nodes to share this repository with.": "Sélectionner les nœuds qui partagent ce répertoire.",
"Select the devices to share this folder with.": "Sélectionner les appareils avec qui partager ce répertoire.",
"Settings": "Configuration",
"Share With Nodes": "Partager avec les nœuds",
"Share With Devices": "Partager avec les appareils",
"Shared With": "Partagé avec",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Identifiant court pour le répertoire. Il doit être le même sur l'ensemble des nœuds du cluster.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Court identifiant du répertoire. Il doit être le même sur l'ensemble des appareils du groupe.",
"Show ID": "Montrer l'ID",
"Shown instead of Node ID in the cluster status.": "Affiché à la place de l'ID du nœud au sein du cluster.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Affiché à la place de l'ID du nœud dans le statut du cluster. Sera annoncé aux autres nœuds comme un nom par défaut optionnel.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Affiché à la place de l'ID du nœud dans le statut du cluster. Sera mis à jour par le nom que le nœud annonce si laissé vide.",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Affiché à la place de l'ID de l'appareil dans le statut du groupe. Sera proposé aux autres nœuds comme un nom par défaut optionnel.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Affiché à la place de l'ID de l'appareil dans le statut du groupe. Si laissé vide, il sera changé par le nom proposé par l'appareil.",
"Shutdown": "Éteindre",
"Simple File Versioning": "Versions simples de fichier",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Single level wildcard (matches within a directory only)": "Astérisque à un seul niveau (correspond uniquement à lintérieur du répertoire)",
"Source Code": "Code source",
"Staggered File Versioning": "Versions échelonnées de fichier",
"Start Browser": "Démarrer le navigateur web",
@@ -116,37 +107,34 @@
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing semble être éteint, ou il y a un problème avec votre connexion Internet. Nouvelle tentative ...",
"The aggregated statistics are publicly available at {%url%}.": "Les statistiques agrégées sont disponibles publiquement à l'adresse {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuration a été sauvée mais pas activée. Syncthing doit redémarrer afin d'activer la nouvelle configuration.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Le rapport d'utilisation chiffré est envoyé quotidiennement. Il sert à répertorier les plateformes utilisées, la taille des répertoires et les versions de l'application. Si le jeu de données rapportées devait être changé, il vous sera demandé de le valider de nouveau via ce dialogue.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "L'ID du nœud ne semble pas être valide. Il devrait ressembler à une chaine de 52 caractères comprenant lettres et chiffres, avec des espaces et des traits d'union optionnels.",
"The entered node 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 du nœud inséré ne semble pas être valide. Il devrait ressembler à une chaîne de 52 ou 56 comprenant lettres et chiffres, avec des espaces et des traits d'union optionnels.",
"The device ID cannot be blank.": "L'ID de l'appareil ne peut être vide.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "L'ID de l'appareil à renseigner peut être trouvé dans le menu \"Éditer > Montrer l'ID\" des autres nœuds. Les espaces et les tirets sont optionnels (ils seront ignorés).",
"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.": "Le rapport d'utilisation chiffré est envoyé quotidiennement. Il sert à répertorier les plateformes utilisées, la taille des répertoires et les versions de l'application. Si les données rapportées sont modifiées cette boite de dialogue vous redemandera votre confirmation.",
"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 de l'appareil inséré ne semble pas être valide. Il devrait ressembler à une chaîne de 52 ou 56 caractères comprenant des lettres, des chiffres et potentiellement des espaces et des traits d'union.",
"The folder ID cannot be blank.": "L'ID du répertoire ne peut être vide.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "L'ID du répertoire doit être un identifiant court (64 caractères ou moins) comprenant uniquement des lettres, nombres, points (.), traits d'union (-) et tirets bas (_).",
"The folder ID must be unique.": "L'ID du répertoire doit être unique.",
"The folder path cannot be blank.": "Le chemin du répertoire ne peut pas être vide.",
"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.": "Les intervalles suivant sont utilisés: la première heure une version est conservée chaque 30 secondes, le premier jour une version est conservée chaque heure, les premiers 30 jours une version est conservée chaque jour, jusqu'à la limite d'âge maximum une version est conservée chaque semaine.",
"The maximum age must be a number and cannot be blank.": "L'ancienneté maximum doit être un nombre et ne peut être vide.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Le temps maximum de conservation d'une version (en jours, mettre à 0 pour conserver les versions pour toujours)",
"The node ID cannot be blank.": "L'ID du nœud ne peut être vide.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "L'ID du nœud à insérer peut être trouvé à travers le menu \"Éditer > Montrer l'ID\" des autres nœuds. Les espaces et les traits d'union sont optionnels (ils seront ignorés).",
"The number of old versions to keep, per file.": "Le nombre d'anciennes versions à garder, par fichier.",
"The number of versions must be a number and cannot be blank.": "Le nombre de version doit être un nombre et ne peut pas être vide.",
"The repository ID cannot be blank.": "L'ID du répertoire ne peut être vide.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "L'ID du répertoire doit être un identifiant court (64 caractères ou moins) comprenant des lettres, nombres, points (.), trait d'union (-) et tiret bas (_).",
"The repository ID must be unique.": "L'ID du répertoire doit être unique.",
"The repository path cannot be blank.": "Le chemin du répertoire ne peut pas être vide.",
"The rescan interval must be at least 5 seconds.": "L'intervalle de scan doit être d'au minimum 5 secondes.",
"Unknown": "Inconnu",
"Up to Date": "Synchronisation à jour",
"Upgrade To {%version%}": "Mettre à jour vers {{version}}",
"Upgrading": "Mise à jour de Syncthing",
"Upload Rate": "Débit d'envoi",
"Usage": "Utilisation",
"Use Compression": "Utiliser la compression",
"Use HTTPS for GUI": "Utiliser l'HTTPS pour le GUI",
"Version": "Version",
"Versions Path": "Emplacement des 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 sont supprimées automatiquement si celles-ci sont plus anciennes que l'ancienneté maximum ou que leur nombre est supérieur au nombre autorisé dans une intervale.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Lorsqu'un nœud est ajouté, gardez à l'esprit que ce nœud doit aussi être ajouté de l'autre coté.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Lorsqu'un nouveau répertoire est ajouté, gardez à l'esprit que l'ID du répertoire est utilisé pour lier les répertoires à travers les nœuds. Ils sont sensibles à la casse et doivent être identiques à travers tous les nœuds.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Lorsqu'un appareil est ajouté, gardez à l'esprit que cet appareil doit aussi être ajouté de l'autre coté.",
"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.": "Lorsqu'un nouveau répertoire est ajouté, gardez à l'esprit que son ID est utilisé pour lier les répertoires à travers les appareils. Les ID sont sensibles à la casse et doivent être identiques à travers tous les nœuds.",
"Yes": "Oui",
"You must keep at least one version.": "Vous devez garder au minimum une version.",
"full documentation": "full documentation",
"full documentation": "documentation complète",
"items": "éléments"
}

View File

@@ -1,150 +1,138 @@
{
"API Key": "API kulcs",
"About": "Névjegy",
"Add Node": "Csomópont hozzáadása",
"Add Repository": "Tároló hozzáadása",
"Add Device": "Eszköz hozzáadása",
"Add Folder": "Mappa hozzáadása",
"Address": "Cím",
"Addresses": "Címek",
"Allow Anonymous Usage Reporting?": "Engedélyezed a névtelen felhasználási statisztikai adatok küldését?",
"Announce Server": "Cím hirdető szerver",
"Anonymous Usage Reporting": "Névtelen felhasználási statisztikák küldése",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Allow Anonymous Usage Reporting?": "Engedélyezed a névtelen felhasználási adatok küldését?",
"Anonymous Usage Reporting": "Névtelen felhasználási adatok küldése",
"Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.",
"Bugs": "Hibák",
"CPU Utilization": "Processzor használat",
"Close": "Bezárás",
"Comment, when used at the start of a line": "Megjegyzés, a sor elején használva",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Compression is recommended in most setups.": "A tömörítés a a legtöbb esetben ajánlott",
"Connection Error": "Kapcsolódási hiba",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg és a következő Közreműködők",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg és az alábbi Közreműködők",
"Delete": "Törlés",
"Disconnected": "Kapcsolat bontása",
"Device ID": "Eszköz azonosító",
"Device Identification": "Eszköz azonosító",
"Device Name": "Eszköz neve",
"Disconnected": "Kapcsolat bontva",
"Documentation": "Dokumentáció",
"Download Rate": "Letöltési sebesség",
"Edit": "Szerkesztés",
"Edit Node": "Csomópont szerkesztése",
"Edit Repository": "Tároló szerkesztése",
"Edit Device": "Eszköz szerkesztése",
"Edit Folder": "Mappa szerkesztése",
"Editing": "Szerkesztés",
"Enable UPnP": "UPnP engedélyezése",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Add meg kettősponttal elválasztva \"ip:port\" a címet vagy add meg a \"dynamic\" szót az a cím automatikus észleléséhez.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Add meg kettősponttal elválasztva (ip:port) a címet vagy add meg a \"dynamic\" szót az a cím automatikus észleléséhez.",
"Enter ignore patterns, one per line.": "Figyelmen kívül hagyáshoz ide írhatod a mintákat, soronként egyet",
"Error": "Hiba",
"File Versioning": "File verziózás",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "A file jogosultásgok figyelmen kívül hagyása. FAT file-rendszernél haszálatos.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "A file-ok időpecsételt verziói a .stversions mappában kerülnek áthelyezésre, amikor felülírásra vagy törlésre kerülnek a Síncthing által.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "A file-ok védve lesznek, a többi csomóponton történt változástól, de ezen a csomóponton történt változás el lesz küldve a többi csomópontra.",
"Folder": "Mappa",
"GUI Authentication Password": "GUI jelszó",
"GUI Authentication User": "GUI felhastnáló",
"GUI Listen Addresses": "GUI port",
"File Versioning": "Fájl verziózás",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "A fájl jogosultságok figyelmen kívül hagyása. FAT fájlrendszernél használatos.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "A fájlok időpecsételt verziói a .stversions mappában kerülnek áthelyezésre, amikor felülírásra vagy törlésre kerülnek a Sincthing által.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "A fájlok védve vannak a más eszközökön történt változásokkal szemben, de az ezen az eszközön történt változások érvényesek lesznek a többire.",
"Folder ID": "Mappa azonosító",
"Folder Master": "Központi mappa",
"Folder Path": "Mappa elérési útja",
"GUI Authentication Password": "Grafikus felület jelszava",
"GUI Authentication User": "Grafikus felület felhasználó neve ",
"GUI Listen Addresses": "Grafikus felület címe",
"Generate": "Generálás",
"Global Discovery": "Globális csomópont keresés",
"Global Discovery Server": "Globális csomópont kereséshez használt szerver",
"Global Repository": "Globális tároló",
"Global Discovery": "Globális felfedezés",
"Global Discovery Server": "Globális felfedező szerver",
"Global State": "Globális állapot",
"Idle": "Tétlen",
"Ignore Patterns": "Ignore Patterns",
"Ignore Patterns": "Figyelmen kívül hagyás",
"Ignore Permissions": "Jogosultságok figyelmen kívül hagyása",
"Incoming Rate Limit (KiB/s)": "Bejövő sebesség korlát (KIB/mp)",
"Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Keep Versions": "Verziók megtartása",
"Inversion of the given condition (i.e. do not exclude)": "A feltétel ellentéte (pl. ki nem hagyás)",
"Keep Versions": "Megtartott verziók",
"Last seen": "Utoljára látva",
"Latest Release": "Utolsó kiadás",
"Local Discovery": "Helyi csomópont keresés",
"Local Discovery Port": "Helyi csomópont keresés port-ja",
"Local Repository": "Helyi tároló",
"Master Repo": "Központi tároló",
"Max File Change Rate (KiB/s)": "Maximális file változás sebessége (KiB/mp)",
"Max Outstanding Requests": "Maximális kimenő kérés",
"Local Discovery": "Helyi felfedezés",
"Local State": "Helyi állapot",
"Maximum Age": "Maximális kor",
"Multi level wildcard (matches multiple directory levels)": "Több szintű joker (több könyvtár szintre érvényesül)",
"Multi level wildcard (matches multiple directory levels)": "Több szintű helyettesítő karakter (több könyvtár szintre érvényesül)",
"Never": "Soha",
"No": "Nem",
"No File Versioning": "Nincs file verziózás",
"Node ID": "Csomópont azonosító",
"Node Identification": "Csomópont azonosítás",
"Node Name": "Csomópont név",
"No File Versioning": "Nincs fájl verziózás",
"Notice": "Megjegyzés",
"OK": "Rendben",
"Offline": "Nincs kpcsolat",
"Offline": "Nincs kapcsolat",
"Online": "Kapcsolódva",
"Out Of Sync": "Nincs szinkronban",
"Outgoing Rate Limit (KiB/s)": "Kimenő sávszélesség (KiB/mp)",
"Override Changes": "Változtatások felülbírálása",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "A tároló útvonala ezen a számítógépen. Amennyiben nem létezik automatikusan létrehozzuk. A hullámvonal (~) karakter használható a rövidítésre",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Az útvonal ahol a régi verziókat tároljuk (ha üresen hagyod akkor .stversions mappa lesz a neve).",
"Please wait": "Kérem várj",
"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": "A mappa elérési útja az eszközön. Amennyiben nem létezik, a program automatikusan létrehozza. A hullámvonal (~) a következő helyettesítésre használható: ",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Elérési út ahol a verziók tárolásra kerülnek (szabadon hagyva az alapértelmezett .stversions mappa lesz használva)",
"Please wait": "Kérlek várj",
"Preview": "Előnézet",
"Preview Usage Report": "Felhasználási adatok átnézése",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"Quick guide to supported patterns": "Rövid útmutató a használható mintákról",
"RAM Utilization": "Memória használat",
"Reconnect Interval (s)": "Újracsatlakozási intervallum (mp)",
"Repository ID": "Tároló azonosító",
"Repository Master": "Központi tároló",
"Repository Path": "Tároló útvonala",
"Rescan": "Újraátvizsgálás",
"Rescan": "Átnézés",
"Rescan Interval": "Átnézési intervallum",
"Rescan Interval (s)": "Átnézési intervallum (mp)",
"Restart": "Újraindítás",
"Restart Needed": "Újraindítás szükséges",
"Restarting": "Újraindulás",
"Save": "Mentés",
"Scanning": "Átnézés",
"Select the nodes to share this repository with.": "Válaszd ki a csomópontokat amikkel a tárolót megosszuk",
"Select the devices to share this folder with.": "Válaszd ki az eszközöket amelyekkel meg szeretnéd osztani a mappát",
"Settings": "Beállítások",
"Share With Nodes": "Megosztás a csomópontokkal",
"Share With Devices": "Megosztás eszközökkel",
"Shared With": "Megosztva velük",
"Short identifier for the repository. Must be the same on all cluster nodes.": "A tároló rövid azonosítója. Ugyanannak kell lennie minden fürtbeli csomóponton.",
"Show ID": "Azonosító mutatáas",
"Shown instead of Node ID in the cluster status.": "A csomópont azonosító helyett jelenik meg a fürt állapotánál.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "A csomópont azonosító helyett jelenik meg a fürtben a státusznál. A csomópontoknak ez is hirdetve lesz, mint opcionális alapértelmezett név.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "A csomópont azonosító helyett jelenik meg a fürtben a státusznál. A csomópont neve a hirdetettre lesz llítva amennyiben az üresen van hagyva.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Rövid azonosító. Minden megosztott eszközön azonos kell legyen.",
"Show ID": "Azonosító mutatása",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Az eszköz azonosító helyett jelenik meg. A többi eszközön alapértelmezett névként használható. ",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Az eszköz azonosító helyett jelenik meg. Üresen hagyva az eszköz saját neve lesz használva ",
"Shutdown": "Leállítás",
"Simple File Versioning": "Egyszerű file verziózás",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Simple File Versioning": "Egyszerű fájl verziózás",
"Single level wildcard (matches within a directory only)": "Egyszintű helyettesítő karakter (csak egy mappára érvényes)",
"Source Code": "Forráskód",
"Staggered File Versioning": "Többszintű file verziózás",
"Staggered File Versioning": "Többszintű fájl verziózás",
"Start Browser": "Böngésző indítása",
"Stopped": "Leállítva",
"Support / Forum": "Támogatás / Fórum",
"Sync Protocol Listen Addresses": "Szinkronizációs protokoll hallgatózási címe",
"Sync Protocol Listen Addresses": "Szinkronizációs protokoll címe",
"Synchronization": "Szinkronizálás",
"Syncing": "Syncthing",
"Syncing": "Szinkronizálás",
"Syncthing has been shut down.": "Syncthing leállítva",
"Syncthing includes the following software or portions thereof:": "Syncthing a következő programokat, vagy programkomponenseket tartalmazza.",
"Syncthing includes the following software or portions thereof:": "Syncthing a következő programokat, vagy komponenseket tartalmazza.",
"Syncthing is restarting.": "Syncthing újraindul",
"Syncthing is upgrading.": "Syncthing frissül",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "A Syncthing úgy tűnik, hogy nem működik, vagy valami probléma van az hálózati kapcsolattal. Újra próbálom...",
"The aggregated statistics are publicly available at {%url%}.": "Az összevont statisztikák nyilvánosan elérhetők a {{url}} címen.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "A beállítások ok elmentésre kerültek, de nem lettek aktiválva. Indítsad újra a Syncthing-et, hogy aktíváld őket.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "A titkosított felhasználási jelentés naponta kerül elküldésre. Arra használjuk, hogy a futtató platformot, tároló méreteket illetve program verziókat kövessük nyomon. Amennyiben ez változik akkor újra meg fog jelenni ez az ablak.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "A beírt csomópont azonosító nem tűnik megfelelőnek. 52 karakter hosszúnak kell lennie és csak számokat illetve betűket tartalmazhat, amit szóközök illetve kötőjelek tagolhatnak.",
"The entered node 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.": "A beírt csomópont azonosító nem tűnik megfelelőnek. 52 vagy 56 karakteresnek kell lennie csak számot és betűt kell tartalmaznia és szóközökkel vagy kötőjelekkel lehet tagolva.",
"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.": "A következő intervallumokat használjuk: egy-egy régi verziót őrzünk meg az első órában minden 30 másodpercben, az első nap minden órában, az első 30 napban minden nap, egészen addig amíg el nem érjük a maximálisan megtartható verziók számát minden héten.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "A beállítások elmentésre kerültek, de nem lettek aktiválva. Indíts újra a Syncthing-et, hogy aktiváld őket.",
"The device ID cannot be blank.": "Az eszköz azonosító nem lehet üres.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Az eszköz azonosító az \"Azonosító mutatása\" ablakban található az eszközökön. A szóközök és kötőjelek opcionálisak (nem lesznek figyelembe véve)",
"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.": "A titkosított felhasználási adatok naponta kerülnek küldésre. Arra használjuk őket hogy kövessük a különböző platformokat, mappa méreteket és program verziókat. Amennyiben az elküldésre kerülő adat megváltozik, ez az ablak újra megjelenik.",
"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.": "A beírt eszköz azonosító nem valódi. Az azonosító 52 vagy 56 karakter hosszú, számokból és betűkből áll, opcionálisan szóközöket és kötőjeleket tartalmaz.",
"The folder ID cannot be blank.": "A mappa azonosító nem lehet üres.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "A mappa azonosító rövid (maximum 64 karakter), betűkből, számokból és a pont (.), kötőjel (-) és alulvonás (_) karakterekből állhat.",
"The folder ID must be unique.": "A mappa azonosító egyedi kell legyen",
"The folder path cannot be blank.": "Az elérési út nem lehet üres",
"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.": "A következő intervallumokat használjuk: egy régi verziót őrzünk meg az első órában minden 30 másodpercben, az első nap minden órában, az első 30 napban minden nap, egészen addig amíg el nem érjük a maximálisan megtartható verziók számát minden héten.",
"The maximum age must be a number and cannot be blank.": "A maximális kornak számnak kell lenni és nem lehet üres",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "A verziók megtartásának maximális ideje (napokban, ha 0-t adsz meg örökre megmaradnak).",
"The node ID cannot be blank.": "A csomópont azonosító nem lehet üres",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "A csomópont azonosító a túloldalon a \"Beállítások > Azonosító mutatása\" alatt található. A szóközök illetve a kötőjelek opcionálisak (kihagyhatóak). ",
"The number of old versions to keep, per file.": "Mennyi régi változatot tartsunk meg a file-okból",
"The number of versions must be a number and cannot be blank.": "A megtartott változatok száma nem lehet üres",
"The repository ID cannot be blank.": "A tároló azonosító nem lehet üres",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "A tároló azonosító egy rövid (maximálisan 64 karakteres) csak számokat, betűket, pontot (.), kötőjelet (-) illetve aláhúzást (_) tartalmazó karakterlánc.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "A tároló azonosító egy rövid (maximálisan 64 karakteres) csak számokat, betűket, pontot (.), kötőjelet (-) illetve aláhúzást (_) tartalmazó karakterlánc",
"The repository ID must be unique.": "A tároló azonosítónak egyedinek kell lennie",
"The repository path cannot be blank.": "A tároló útvonala nem lehet üres",
"The rescan interval must be at least 5 seconds.": "Az átnézési intervallumbak legalább 5 másodpercnek kell lennie.",
"The number of old versions to keep, per file.": "A megtartott régi verziók száma, fájlonként.",
"The number of versions must be a number and cannot be blank.": "A megtartott verziók száma nem lehet üres",
"The rescan interval must be at least 5 seconds.": "Az átnézési intervallumnak legalább 5 másodpercnek kell lennie.",
"Unknown": "Ismeretlen",
"Up to Date": "Friss",
"Upgrade To {%version%}": "Frissítés a {{version}} verzióra",
"Upgrading": "Frissítés",
"Upload Rate": "Feltöltési sebesség",
"Usage": "Használat",
"Use Compression": "Tömörítés használata",
"Use HTTPS for GUI": "HTTPS használata a GUI-hoz",
"Version": "Verzió",
"Versions Path": "Verziók útvonala",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "A régi verziók automatikusan törlődnek, amennyiben öregebbek mint a maximum kor, vagy már több van belőlük mint az adott intervallumban megtartható maximum.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Amikor új csomópontot adsz hozzá, tartsd észben, hogy azt a túloldalhoz is hozzá kell majd adni.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Amikor hozzáadod a tárolót, tartsad észben, hogy a Tároló azonosító az ami összeköti a csomópontokat. Kis-nagybetű érzékeny, és pontosan ugyan úgy kell azokat megadni mindegyik csomóponton.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Amikor új eszközt adsz hozzá, tartsd észben hogy, ezt az eszközt is hozzá kell adni a másik oldalon.",
"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.": "Amikor új mappát adsz hozzá, tartsd észben hogy a mappa azonosító arra való hogy összekösd a mappákat az eszközeiden. Az azonosító kisbetű-nagybetű érzékeny és pontosan egyeznie kell az eszközökön.",
"Yes": "Igen",
"You must keep at least one version.": "Legalább egy verziót meg kell tartanod",
"full documentation": "teljes dokumentáció",

View File

@@ -1,106 +1,97 @@
{
"API Key": "Chiave API",
"About": "Informazioni",
"Add Node": "Aggiungi Nodo",
"Add Repository": "Aggiungi Deposito",
"Add Device": "Aggiungi Dispositivo",
"Add Folder": "Aggiungi Cartella",
"Address": "Indirizzo",
"Addresses": "Indirizzi",
"Allow Anonymous Usage Reporting?": "Abilitare Statistiche Anonime di Utilizzo?",
"Announce Server": "Server di Presenza Globale dei Nodi",
"Anonymous Usage Reporting": "Statistiche Anonime di Utilizzo",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Any devices configured on an introducer device will be added to this device as well.": "Qualsiasi dispositivo configurato in un introduttore verrà aggiunto anche a questo dispositivo.",
"Bugs": "Bug",
"CPU Utilization": "Utilizzo CPU",
"Close": "Chiudi",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Comment, when used at the start of a line": "Per commentare, va inserito all'inizio di una riga",
"Compression is recommended in most setups.": "La compressione è raccomandata nella maggior parte delle configurazioni.",
"Connection Error": "Errore di Connessione",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg e i seguenti Collaboratori:",
"Delete": "Elimina",
"Device ID": "ID Dispositivo",
"Device Identification": "Identificazione Dispositivo",
"Device Name": "Nome Dispositivo",
"Disconnected": "Disconnesso",
"Documentation": "Documentazione",
"Download Rate": "Velocità Download",
"Edit": "Modifica",
"Edit Node": "Modifica Nodo",
"Edit Repository": "Modifica Deposito",
"Editing": "Editing",
"Edit Device": "Modifica Dispositivo",
"Edit Folder": "Modifica Cartella",
"Editing": "Modifica di",
"Enable UPnP": "Attiva UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Inserisci gli indirizzi \"ip:porta\" separati da una virgola, altrimenti inserisci \"dynamic\" per effettuare il rilevamento automatico dell'indirizzo.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Enter ignore patterns, one per line.": "Inserisci gli schemi di esclusione, uno per riga.",
"Error": "Errore",
"File Versioning": "Controllo Versione dei File",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Il software evita i bit dei permessi dei file durante il controllo delle modifiche. Utilizzato nei filesystem FAT.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "I file sostituiti o eliminati da syncthing vengono datati e spostati in una cartella .stversions .",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "I file sono protetti dalle modifiche effettuate negli altri nodi, ma le modifiche effettuate in questo nodo verranno inviate anche al resto del cluster.",
"Folder": "Cartella",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "I file sono protetti dalle modifiche effettuate negli altri dispositivi, ma le modifiche effettuate in questo dispositivo verranno inviate anche al resto del cluster.",
"Folder ID": "ID Cartella",
"Folder Master": "Cartella Principale",
"Folder Path": "Percorso Cartella",
"GUI Authentication Password": "Password di Autenticazione dell'Utente",
"GUI Authentication User": "Utente dell'Interfaccia Grafica",
"GUI Listen Addresses": "Indirizzi dell'Interfaccia Grafica",
"Generate": "Genera",
"Global Discovery": "Individuazione Globale",
"Global Discovery Server": "Server di Ricerca Globale",
"Global Repository": "Deposito Globale",
"Global State": "Stato Globale",
"Idle": "Inattivo",
"Ignore Patterns": "Ignore Patterns",
"Ignore Patterns": "Schemi Esclusione File",
"Ignore Permissions": "Ignora Permessi",
"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)",
"Incoming Rate Limit (KiB/s)": "Limite Velocità in Ingresso (KiB/s)",
"Introducer": "Introduttore",
"Inversion of the given condition (i.e. do not exclude)": "Inversione della condizione indicata (ad es. non escludere)",
"Keep Versions": "Versioni Mantenute",
"Last seen": "Last seen",
"Last seen": "Ultima connessione",
"Latest Release": "Ultima Versione",
"Local Discovery": "Individuazione Locale",
"Local Discovery Port": "Porta di Individuazione Locale",
"Local Repository": "Deposito Locale",
"Master Repo": "Deposito Principale",
"Max File Change Rate (KiB/s)": "Tasso Massimo di Cambiamento dei File (KiB/s)",
"Max Outstanding Requests": "Numero Massimo di Richieste Simultanee per i Blocchi di File",
"Local State": "Stato Locale",
"Maximum Age": "Durata Massima",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Never",
"Multi level wildcard (matches multiple directory levels)": "Metacarattere multi-livello (corrisponde alle cartelle e alle sotto-cartelle)",
"Never": "Mai",
"No": "No",
"No File Versioning": "Nessun Controllo Versione",
"Node ID": "ID Nodo",
"Node Identification": "Identificazione Nodo",
"Node Name": "Nome Nodo",
"Notice": "Avviso",
"OK": "OK",
"Offline": "Non in linea",
"Online": "In linea",
"Out Of Sync": "Non Sincronizzati",
"Outgoing Rate Limit (KiB/s)": "Limite di Velocità in Uscita (KiB/s)",
"Outgoing Rate Limit (KiB/s)": "Limite Velocità in Uscita (KiB/s)",
"Override Changes": "Ignora Modifiche",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Percorso del deposito nel computer locale. Verrà creato se non esiste già. Il carattere tilde (~) può essere utilizzato come scorciatoia per",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Percorso di salvataggio delle versioni (lasciare vuoto per utilizzare la cartella predefinita .stversions nel deposito).",
"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": "Percorso della cartella nel computer locale. Verrà creata se non esiste già. Il carattere tilde (~) può essere utilizzato come scorciatoia per",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Percorso di salvataggio delle versioni (lasciare vuoto per utilizzare la cartella predefinita .stversions in questa cartella).",
"Please wait": "Attendere prego",
"Preview": "Preview",
"Preview": "Anteprima",
"Preview Usage Report": "Anteprima Statistiche di Utilizzo",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"Quick guide to supported patterns": "Guida veloce agli schemi supportati",
"RAM Utilization": "Utilizzo RAM",
"Reconnect Interval (s)": "Intervallo di Riconnessione (s)",
"Repository ID": "ID Deposito",
"Repository Master": "Deposito Principale",
"Repository Path": "Percorso del Deposito",
"Rescan": "Riscansiona",
"Rescan Interval": "Intervallo di Scansione",
"Rescan Interval (s)": "Intervallo di Scansione dei File (s)",
"Rescan Interval": "Intervallo Scansione",
"Restart": "Riavvia",
"Restart Needed": "Riavvio Necessario",
"Restarting": "Riavvio",
"Save": "Salva",
"Scanning": "Scansione in corso",
"Select the nodes to share this repository with.": "Seleziona i nodi con i quali vuoi condividere questo deposito.",
"Select the devices to share this folder with.": "Seleziona i dispositivi con i quali condividere questa cartella.",
"Settings": "Impostazioni",
"Share With Nodes": "Condividi Con i Nodi",
"Share With Devices": "Condividi con i Dispositivi",
"Shared With": "Condiviso Con",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Breve identificatore del deposito. Deve essere lo stesso su tutti i nodi del cluster.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Breve identificatore della cartella. Deve essere lo stesso su tutti i dispositivi del cluster.",
"Show ID": "Mostra ID",
"Shown instead of Node ID in the cluster status.": "Visibile al posto dell'ID Nodo nello stato del cluster.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Visibile al posto dell'ID Dispositivo nello stato del cluster. Negli altri dispositivi verrà presentato come nome predefinito opzionale.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Visibile al posto dell'ID Dispositivo nello stato del cluster. Se viene lasciato vuoto, verrà utilizzato il nome proposto dal dispositivo.",
"Shutdown": "Arresta",
"Simple File Versioning": "Controllo Versione Semplice",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Single level wildcard (matches within a directory only)": "Metacarattere di singolo livello (corrisponde solo all'interno di una cartella)",
"Source Code": "Codice Sorgente",
"Staggered File Versioning": "Controllo Versione Cadenzato",
"Start Browser": "Avvia Browser",
@@ -116,37 +107,34 @@
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing sembra inattivo, oppure c'è un problema con la tua connessione a Internet. Nuovo tentativo…",
"The aggregated statistics are publicly available at {%url%}.": "Le statistiche aggregate sono disponibili pubblicamente su {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configurazione è stata salvata ma non attivata. Devi riavviare Syncthing per attivare la nuova configurazione.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Quotidianamente il software invia le statistiche di utilizzo in forma criptata. Questi dati riguardano i sistemi operativi utilizzati, le dimensioni dei depositi e le versioni del software. Se i dati riportati cambiano verrà mostrata di nuovo questa finestra di dialogo.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "L'ID del nodo inserito non sembra valido. Dovrebbe essere una stringa di 52 caratteri costituita da lettere e numeri, con spazi e trattini opzionali.",
"The entered node 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 nodo inserito non sembra valido. Dovrebbe essere una stringa di 52 o 56 caratteri costituita da lettere e numeri, con spazi e trattini opzionali.",
"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 device ID cannot be blank.": "L'ID del dispositivo non può essere vuoto.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Trova l'ID nella finestra di dialogo \"Modifica > Mostra ID\" dell'altro dispositivo, poi inseriscilo qui. Gli spazi e i trattini sono opzionali (ignorati).",
"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.": "Quotidianamente il software invia le statistiche di utilizzo in forma criptata. Questi dati riguardano i sistemi operativi utilizzati, le dimensioni delle cartelle e le versioni del software. Se i dati riportati sono cambiati, verrà mostrata di nuovo questa finestra di dialogo.",
"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 dispositivo inserito non sembra valido. Dovrebbe essere una stringa di 52 o 56 caratteri costituita da lettere e numeri, con spazi e trattini opzionali.",
"The folder ID cannot be blank.": "L'ID della cartella non può essere vuoto.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "L'ID della cartella dev'essere un identificatore breve (64 caratteri o meno) costituito solamente da lettere, numeri, punti (.), trattini (-) e trattini bassi (_).",
"The folder ID must be unique.": "L'ID della cartella dev'essere unico.",
"The folder path cannot be blank.": "Il percorso della cartella non può essere vuoto.",
"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.": "Vengono utilizzati i seguenti intervalli temporali: per la prima ora viene mantenuta una versione ogni 30 secondi, per il primo giorno viene mantenuta una versione ogni ora, per i primi 30 giorni viene mantenuta una versione al giorno, successivamente viene mantenuta una versione ogni settimana fino al periodo massimo impostato.",
"The maximum age must be a number and cannot be blank.": "La durata massima dev'essere un numero e non può essere vuoto.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "La durata massima di una versione (in giorni, imposta a 0 per mantenere le versioni per sempre).",
"The node ID cannot be blank.": "L'ID del nodo non può essere vuoto.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Trova l'ID nella finestra di dialogo \"Modifica > Mostra ID\" dell'altro nodo, poi inseriscilo qui. Gli spazi e i trattini sono opzionali (ignorati).",
"The number of old versions to keep, per file.": "Il numero di vecchie versioni da mantenere, per file.",
"The number of versions must be a number and cannot be blank.": "Il numero di versioni dev'essere un numero e non può essere vuoto.",
"The repository ID cannot be blank.": "L'ID del deposito non può essere vuoto.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "L'ID del deposito dev'essere un identificatore breve (64 caratteri o meno) costituito solamente da lettere, numeri, punti (.), trattini (-) e trattini bassi (_).",
"The repository ID must be unique.": "L'ID del deposito dev'essere unico.",
"The repository path cannot be blank.": "Il percorso del deposito non può essere vuoto.",
"The rescan interval must be at least 5 seconds.": "L'intervallo di scansione non può essere inferiore a 5 secondi.",
"Unknown": "Sconosciuto",
"Up to Date": "Sincronizzato",
"Upgrade To {%version%}": "Aggiorna Alla {{version}}",
"Upgrade To {%version%}": "Aggiorna alla {{version}}",
"Upgrading": "Aggiornamento",
"Upload Rate": "Velocità Upload",
"Usage": "Utilizzo",
"Use Compression": "Utilizza Compressione",
"Use HTTPS for GUI": "Utilizza HTTPS per l'interfaccia grafica",
"Version": "Versione",
"Versions Path": "Percorso Cartella delle Versioni",
"Versions Path": "Percorso Cartella Versioni",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Le versioni vengono eliminate automaticamente se superano la durata massima o il numero di file permessi in un determinato intervallo temporale.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Ora la stessa operazione deve essere eseguita anche nel nuovo nodo inserendo l'ID di questo nodo.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Quando aggiungi un nuovo deposito ricordati che gli ID vengono utilizzati per collegare i depositi nei nodi. Distinguono maiuscole e minuscole e devono corrispondere esattamente su tutti i nodi.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Anche nel nuovo dispositivo devi aggiungere l'ID di questo, con la stessa procedura.",
"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.": "Quando aggiungi una nuova cartella, ricordati che gli ID vengono utilizzati per collegare le cartelle nei dispositivi. Distinguono maiuscole e minuscole e devono corrispondere esattamente su tutti i dispositivi.",
"Yes": "Sì",
"You must keep at least one version.": "È necessario mantenere almeno una versione.",
"full documentation": "full documentation",
"full documentation": "documentazione completa",
"items": "elementi"
}

View File

@@ -1,28 +1,30 @@
{
"API Key": "API raktas",
"About": "Apie programą",
"Add Node": "Pridėti mazgą",
"Add Repository": "Pridėti saugyklą",
"Add Device": "Pridėti įrenginį",
"Add Folder": "Pridėti aplanką",
"Address": "Adresas",
"Addresses": "Adresai",
"Allow Anonymous Usage Reporting?": "Siųsti anonimišką vartojimo ataskaitą?",
"Announce Server": "Aptikimų serveris",
"Anonymous Usage Reporting": "Anoniminė vartojimo ataskaita",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.",
"Bugs": "Klaidos",
"CPU Utilization": "CAP sunaudojimas",
"CPU Utilization": "Procesoriaus panaudojimas",
"Close": "Uždaryti",
"Comment, when used at the start of a line": "Komentaras naudojamas naujoje eilutėje",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Compression is recommended in most setups.": "Daugumoje atvejų spaudimas rekomenduojamas.",
"Connection Error": "Susijungimo klaida",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Visos teisės saugomos © 2014 Jakob Borg ir šių bendraautorių:",
"Delete": "Trinti",
"Device ID": "Įrenginio ID",
"Device Identification": "Įrenginio identifikacija",
"Device Name": "Įrenginio pavadinimas",
"Disconnected": "Atsijungęs",
"Documentation": "Aprašymas",
"Download Rate": "Parsisiuntimo greitis",
"Edit": "Redaguoti",
"Edit Node": "Redaguoti mazgą",
"Edit Repository": "Redaguoti saugyklą",
"Edit Device": "Keisti įrenginį",
"Edit Folder": "Keisti aplanką",
"Editing": "Redagavimas",
"Enable UPnP": "Įjungti UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Įveskite dvitaškiu atskirtą \"ip:port\" adresą arba žodį \"dynamic\" norėdami gauti adresą automatiškai",
@@ -31,15 +33,17 @@
"File Versioning": "Versijų valdymas",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Nekreipti dėmesio į failų naudojimosi leidimus.\nTaikyti FAT sistemose.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Syncthing programa talpina senesnes versijas .stversions aplanke.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Failai apsaugoti nuo pakeitimų kituose mazguose, bet pakeitimai padaryti šiame mazge bus siųsti visai grupei.",
"Folder": "Aplankas",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Failai apsaugoti nuo pakeitimų atliktų kituose įrenginiuose, bet pakeitimai šiame įrenginyje bus nusiųsti kitiems.",
"Folder ID": "Aplanko ID",
"Folder Master": "Kelias iki aplanko",
"Folder Path": "Kelias iki apkanko",
"GUI Authentication Password": "Valdymo skydelio slaptažodis",
"GUI Authentication User": "Valdymo skydelio vartotojo vardas",
"GUI Listen Addresses": "Valdymo skydelio adresas",
"Generate": "Sukurti",
"Global Discovery": "Visuotinis matomumas",
"Global Discovery Server": "Visuotinio matomumo serveris",
"Global Repository": "Visuotinė saugykla",
"Global State": "Visuotinė būsena",
"Idle": "Laisvas",
"Ignore Patterns": "Nepaisyti šablonų",
"Ignore Permissions": "Nepaisyti failų prieigos leidimų",
@@ -50,19 +54,12 @@
"Last seen": "Paskutinį kartą matytas",
"Latest Release": "Paskutinė versija",
"Local Discovery": "Vietinis matomumas",
"Local Discovery Port": "Vietinio matomumo jungtis",
"Local Repository": "Vietinė saugykla",
"Master Repo": "Pagrindinė saugykla",
"Max File Change Rate (KiB/s)": "Maksimalus failų apsikeitimo greitis (KiB/s)",
"Max Outstanding Requests": "Maksimalus išeinančių užklausų skaičius",
"Local State": "Vietinė būsena",
"Maximum Age": "Maksimalus amžius",
"Multi level wildcard (matches multiple directory levels)": "Keletos lygių pakaitos (atitinka keletą direktorijų lygių)",
"Never": "Niekada",
"No": "Ne",
"No File Versioning": "Nėra versijų valdymo",
"Node ID": "Mazgo vardas",
"Node Identification": "Mazgo tapatybė",
"Node Name": "Mazgo vardas",
"Notice": "Įspėjimas",
"OK": "Gerai",
"Offline": "Atsijungęs",
@@ -70,34 +67,28 @@
"Out Of Sync": "Nesutikrinta",
"Outgoing Rate Limit (KiB/s)": "Išeinančio srauto maksimalus greitis (KiB/s)",
"Override Changes": "Perrašyti pakeitimus",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Kelias iki vietinės saugyklos. Tildės ženklas (~) gali būti naudojamas nuorodai",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Kelias iki papkės kur saugomos senesnės versijos (palikite tuščią norėdami naudoti .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": "Kelias iki aplanko šiame kompiuteryje. Bus sukurtas, jei neegzistuoja. Tildės simbolis (~) gali būti naudojamas kaip trumpinys",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Kelias, kur bus saugomos versijos (palikite tuščią numatytam .stversions aplankui).",
"Please wait": "Prašome palaukti",
"Preview": "Peržiūra",
"Preview Usage Report": "Vartojimo statistikos peržiūra",
"Quick guide to supported patterns": "Trumpas leistinų šablonų vadovas",
"RAM Utilization": "LKA panaudojimas",
"Reconnect Interval (s)": "Pertrauka tarp susijungimų (s)",
"Repository ID": "Saugyklos vardas",
"Repository Master": "Pagrindinė saugykla",
"Repository Path": "Kelias iki saugyklos",
"RAM Utilization": "Atminties naudojimas",
"Rescan": "Nuskaityti iš naujo",
"Rescan Interval": "Pertrauka tarp nuskaitymų",
"Rescan Interval (s)": "Pertrauka tarp nuskaitymų (s)",
"Restart": "Perleisti",
"Restart Needed": "Reikalingas perleidimas",
"Restarting": "Persileidžia",
"Save": "Išsaugoti",
"Scanning": "Skenuojama",
"Select the nodes to share this repository with.": "Pasirinkite mazgus su kuriais norite dalintis šia saugykla",
"Select the devices to share this folder with.": "Pasirinkite įrenginius, su kuriais dalinsitės šį aplanką.",
"Settings": "Nustatymai",
"Share With Nodes": "Dalinamasi su šiais mazgais",
"Share With Devices": "Dalintis su įrenginiais",
"Shared With": "Dalinamasi su",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Trumpas saugyklos identifikavimas. Turi būti vienodas visuose grupės mazguose.",
"Show ID": "Rodyti vardą",
"Shown instead of Node ID in the cluster status.": "Grupės būsenoje rodomas vietoje mazgo vardo.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Grupės būsenoje rodomas vietoje mazgo vardo. Kiti mazgai matys kaip pasirinktinį vardą.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Grupės būsenoje rodomas vietoje mazgo vardo. Bus atnaujintas į mazgo vardą jei nieko neįrašysite.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Trumpas aplanko identifikatorius. Privalo būti toks pat visuose įrenginiuose.",
"Show ID": "Rodyti 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": "Išjungti",
"Simple File Versioning": "Supaprastintas versijų valdymas",
"Single level wildcard (matches within a directory only)": "Vieno lygio pakaitos (atitinka tik vieną direktorijos lygį)",
@@ -116,35 +107,32 @@
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing išjungta arba problemos su Interneto ryšių. Bandoma iš naujo...",
"The aggregated statistics are publicly available at {%url%}.": "Naudojimosi ataskaitą galite peržiūrėti adresu: {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Nauji nustatymai išsaugoti, bet neaktyvuoti. Perleiskite Syncthing programą iš naujo norėdami įgalinti naujus nustatymus.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Šifruota naudojimosi ataskaita siunčiama kasdien. Šiuo metu, ataskaitoje matosi tik operacinė sistema, saugyklos dydis ir programos versija. Jeigu ateityje bus siunčiama daugiau duomenų, jums vėl bus parodyta ši pranešimas.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Įvestas neteisingas mazgo vardas. Turi būti 52 simbolių eilutė su raidėmis ir skaičiais kuriuos galima atskirti tarpu arba brūkšneliu.",
"The entered node 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.": "Įvestas neteisingas mazgo vardas. Turi būti 52 ar 56 simbolių eilutė su raidėmis ir skaičiais kuriuos galima atskirti tarpu arba brūkšneliu.",
"The device ID cannot be blank.": "Įrenginio ID negali būti tuščias.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Įrenginio ID, kurį čia reikia įvesti, gali būti rastas „Keisti > Rodyti vardą“ dialoge kitame įrenginyje. Tarpai ir brūkšneliai nebūtini (ignoruojami).",
"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.": "Kas dieną siunčiama šifruota naudojimo ataskaita. Ji naudojama sekti, kokios platformos naudojamos, aplankų dydžius ir programų versijas. Jei siunčiamų duomenų tipas pasikeis, šis dialogas bus parodytas iš naujo.",
"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.": "Aplanko ID negali būti tuščias.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The folder ID must be unique.": "Aplanko ID turi būti unikalus.",
"The folder path cannot be blank.": "Kelias iki aplanko negali būti tuščias.",
"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.": "Šie pertraukų nustatymai naudojami: pirmą valandą versijos laikomos 30 sekundžių, pirmą dieną versijos laikomos valandą, pirmas 30 dienų versijos laikomos parą, kol nebus viršytas nustatytas maksimalus amžius.",
"The maximum age must be a number and cannot be blank.": "Maksimalus amžius turi būti skaitmuo ir negali būti tuščias laukelis.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Maksimalus laikas kurį bus saugojama versija (dienomis, nustatykite 0 norėdami saugoti amžinai).",
"The node ID cannot be blank.": "Mazgo vardas negali būti tuščias.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Mazgo vardas visada galima sužinoti apsilankius \"Edit > Show ID\". Tarpai ir brūkšneliai nebūtini (ignoruojami).",
"The number of old versions to keep, per file.": "Kiek failo versijų saugoti.",
"The number of versions must be a number and cannot be blank.": "Versijų skaičius turi būti skaitmuo ir negali būti tuščias laukelis.",
"The repository ID cannot be blank.": "Saugyklos vardas negali būti tuščias.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Saugyklos vardas negali būti ilgesnis nei 64 simboliai. Galima naudoti tik raides ir skaičius bet tašką (.), brūkšnelį (-) ir pabraukimą (_).",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Saugyklos vardas negali būti ilgesnis nei 64 simboliai. Galima naudoti tik raides ir skaičius bet tašką (.), brukšnelį (-) ir pabraukimą (_).",
"The repository ID must be unique.": "Saugyklos vardas turi būti unikalus.",
"The repository path cannot be blank.": "Kelias iki saugyklos negali būti tuščias.",
"The rescan interval must be at least 5 seconds.": "Nuskaityti galima nedažniau nei kas 5 sekundes.",
"Unknown": "Velniava",
"Unknown": "Nežinoma",
"Up to Date": "Atnaujinta",
"Upgrade To {%version%}": "Atnaujinti į {{version}}",
"Upgrading": "Atnaujinama",
"Upload Rate": "Išsiuntimo greitis",
"Usage": "Vartosena",
"Use Compression": "Naudoti suspaudimą",
"Use HTTPS for GUI": "Valdymo skydeliui naudoti saugų ryšį ",
"Version": "Versija",
"Versions Path": "Kelias iki versijos",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versijos ištrinamos jei senesnės už nustatyta maksimalų amžių arba jei viršytas maksimalus failų skaičius per nustatytą laiko tarpą.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Kai pridedate naują mazgą neužmirškite, kad kitame gale reikia sukonfigūruoti šį mazgą.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Kai įvedate naują saugyklą neužmirškite, kad ji bus naudojama visuose mazguose. Svarbu visur įvesti visiškai tokį pat saugyklos vardą neužmirštant apie didžiąsias ir mažąsias raides.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Pridėdami įrenginį, turėkite omeny, kad šis įrenginys taip pat turi būti pridėtas kitoje pusėje.",
"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": "Taip",
"You must keep at least one version.": "Būtina saugoti bent vieną versiją.",
"full documentation": "pilna dokumentacija",

140
gui/lang/lang-nb.json Normal file
View File

@@ -0,0 +1,140 @@
{
"API Key": "API-nøkkel",
"About": "Om",
"Add Device": "Legg Til Enhet",
"Add Folder": "Legg Til Mappe",
"Address": "Adresse",
"Addresses": "Adresser",
"Allow Anonymous Usage Reporting?": "Tillat Anonym Datainnsamling?",
"Anonymous Usage Reporting": "Anonym Datainnsamling",
"Any devices configured on an introducer device will be added to this device as well.": "Enheter konfigurert på en introduksjonsenhet vil også bli lagt til denne enheten.",
"Bugs": "Programfeil",
"CPU Utilization": "CPU-utnyttelse",
"Close": "Lukk",
"Comment, when used at the start of a line": "Kommentar, når det blir brukt i starten av en linje.",
"Compression is recommended in most setups.": "Komprimering er anbefalt i de fleste tilfeller.",
"Connection Error": "Tilkoblingsfeil",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright @ 2014 Jakob Borg og følgende Bidragsytere:",
"Delete": "Slett",
"Device ID": "Enhet ID",
"Device Identification": "Enhetskjennemerke",
"Device Name": "Navn På Enhet",
"Disconnected": "Frakoblet",
"Documentation": "Dokumentasjon",
"Download Rate": "Nedlastingsrate",
"Edit": "Rediger",
"Edit Device": "Rediger Enhet",
"Edit Folder": "Rediger Mappe",
"Editing": "Redigerer",
"Enable UPnP": "Aktiver UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": " Skriv inn kommaseparerte \"ip:port\"-adresser, eller \"dynamic\" for å automatisk finne adressen.",
"Enter ignore patterns, one per line.": "Skriv inn mønster som skal utelates, ett per linje.",
"Error": "Feilmelding",
"File Versioning": "Versjonskontroll",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Ignorer bit som styrer filtilgang når en ser etter endringer. Bruk på FAT-filsystem.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Filer blir flyttet til tidsstemplede versjoner i en .stversions-mappe når de blir erstattet eller slettet av syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Filer er beskyttet mot endringer som er gjort på andre enheter, men endringer som er gjort på denne enheten blir sendt til resten av gruppen.",
"Folder ID": "Mappe ID",
"Folder Master": "Styrende Mappe",
"Folder Path": "Mappeplassering",
"GUI Authentication Password": "GUI Passord",
"GUI Authentication User": "GUI Bruker",
"GUI Listen Addresses": "GUI Lytteadresse",
"Generate": "Generer",
"Global Discovery": "Global Søking",
"Global Discovery Server": "Global Søkemotor",
"Global State": "Global Tilstand",
"Idle": "Pause",
"Ignore Patterns": "Utelatelsesmønster",
"Ignore Permissions": "Ignorer Tilgangsbit",
"Incoming Rate Limit (KiB/s)": "Innkommende Hastighetsbegrensning (KiB/s)",
"Introducer": "Introduktør",
"Inversion of the given condition (i.e. do not exclude)": "Invers av den gitte tilstanden (t.d. ikke ekskluder)",
"Keep Versions": "Behold Versjoner",
"Last seen": "Sist sett",
"Latest Release": "Nyeste Versjon",
"Local Discovery": "Lokal Søking",
"Local State": "Lokal Tilstand",
"Maximum Age": "Maksimal Levetid",
"Multi level wildcard (matches multiple directory levels)": "Multinivåsøk (søker på flere mappenivå)",
"Never": "Aldri",
"No": "Nei",
"No File Versioning": "Ingen Versjonskontroll",
"Notice": "Notis",
"OK": "OK",
"Offline": "Frakobla",
"Online": "Tilkobla",
"Out Of Sync": "Ikke Synkronisert",
"Outgoing Rate Limit (KiB/s)": "Utgående Hastighetsbegrensning (KiB/s)",
"Override Changes": "Overstyr Endringer",
"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": "Plasseringen av mappen på datamaskinen. Blir opprettet om den ikke finnes. Krøllstrektegnet (~) kan brukes som forkortelse for",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Plasseringen for lagrede versjoner (la denne være tom for å bruke standard .stversions-mappen i mappen).",
"Please wait": "Vennligst vent",
"Preview": "Forhåndsvisning",
"Preview Usage Report": "Forhåndsvisning Av Datainnsamling",
"Quick guide to supported patterns": "Kjapp innføring i godkjente mønster",
"RAM Utilization": "RAM-utnyttelse",
"Rescan": "Skann På Ny",
"Rescan Interval": "Skanneintervall",
"Restart": "Omstart",
"Restart Needed": "Omstart Kreves",
"Restarting": "Starter På Ny",
"Save": "Lagre",
"Scanning": "Skanner",
"Select the devices to share this folder with.": "Velg enhetene du vil dele denne mappen med.",
"Settings": "Innstillinger",
"Share With Devices": "Del Med Enheter",
"Shared With": "Del Med",
"Short identifier for the folder. Must be the same on all cluster devices.": "Kort kjennemerke på mappen. Må være det samme på alle enheter i en gruppe.",
"Show ID": "Vis ID",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vis i stedet for Eining ID i gruppestatus. Vil bli kringkastet til andre enheter som et valgfritt standardnavn.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vist i stedet for Mappe-ID i gruppestatus. Vil bli oppdatert til navnet enheten kringkaster dersom tomt.",
"Shutdown": "Slå Av",
"Simple File Versioning": "Enkel Versjonskontroll",
"Single level wildcard (matches within a directory only)": "Enkeltnivåsøk (søker kun i en mappe)",
"Source Code": "Kildekode",
"Staggered File Versioning": "Forskjøvet Versjonskontroll",
"Start Browser": "Start Nettleser",
"Stopped": "Stoppa",
"Support / Forum": "Brukerstøtte / Forum",
"Sync Protocol Listen Addresses": "Lytteadresse For Synkroniseringsprotokoll",
"Synchronization": "Synkronisering",
"Syncing": "Synkroniserer",
"Syncthing has been shut down.": "Syncthing har blitt slått av.",
"Syncthing includes the following software or portions thereof:": "Syncthing inkluderer helt eller delvis følgende programvare:",
"Syncthing is restarting.": "Syncthing starter på ny.",
"Syncthing is upgrading.": "Syncthing oppgraderer.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ut til å være nede, eller så er det et problem med nettforbindelsen din. Prøver på ny …",
"The aggregated statistics are publicly available at {%url%}.": "Samlet statistikk er åpent tilgjengelig på {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Innstillingene har blitt lagret men ikke aktivert. Syncthing må starte på ny for å aktivere de nye innstillingene.",
"The device ID cannot be blank.": "Enhets-ID kan ikke være tom.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Enhet-IDen lagt til her kan hentes fram via \"Rediger > Vis ID\"-dialogboksen på den andre enheten. Mellomrom og bindestrek er valgfritt (blir ignorert).",
"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.": "Kryptert informasjon om bruken av programmet blir gjort daglig. Dette blir brukt til å følge med på vanlig brukte systemoppsett, størrelser på mapper, og versjoner av programmet. Om datasettet endrer seg vil denne dialogboksen dukke opp og du vil bli bedt om å godkjenne dette.",
"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.": "IDen for denne enheten er ikke godkjent. Det bør være 52 eller 56 tegn bestående av bokstaver og tall, valgfritt med mellomrom og bindestrek.",
"The folder ID cannot be blank.": "Mappe-ID kan ikke være tom.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Mappe-IDen må være et kort kjennemerke (64 tegn eller mindre) bestående kun av bokstaver, tall og tegnene punktum (.), mellomrom (-) og strek (_).",
"The folder ID must be unique.": "Mappe-ID må være unik.",
"The folder path cannot be blank.": "Mappeplasseringen kan ikke være tom.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "Følgende intervall blir brukt: den første timen blir en versjon lagret hvert 30. sekund, den første dagen blir en versjon lagret hver time, de første 30 dagene blir en versjon lagret hver dag, og inntil maksimal levetid blir en versjon lagret hver uke.",
"The maximum age must be a number and cannot be blank.": "Maksimal levetid må være et tall og kan ikke være tomt.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Maksimal tid å beholde en versjon (i dager, sett til 0 for å beholde versjoner på ubegrenset tid).",
"The number of old versions to keep, per file.": "Antall gamle versjoner å beholde, per fil.",
"The number of versions must be a number and cannot be blank.": "Antall versjoner må være et tall og kan ikke være tomt.",
"The rescan interval must be at least 5 seconds.": "Skanneintervallet må være minst 5 sekund.",
"Unknown": "Ukjent",
"Up to Date": "Oppdatert",
"Upgrade To {%version%}": "Oppgrader Til {{version}}",
"Upgrading": "Oppgraderer",
"Upload Rate": "Opplastingsrate",
"Use Compression": "Bruk Komprimering",
"Use HTTPS for GUI": "Bruk HTTPS for GUI",
"Version": "Versjon",
"Versions Path": "Plassering Av Versjoner",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versjoner blir automatisk slettet når maksimal levetid er nådd eller når antall filer er oversteget.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Merk at når en ny enhet blir lagt til må denne også legges til på andre siden.",
"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.": "Når en ny mappe blir lagt til, husk at Mappe-ID blir brukt til å binde sammen mapper mellom enheter. Det er forskjell på store og små bokstaver, så IDene må være identiske på alle enhetene.",
"Yes": "Ja",
"You must keep at least one version.": "Du må beholde minst én versjon",
"full documentation": "all dokumentasjon",
"items": "element"
}

View File

@@ -1,152 +0,0 @@
{
"API Key": "API-sleutel",
"About": "Over",
"Add Node": "Voeg node toe",
"Add Repository": "Voeg repository toe",
"Address": "Adres",
"Addresses": "Adressen",
"Allow Anonymous Usage Reporting?": "Bijhouden van anonieme gebruikers statistieken toestaan?",
"Announce Server": "Aankondigings Server",
"Anonymous Usage Reporting": "Bijhouden anonieme gebruikers statistieken",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Bugs": "Fouten",
"CPU Utilization": "CPU Gebruik",
"Close": "Sluiten",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Connection Error": "Verbindingsfout",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg en de onderstaande bijdragers:",
"Delete": "Verwijderen",
"Disconnected": "Niet Verbonden",
"Documentation": "Documentatie",
"Download Rate": "Downloadsnelheid",
"Edit": "Bewerk",
"Edit Node": "Bewerk node",
"Edit Repository": "Repository Bijwerken",
"Editing": "Editing",
"Enable UPnP": "UPnP aanzetten",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Geef, gescheiden door komma's, \"ip:port\" adressen of \"dynamic\" voor het automatische vinden van de addressen.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Fout",
"File Versioning": "Versiebeheer",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Bestands permissiebits worden genegeerd wanneer naar veranderingen wordt gekeken. Gebruik dit op FAT bestandsystemen",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Bestanden worden naar de .stversions map verplaatst met een tijdsaanduiding, wanneer ze aangepast of verwijderd worden door syncthing.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Bestanden zijn beschermd tegen verandering gedaan op andere nodes, maar veranderingen op deze node worden naar de rest van het cluster gestuurd",
"Folder": "Map",
"GUI Authentication Password": "GUI Authentificatie Wachtwoord",
"GUI Authentication User": "GUI Authentificatie Gebruikersnaam",
"GUI Listen Addresses": "GUI Inkomend adres",
"Generate": "Genereer",
"Global Discovery": "Globaal zoeken",
"Global Discovery Server": "Globale zoekserver",
"Global Repository": "Globale repository",
"Idle": "Inactief",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Rechten negeren",
"Incoming Rate Limit (KiB/s)": "Download snelheidslimiet (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": "Versies behouden",
"Last seen": "Laatst gezien op",
"Latest Release": "Laatste uitgave",
"Local Discovery": "Lokaal zoeken",
"Local Discovery Port": "Lokaal zoeken-poort",
"Local Repository": "Lokale repository",
"Master Repo": "Tegen veranderingen beschermen",
"Max File Change Rate (KiB/s)": "Maximale bestands uitwisselsnelheid (KiB/s)",
"Max Outstanding Requests": "Maximaal aantal openstaande aanvragen",
"Maximum Age": "Maximum leeftijd",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Nooit",
"No": "Nee",
"No File Versioning": "Geen versiebeheer",
"Node ID": "Node ID",
"Node Identification": "Node Identificatie",
"Node Name": "Node naam",
"Notice": "Notificatie",
"OK": "OK",
"Offline": "Offline",
"Online": "Online",
"Out Of Sync": "Niet gesynchroniseerd",
"Outgoing Rate Limit (KiB/s)": "Uitgaande snelheidslimiet (KiB/s)",
"Override Changes": "Veranderingen overschrijven",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Pad naar de repository op de lokale computer. Word aangemaakt indien deze niet bestaat. Het tilde (~) karakter kan gebruikt worden als afkorting voor",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Pad waar de verschillende versies opgeslagen dienen te worden (laat leeg voor de standaard map '.stversion' in de repository).",
"Please wait": "Even geduld",
"Preview": "Voorbeeld",
"Preview Usage Report": "Bekijk gebruiksstatistieken",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "RAM gebruik",
"Reconnect Interval (s)": "Herverbind-interval (s)",
"Repository ID": "Repository ID",
"Repository Master": "Hoofd repository",
"Repository Path": "Pad van repository",
"Rescan": "Opnieuw scannen",
"Rescan Interval": "Scanfrequentie",
"Rescan Interval (s)": "Herscan interval (s)",
"Restart": "Herstart",
"Restart Needed": "Herstart nodig",
"Restarting": "Herstarten",
"Save": "Bewaar",
"Scanning": "Aan het zoeken",
"Select the nodes to share this repository with.": "Selecteer de nodes om deze repository mee te delen",
"Settings": "Instellingen",
"Share With Nodes": "Deel met nodes",
"Shared With": "Gedeeld met",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Korte naam voor de repository. Moet hetzelfde zijn op alle nodes in het cluster.",
"Show ID": "Toon ID",
"Shown instead of Node ID in the cluster status.": "Wordt weergegeven i.p.v. het node ID in de cluster status",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "De node naam wordt getoond in plaats van de node ID in het cluster status overzicht. Deze naam wordt aan andere nodes voorgesteld als een optionele, standaardnaam.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "De node naam wordt getoond in plaats van de node ID in het cluster status overzicht. Deze naam wordt geüpdatet met de naam die de node zelf adverteert indien dit veld leeg wordt gelaten.",
"Shutdown": "Sluit af",
"Simple File Versioning": "Eenvoudig versiebeheer",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Source Code": "Broncode",
"Staggered File Versioning": "Staggered File Versioning",
"Start Browser": "Start browser",
"Stopped": "Gestopt",
"Support / Forum": "Support / Forum",
"Sync Protocol Listen Addresses": "Synchronisatie protocol luister adres",
"Synchronization": "Synchronisatie",
"Syncing": "Aan het synchroniseren",
"Syncthing has been shut down.": "Syncthing is afgesloten",
"Syncthing includes the following software or portions thereof:": "De volgende software of delen daarvan zijn onderdeel van syncthing:",
"Syncthing is restarting.": "Syncthing is aan het herstarten.",
"Syncthing is upgrading.": "Syncthing is aan het upgraden.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing lijkt afgesloten te zijn, of er is een verbindingsprobleem met het internet. Nieuwe poging....",
"The aggregated statistics are publicly available at {%url%}.": "The verzamelde statistieken zijn publiek beschikbaar op {{url}}",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "De configuratie is opslagen maar nog niet actief. Syncthing moet opnieuw opgestart worden om de nieuwe configuratie te activeren.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "De versleutelde gebruikers statistieken worden dagelijks verstuurd. Deze worden gebruikt om veelgebruikte platformen, repo groottes en app versies bij te houden. Als er nieuwe statistieken worden bijgehouden, wordt dit venster weer getoond.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Het ingevoerde node ID lijkt niet valide te zijn. Het moet een 52 karakter lange string zijn bestaande uit letters en cijfers, spaties en streepjes zijn optioneel.",
"The entered node 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.": "Het ingevoerde node ID lijkt niet valide te zijn. Het moet een 52 of 56 karakter lange string zijn, bestaande uit letters en cijfers, spaties en streepjes zijn optioneel.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "De volgende intervallen worden gebruikt: het eerste uur worden versies iedere 30 seconden bewaard, de eerste dag worden versies ieder uur bewaard, de eerste 30 dagen worden versies iedere dag bewaard, tot de maximale leeftijd worden versies iedere week bewaard.",
"The maximum age must be a number and cannot be blank.": "De maximum leeftijd moet uit cijfers bestaan en mag niet leeggelaten worden.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "De maximale tijdsduur om een versie te bewaren (in dagen, gebruik 0 om versies voor altijd te bewaren).",
"The node ID cannot be blank.": "Er moet een node ID ingevoerd worden",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Het node ID dat ingevoerd moet worden kan op de andere node gevonden via \"Bewerk > Toon ID\". Spaties en streepjes zijn toegestaan (worden genegeerd).",
"The number of old versions to keep, per file.": "Het aantal versies dat bewaard moet worden per file.",
"The number of versions must be a number and cannot be blank.": "Het aantal nummers moet een getal zijn en mag niet leeg blijven.",
"The repository ID cannot be blank.": "Er moet een repository ID ingevoerd worden.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Het repository ID moet een korte naam zijn (met 64 karakters of minder) en mag alleen bestaan uit cijfers, letters, punten (.), streepjes (-) en liggende streepjes (_). ",
"The repository ID must be unique.": "Het repository ID moet uniek zijn.",
"The repository path cannot be blank.": "Het repository ID moet ingevuld worden.",
"The rescan interval must be at least 5 seconds.": "De scanfrequentie moet minimaal 5 seconde zijn.",
"Unknown": "Onbekend",
"Up to Date": "Gesynchroniseerd",
"Upgrade To {%version%}": "Upgrade naar {{version}}",
"Upgrading": "Bezig met upgrade",
"Upload Rate": "Upload snelheid",
"Usage": "Gebruik",
"Use Compression": "Compressie gebruiken",
"Use HTTPS for GUI": "Gebruik HTTPS voor de GUI",
"Version": "Versie",
"Versions Path": "Bestandspad versies",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versies worden automatisch verwijderd als deze ouder zijn dan de maximale leeftijd of als ze het maximaal aantal toegestane bestanden per interval overschrijden. ",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Bedenk bij het toevoegen van een nieuwe node dat deze node ook toegevoegd moet worden aan de kant van de nieuwe node.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Bedenk bij het toevoegen van een nieuwe repository dat het repository ID de repositores met elkaar verbindt tussen de nodes. Ze zijn hoofdlettergevoelig en moeten exact dezelfde naam hebben op alle nodes.",
"Yes": "Ja",
"You must keep at least one version.": "Minstens 1 versie moet bewaard blijven.",
"full documentation": "full documentation",
"items": "objecten"
}

140
gui/lang/lang-nn.json Normal file
View File

@@ -0,0 +1,140 @@
{
"API Key": "API-nøkkel",
"About": "Om",
"Add Device": "Legg Til Eining",
"Add Folder": "Legg Til Mappe",
"Address": "Adresse",
"Addresses": "Adresser",
"Allow Anonymous Usage Reporting?": "Tillat Anonym Datainnsamling?",
"Anonymous Usage Reporting": "Tillat Anonym Datainnsamling",
"Any devices configured on an introducer device will be added to this device as well.": "Einingar konfigurert på ein introduksjonseining vil òg verte lagt til denne eininga.",
"Bugs": "Programfeil",
"CPU Utilization": "CPU-utnytting",
"Close": "Lukk",
"Comment, when used at the start of a line": "Kommentar, når det vert brukt i starten av ei linje.",
"Compression is recommended in most setups.": "Komprimering er tilrådd i dei fleste høve.",
"Connection Error": "Tilkoplingsfeil",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright @ 2014 Jakob Borg og følgjande Bidragsytarar:",
"Delete": "Slett",
"Device ID": "Eining ID",
"Device Identification": "Einingskjennemerkje",
"Device Name": "Namn På Eining",
"Disconnected": "Fråkopla",
"Documentation": "Dokumentasjon",
"Download Rate": "Nedlastingsrate",
"Edit": "Rediger",
"Edit Device": "Rediger Eining",
"Edit Folder": "Rediger Mappe",
"Editing": "Redigerer",
"Enable UPnP": "Aktiver UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Skriv inn \"ip:port\"-adresser med komma mellom kvar adresse, eller \"dynamisk\" for å automatisk søkja opp adressa.",
"Enter ignore patterns, one per line.": "Skriv inn mønster som skal utelatast, eitt per linje.",
"Error": "Feilmelding",
"File Versioning": "Versjonskontroll",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Ignorer bit som styrer filtilgang når ein ser etter endringar. Bruk på FAT-filsystem.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Filer vert flytta til tidsstempla versjonar i ei .stversions-mappe når dei vert erstatta eller sletta av syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Filer er beskytta mot endringar gjort på andre einingar, men endringar gjort på denne eininga vert sendt til resten av gruppa.",
"Folder ID": "Mappe ID",
"Folder Master": "Styrande Mappe",
"Folder Path": "Mappeplassering",
"GUI Authentication Password": "GUI Passord",
"GUI Authentication User": "GUI Brukar",
"GUI Listen Addresses": "GUI Lytteadresse",
"Generate": "Generer",
"Global Discovery": "Global Søking",
"Global Discovery Server": "Global Søkjemotor",
"Global State": "Global Tilstand",
"Idle": "Pause",
"Ignore Patterns": "Utelatingsmønster",
"Ignore Permissions": "Ignorer Tilgangsbit",
"Incoming Rate Limit (KiB/s)": "Innkomande Hastigheitsgrense (KiB/s)",
"Introducer": "Introduktør",
"Inversion of the given condition (i.e. do not exclude)": "Invers av den gitte tilstanden (t.d. ikkje ekskluder)",
"Keep Versions": "Behald Versjonar",
"Last seen": "Sist sett",
"Latest Release": "Nyaste Versjon",
"Local Discovery": "Lokal Søking",
"Local State": "Lokal Tilstand",
"Maximum Age": "Maksimal Levetid",
"Multi level wildcard (matches multiple directory levels)": "Multinivåsøk (søkjer på fleire mappenivå)",
"Never": "Aldri",
"No": "Nei",
"No File Versioning": "Ingen Versjonskontroll",
"Notice": "Notis",
"OK": "OK",
"Offline": "Fråkopla",
"Online": "Tilkopla",
"Out Of Sync": "Ikkje Synkronisert",
"Outgoing Rate Limit (KiB/s)": "Utgåande Hastigheitsgrense (KiB/s)",
"Override Changes": "Overstyr Endringar",
"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": "Plasseringen av mappa på datamaskinen. Vert oppretta om han ikkje finst. Krøllstrekteiknet (~) kan brukast som forkorting for",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Plasseringa for lagra versjonar (la denne vera tom for å bruka standard .stversions-mappa i mappa).",
"Please wait": "Ver venleg og vent",
"Preview": "Førehandsvisning",
"Preview Usage Report": "Førehandsvis Datainnsamling",
"Quick guide to supported patterns": "Kjapp innføring i godkjente mønster",
"RAM Utilization": "RAM-utnytting",
"Rescan": "Skann På Ny",
"Rescan Interval": "Skanneintervall",
"Restart": "Omstart",
"Restart Needed": "Omstart Trengs",
"Restarting": "Startar På Ny",
"Save": "Lagre",
"Scanning": "Skannar",
"Select the devices to share this folder with.": "Vel einingane du vil dela denne mappa med.",
"Settings": "Innstillingar",
"Share With Devices": "Del Med Einingar",
"Shared With": "Delt Med",
"Short identifier for the folder. Must be the same on all cluster devices.": "Kort kjennemerke på mappa. Må vera det same på alle einingar i ei gruppe.",
"Show ID": "Vis ID",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vis i staden for Eining ID i gruppestatus. Vil verta kringkasta til andre einingar som eit valfritt standardnamn.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vist i staden for Mappe-ID i gruppestatus. Vil verta oppdatert til namnet eininga kringkastar dersom tomt.",
"Shutdown": "Slå Av",
"Simple File Versioning": "Enkel Versjonskontroll",
"Single level wildcard (matches within a directory only)": "Enkeltnivåsøk (søkjer kun i ei mappe)",
"Source Code": "Kildekode",
"Staggered File Versioning": "Forskyvd Versjonskontroll",
"Start Browser": "Start Nettlesar",
"Stopped": "Stoppa",
"Support / Forum": "Brukarstøtte / Forum",
"Sync Protocol Listen Addresses": "Lytteadresse For Synkroniseringsprotokoll",
"Synchronization": "Synkronisering",
"Syncing": "Synkroniserer",
"Syncthing has been shut down.": "Syncthing har blitt slått av.",
"Syncthing includes the following software or portions thereof:": "Syncthing inkluderer føljande programvare heilt eller delvis:",
"Syncthing is restarting.": "Syncthing startar på ny.",
"Syncthing is upgrading.": "Syncthing oppgraderer.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ut til å vera nede, eller så er det eit problem med nettilkoplinga di. Prøvar på ny …",
"The aggregated statistics are publicly available at {%url%}.": "Samla statistikk er opent tilgjengeleg på {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Instillingane har blitt lagra men ikkje aktivert. Syncthing må starta på ny for å aktivera dei nye instillingane.",
"The device ID cannot be blank.": "Eining ID kan ikkje vera tom.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Eining-IDen lagt til her kan hentast fram via \"Rediger > Vis ID\"-dialogboksen på den andre eininga. Mellomrom og bindestrek er valfritt (vert ignorert).",
"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.": "Kryptert informasjon om bruken av programmet vert gjort dagleg. Dette vert brukt til å følgja med på vanleg brukte systemoppsett, storleikar på mapper, og versjonar av programmet. Om datasettet endrar seg vil denne dialogboksen dukka opp og du vil bli bedt om å godkjenna dette.",
"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.": "IDen for denne eininga er ikkje godkjend. Det bør vera 52 eller 56 teikn samansett av bokstavar og tal, valfritt med mellomrom og bindestrek.",
"The folder ID cannot be blank.": "Mappe ID kan ikkje vera tom.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Mappe-IDen må vera eit kort kjennemerke (64 teikn eller mindre) samansett kun av bokstavar, tal og teikna punktum (.), mellomrom (-) og strek (_).",
"The folder ID must be unique.": "Mappe ID må vera unik.",
"The folder path cannot be blank.": "Mappeplasseringa kan ikkje vera tom.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "Fylgjande intervall vert brukt: den fyrste timen vert ein versjon lagra kvart 30. sekund, den fyrste dagen vert ein versjon lagra kvar time, dei fyrste 30 dagane vert ein versjon lagra kvar dag, og inntil høgaste levetid vert ein versjon lagra kvar uke.",
"The maximum age must be a number and cannot be blank.": "Maksimal levetid må vera eit tal og kan ikkje vera blankt.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Maksimalt tidsrom å behalda ein versjon (i dagar, set til 0 for å behalda versjonar for ubegrensa tid.)",
"The number of old versions to keep, per file.": "Tal på gamle versjonar ein skal behalda, per fil.",
"The number of versions must be a number and cannot be blank.": "Tal på versjonar må vera eit tal og kan ikkje vera tomt.",
"The rescan interval must be at least 5 seconds.": "Skanneintervallet må vera minst 5 sekund.",
"Unknown": "Ukjent",
"Up to Date": "Oppdatert",
"Upgrade To {%version%}": "Oppgrader Til {{version}}",
"Upgrading": "Oppgraderer",
"Upload Rate": "Opplastingsrate",
"Use Compression": "Bruk Komprimering",
"Use HTTPS for GUI": "Bruk HTTPS for GUI",
"Version": "Versjon",
"Versions Path": "Plassering Av Versjonar",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versjonar vert automatisk sletta når maksimal levetid er nådd eller når det tillatte talet på filer er overstige.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Merk at når ein ny eining vert lagt til må denne òg leggast til på andre sida.",
"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.": "Når ei ny mappe vert lagt til, hugs at Mappe-ID vert brukt til å binda saman mapper mellom einingar. Det er skilnad på store og små bokstavar, så IDane må vera identiske på alle einingane.",
"Yes": "Ja",
"You must keep at least one version.": "Du må behalda minst ein versjon.",
"full documentation": "all dokumentasjon",
"items": "element"
}

140
gui/lang/lang-pl.json Normal file
View File

@@ -0,0 +1,140 @@
{
"API Key": "Klucz API",
"About": "O Syncthing",
"Add Device": "Dodaj urządzenie",
"Add Folder": "Dodaj folder",
"Address": "Adres",
"Addresses": "Adresy",
"Allow Anonymous Usage Reporting?": "Zezwalaj na anonimowe statystyki użycia",
"Anonymous Usage Reporting": "Anonimowe statystyki użycia",
"Any devices configured on an introducer device will be added to this device as well.": "Wszystkie urządzenia skonfigurowane na urządzeniu wprowadzającym zostaną dodane także do tego urządzenia.",
"Bugs": "Błędy",
"CPU Utilization": "Użycie CPU",
"Close": "Zamknij",
"Comment, when used at the start of a line": "Komentarz, jeżeli użyty na początku linii",
"Compression is recommended in most setups.": "Kompresja jest zalecana w większości przypadków",
"Connection Error": "Błąd połączenia",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg i następujący współautorzy:",
"Delete": "Usuń",
"Device ID": "ID urządzenia",
"Device Identification": "Identyfikator urządzenia",
"Device Name": "Nazwa urządzenia",
"Disconnected": "Rozłączony",
"Documentation": "Dokumentacja",
"Download Rate": "Prędkość pobierania",
"Edit": "Edytuj",
"Edit Device": "Edytuj urządzenie",
"Edit Folder": "Edytuj folder",
"Editing": "Edytowanie",
"Enable UPnP": "Włącz UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Wprowadź adresy oddzielone przecinkiem \"ip:port\", lub wpisz \"dynamic\" w celu wykrycia adresu. ",
"Enter ignore patterns, one per line.": "Wprowadz wzorce ignorowania, jeden w każdej linii.",
"Error": "Błąd",
"File Versioning": "Wersjonowanie plików",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Uprawnienia plików są ignorowane przy poszukiwaniu zmian. Używaj w systemie plików FAT",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "W momencie zmiany lub usuwania pliki są przenoszone do oznaczonych datą wersji wewnątrz folderu .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.": "Pliki są zabezpieczone przed zmianami na innym urządzeniu, jednak zmiany w tym urządzeniu będą wysłane do reszty.",
"Folder ID": "ID folderu",
"Folder Master": "Główny folder",
"Folder Path": "Ścieżka folderu",
"GUI Authentication Password": "Hasło",
"GUI Authentication User": "Użytkownik",
"GUI Listen Addresses": "Adres nasłuchiwania",
"Generate": "Generuj",
"Global Discovery": "Globalne odnajdywanie",
"Global Discovery Server": "Globalny serwer rozgłoszeniowy",
"Global State": "Status globalny",
"Idle": "Bezczynny",
"Ignore Patterns": "Wzorce ignorowania",
"Ignore Permissions": "Ignoruj uprawnienia",
"Incoming Rate Limit (KiB/s)": "Ograniczenie prędkości odbierania (KiB/s)",
"Introducer": "Wprowadzający",
"Inversion of the given condition (i.e. do not exclude)": "Odwrócenie podanego wzorca (np. nie wykluczaj)",
"Keep Versions": "Zachowuj wersje",
"Last seen": "Ostatnio widziany",
"Latest Release": "Najnowsza wersja",
"Local Discovery": "Lokalne odnajdywanie",
"Local State": "Status lokalny",
"Maximum Age": "Maksymalny wiek",
"Multi level wildcard (matches multiple directory levels)": "Wieloznaczność na poziomie katalogów i plików (uwzględnia nazwy folderów i plików)",
"Never": "Nigdy",
"No": "Nie",
"No File Versioning": "Bez wersjonowania pliku",
"Notice": "Wskazówka",
"OK": "OK",
"Offline": "Rozłączony",
"Online": "Połączony",
"Out Of Sync": "Niezsynchronizowane",
"Outgoing Rate Limit (KiB/s)": "Ograniczenie prędkości wysyłania (KiB/s)",
"Override Changes": "Nadpisz zmiany",
"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": "Ścieżka do lokalnego folderu. Zostanie utworzona jeżeli nie istnieje.\nZnak tyldy (~) może zostać użyty jako skrót do",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Ścieżka gdzie będą przechowywane wersje (pozostaw puste dla domyślnego folderu .stversions)",
"Please wait": "Proszę czekać",
"Preview": "Podgląd",
"Preview Usage Report": "Podgląd raportu użycia.",
"Quick guide to supported patterns": "Krótki przewodnik po obsługiwanych wzorcach",
"RAM Utilization": "Użycie pamięci RAM",
"Rescan": "Skanuj ponownie",
"Rescan Interval": "Interwał skanowania",
"Restart": "Uruchom ponownie",
"Restart Needed": "Wymagane ponowne uruchomienie",
"Restarting": "Uruchamianie ponowne",
"Save": "Zapisz",
"Scanning": "Skanowanie",
"Select the devices to share this folder with.": "Wybierz urządzenie, któremu udostępnić folder.",
"Settings": "Ustawienia",
"Share With Devices": "Udostępnij dla urządzenia",
"Shared With": "Współdzielony z",
"Short identifier for the folder. Must be the same on all cluster devices.": "Krótki identyfikator folderu. Musi być taki sam na wszystkich urządzeniach.",
"Show ID": "Pokaż ID",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Pokazane w statusie zamiast ID urządzenia.Zostanie wysłane do innych urządzeń jako opcjonalna domyślna nazwa.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Pokazane w statusie zamiast ID urządzenia. Zostanie zaktualizowane do nazwy urządzenia jeżeli pozostanie puste.",
"Shutdown": "Wyłącz",
"Simple File Versioning": "Proste wersjonowanie pliku",
"Single level wildcard (matches within a directory only)": "Wieloznaczność na poziomie plików (uwzględnia nazwy plików)",
"Source Code": "Kod źródłowy",
"Staggered File Versioning": "Rozbudowane wersjonowanie pliku",
"Start Browser": "Uruchom przeglądarkę",
"Stopped": "Zatrzymany",
"Support / Forum": "Wsparcie / Forum",
"Sync Protocol Listen Addresses": "Adres nasłuchu protokołu synchronizacji",
"Synchronization": "Synchronizacja",
"Syncing": "Synchronizowanie",
"Syncthing has been shut down.": "Syncthing został wyłączony",
"Syncthing includes the following software or portions thereof:": "Syncthing zawiera następujące oprogramowanie lub ich częśći:",
"Syncthing is restarting.": "Restart Syncthing",
"Syncthing is upgrading.": "Aktualizowanie Syncthing",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing wydaje się być wyłączony lub jest problem z twoim połączeniem internetowym. Próbuje ponownie...",
"The aggregated statistics are publicly available at {%url%}.": "Zebrane statystyki są publicznie dostępna pod adresem {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Konfiguracja została zapisana lecz nie jest aktywna. Syncthing musi zostać zrestartowany aby aktywować nową konfiguracje.",
"The device ID cannot be blank.": "ID urządzenia nie może być puste.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "ID urządzenia można znaleźć w \"Edytuj -> Pokaż ID\" na zdalnym urządzeniu.\nOdstępy i myślniki są opcjonalne (ignorowane)",
"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.": "Zaszyfrowane raporty użycia są wysyłane codziennie. Są one używane w celach statystycznych platform, rozmiarów katalogów i wersji programu. Jeżeli zgłaszane dane ulegną zmianie, ponownie wyświetli się ta informacja.",
"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.": "Wprowadzone ID urządzenia wygląda na niepoprawne. Musi zawierać 52 lub 56 znaków składających się z liter i cyfr. Odstępy i myślniki są opcjonalne.",
"The folder ID cannot be blank.": "ID folderu nie może być puste.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "ID folderu musi być krótkim identyfikatorem (64 lub mniej znaków) zawierać litery, cyfry, znaki kropki (.), myślnika (-) i podkreślenia (_).",
"The folder ID must be unique.": "ID folderu musi być unikalne.",
"The folder path cannot be blank.": "Ścieżka folderu nie może być pusta.",
"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.": "Następujący interwał jest używany: dla pierwszej godziny wersja jest zachowywana co 30 sekund, dla pierwszego dnia wersja jest zachowywana co godzinę, dla pierwszego miesiąca wersja jest zachowywana codziennie, aż do maksymalnego odstępu zapisywania wersji co tydzień.",
"The maximum age must be a number and cannot be blank.": "Maksymalny wiek musi być liczbą i nie może być pusty.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Maksymalny czas zachowania wersji (w dniach, ustaw 0 aby zachować na zawsze)",
"The number of old versions to keep, per file.": "Liczba wersji pliku do zachowania.",
"The number of versions must be a number and cannot be blank.": "Liczba wersji musi być liczbą i nie może być pusta.",
"The rescan interval must be at least 5 seconds.": "Interwał skanowania musi wynosić co najmniej 5 sekund.",
"Unknown": "Nieznany",
"Up to Date": "Aktualny",
"Upgrade To {%version%}": "Aktualizuj do {{version}}",
"Upgrading": "Aktualizowanie",
"Upload Rate": "Prędkość wysyłania",
"Use Compression": "Używaj kompresji",
"Use HTTPS for GUI": "Używaj HTTPS",
"Version": "Wersja",
"Versions Path": "Ścieżka wersji",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Wersje zostają automatycznie usunięte jeżeli są starsze niż maksymalny wiek lub przekraczają liczbę dopuszczalnych wersji.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Gdy dodajesz nowe urządzenie, pamiętaj że urządzenie musi zostać dodane także po drugiej stronie.",
"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.": "Przy dodawaniu nowego folderu, pamiętaj, że ID użyte jest do łączenia folderów pomiędzy urządzeniami. Wielkość liter ciągu ma znaczenie musi zgadzać się na wszystkich urządzeniach.",
"Yes": "Tak",
"You must keep at least one version.": "Musisz posiadać przynajmniej jedną wersję",
"full documentation": "pełna dokumentacja",
"items": "pozycji"
}

View File

@@ -1,68 +1,65 @@
{
"API Key": "Chave da API",
"About": "Acerca da aplicação",
"Add Node": "Adicionar ",
"Add Repository": "Adicionar repositório",
"Add Device": "Adicionar dispositivo",
"Add Folder": "Adicionar pasta",
"Address": "Endereço",
"Addresses": "Endereços",
"Allow Anonymous Usage Reporting?": "Permitir envio de relatórios anónimos de utilização?",
"Announce Server": "Servidor de anúncios",
"Anonymous Usage Reporting": "Enviar relatórios anónimos de utilização",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Any devices configured on an introducer device will be added to this device as well.": "Quaisquer dispositivos configurados num dispositivo apresentador serão também adicionados a este dispositivo.",
"Bugs": "Erros",
"CPU Utilization": "Utilização da CPU",
"Close": "Fechar",
"Comment, when used at the start of a line": "Comentário, quando usado no início de uma linha",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Compression is recommended in most setups.": "A compressão é recomendada na maior parte dos casos.",
"Connection Error": "Erro de ligação",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Direitos reservados © 2014 Jakob Borg e os seguintes contribuidores:",
"Delete": "Eliminar",
"Device ID": "ID do dispositivo",
"Device Identification": "Identificação do dispositivo",
"Device Name": "Nome do dispositivo",
"Disconnected": "Desconectado",
"Documentation": "Documentação",
"Download Rate": "Velocidade de recepção",
"Edit": "Editar",
"Edit Node": "Editar ",
"Edit Repository": "Editar repositório",
"Edit Device": "Editar dispositivo",
"Edit Folder": "Editar pasta",
"Editing": "Editando",
"Enable UPnP": "Activar UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduza endereços \"ip:porto\" separados por vírgulas ou \"dynamic\" para descobrir automaticamente o endereço.",
"Enter ignore patterns, one per line.": "Coloque os padrões a ignorar, um por linha.",
"Enter ignore patterns, one per line.": "Escreva os padrões de exclusão, um por linha.",
"Error": "Erro",
"File Versioning": "Gestão de versões",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "As permissões do ficheiro são ignoradas ao procurar alterações. Utilize nos sistemas de ficheiros FAT.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Os ficheiros são movidos para versões marcadas com o tempo numa pasta .stversions, quando substituídos ou apagados pelo syncthing.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Os ficheiros são protegidos das alterações feitas noutros s, mas alterações feitas neste serão enviadas para o resto do agrupamento.",
"Folder": "Pasta",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Os ficheiros estão protegidos contra alterações feitas noutros dispositivos, mas alterações feitas neste dispositivo serão enviadas ao resto do grupo.",
"Folder ID": "ID da pasta",
"Folder Master": "Pasta mestre",
"Folder Path": "Caminho da pasta",
"GUI Authentication Password": "Senha da autenticação na interface gráfica",
"GUI Authentication User": "Utilizador da autenticação na interface gráfica",
"GUI Listen Addresses": "Endereço de escuta da interface gráfica",
"Generate": "Gerar",
"Global Discovery": "Busca global",
"Global Discovery Server": "Servidor da busca global",
"Global Repository": "Repositório global",
"Global State": "Estado global",
"Idle": "Em espera",
"Ignore Patterns": "Ignorar padrões",
"Ignore Patterns": "Padrões de exclusão",
"Ignore Permissions": "Ignorar permissões",
"Incoming Rate Limit (KiB/s)": "Limite de velocidade de recepção (KiB/s)",
"Introducer": "Introducer",
"Introducer": "Apresentador",
"Inversion of the given condition (i.e. do not exclude)": "Inversão de uma dada condição (ou seja, não excluir)",
"Keep Versions": "Manter versões",
"Last seen": "Última vez que foi verificado",
"Latest Release": "Última versão",
"Local Discovery": "Busca local",
"Local Discovery Port": "Porto da busca local",
"Local Repository": "Repositório local",
"Master Repo": "Repositório mestre",
"Max File Change Rate (KiB/s)": "Velocidade máxima de alterações de ficheiros (KiB/s)",
"Max Outstanding Requests": "Número máximo de pedidos pendentes",
"Local State": "Estado local",
"Maximum Age": "Idade máxima",
"Multi level wildcard (matches multiple directory levels)": "Curinga multi-nível (faz corresponder a vários níveis de pastas)",
"Multi level wildcard (matches multiple directory levels)": "Caractere polivalente multi-nível (faz corresponder a vários níveis de pastas)",
"Never": "Nunca",
"No": "Não",
"No File Versioning": "Sem gestão de versões de ficheiros",
"Node ID": "ID do nó",
"Node Identification": "Identificação do nó",
"Node Name": "Nome do nó",
"Notice": "Avisos",
"OK": "OK",
"Offline": "Desconectado",
@@ -70,37 +67,31 @@
"Out Of Sync": "Não sincronizado",
"Outgoing Rate Limit (KiB/s)": "Limite da velocidade de envio (KiB/s)",
"Override Changes": "Sobrepor alterações",
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Caminho para o repositório no computador local. Será criado se não existir. O carácter (~) pode ser utilizado como atalho para",
"Path where versions should be stored (leave empty for the default .stversions folder in the repository).": "Caminho onde as versões são guardadas (deixe vazio para usar a pasta pré-definida .stversions no repositório).",
"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": "Caminho para a pasta no computador local. Será criada, caso não exista. O caractere (~) pode ser utilizado como atalho para",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Caminho onde as versões são guardadas (deixe vazio para usar a pasta pré-definida .stversions na pasta).",
"Please wait": "Aguarde",
"Preview": "Previsão",
"Preview Usage Report": "Pré-visualizar relatório de utilização",
"Quick guide to supported patterns": "Guia rápido dos padrões suportados",
"RAM Utilization": "Utilização da RAM",
"Reconnect Interval (s)": "Intervalo de reestabelecimento de ligação (s)",
"Repository ID": "ID do repositório",
"Repository Master": "Repositório mestre",
"Repository Path": "Caminho do repositório",
"Rescan": "Verificar agora",
"Rescan Interval": "Intervalo entre verificações",
"Rescan Interval (s)": "Intervalo entre verificações (em segundos)",
"Restart": "Reiniciar",
"Restart Needed": "É preciso reiniciar",
"Restarting": "Reiniciando",
"Save": "Gravar",
"Scanning": "Verificando",
"Select the nodes to share this repository with.": "Seleccione os s com os quais vai partilhar este repositório.",
"Select the devices to share this folder with.": "Seleccione os dispositivos com os quais vai partilhar esta pasta.",
"Settings": "Configurações",
"Share With Nodes": "Partilhar com os s",
"Share With Devices": "Partilhar com os dispositivos",
"Shared With": "Partilhado com",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Identificador curto para o repositório. Tem que ser igual em todos os s do agrupamento.",
"Short identifier for the folder. Must be the same on all cluster devices.": "Identificador curto para a pasta. Tem que ser igual em todos os dispositivos do grupo.",
"Show ID": "Mostrar ID",
"Shown instead of Node ID in the cluster status.": "Apresentado ao invés do ID do nó no estado do agrupamento.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Apresentado ao invés do ID do na informação de estado do agrupamento. Será divulgado aos outros nós como um nome predefinido opcional.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Apresentado ao invés do ID do nó na informação de estado do agrupamento. Será actualizado para o nome que o nó divulga, se for deixado em branco.",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Apresentado ao invés do ID do dispositivo no indicador de estado do grupo. Será divulgado aos outros dispositivos como um nome pré-definido opcional.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Apresentado ao invés do ID do dispositivo no indicador de estado do grupo. Será actualizado para o nome que o dispositivo divulga, se for deixado em branco.",
"Shutdown": "Desligar",
"Simple File Versioning": "Gestão de versões de ficheiros simples",
"Single level wildcard (matches within a directory only)": "Curinga de um só nível (faz corresponder apenas dentro de uma pasta)",
"Single level wildcard (matches within a directory only)": "Caractere polivalente de um só nível (faz corresponder apenas dentro de uma pasta)",
"Source Code": "Código fonte",
"Staggered File Versioning": "Gestão de versões de ficheiros escalonada",
"Start Browser": "Iniciar navegador",
@@ -116,35 +107,32 @@
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "O Syncthing parece estar em baixo, ou então existe um problema com a sua ligação à Internet. Tentando novamente...",
"The aggregated statistics are publicly available at {%url%}.": "As estatísticas agrupadas estão disponíveis publicamente em {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "A configuração foi gravada mas não activada. O Syncthing tem que reiniciar para activar a nova configuração.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "O relatório de utilização cifrado é enviado diariamente. É utilizado para seguir plataformas comuns, tamanhos de repositórios e versões da aplicação. Se o conjunto de dados do relatório for alterado, será notificado novamente através desta janela.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "O ID do nó indicado não parece ser válido. Deveria conter uma palavra de 52 caracteres constituída por letras e números, com espaços e traços opcionais. ",
"The entered node 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.": "O ID do nó fornecido não parece ser válido. Deveria ser um texto com 52 ou 56 caracteres constituídos por letras e números, com espaços e traços opcionais.",
"The device ID cannot be blank.": "O ID do dispositivo não pode estar vazio.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "O ID do dispositivo a introduzir aqui pode ser encontrado no menu \"Editar > Mostrar ID\" do outro dispositivo. Espaços e hífenes são opcionais (ignorados).",
"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.": "O relatório de utilização cifrado é enviado diariamente. É utilizado para rastrear plataformas comuns, tamanhos de pastas e versões da aplicação. Se o tipo de dados do relatório for alterado, será notificado novamente através desta janela.",
"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.": "O ID do dispositivo fornecido não parece ser válido. Deveria ter 52 ou 56 caracteres constituídos por letras e números, com espaços e hífenes opcionais.",
"The folder ID cannot be blank.": "O ID da pasta não pode estar vazio.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "O ID da pasta tem que ser um identificador curto (64 caracteres ou menos) e ser constituído somente por letras, números e os caracteres ponto (.), hífen (-) e sublinhado (_).",
"The folder ID must be unique.": "O ID da pasta tem que ser único.",
"The folder path cannot be blank.": "O caminho da pasta não pode estar vazio.",
"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ão utilizados os seguintes intervalos: na primeira hora é guardada uma versão a cada 30 segundos, no primeiro dia é guardada uma versão a cada hora, nos primeiros 30 dias é guardada uma versão por dia e, até que atinja a idade máxima, é guardada uma versão por semana.",
"The maximum age must be a number and cannot be blank.": "A idade máxima tem que ser um número e não pode estar vazia.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Tempo máximo para manter uma versão (em dias, use 0 para manter a versão para sempre).",
"The node ID cannot be blank.": "O ID do nó não pode estar vazio.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "O ID do nó a introduzir pode ser encontrado no diálogo \"Editar > Mostrar ID\" no outro nó. Espaços e traços são opcionais (ignorados).",
"The number of old versions to keep, per file.": "O número de versões antigas a manter, por ficheiro.",
"The number of versions must be a number and cannot be blank.": "O número de versões tem que ser um número e não pode estar vazio.",
"The repository ID cannot be blank.": "O ID do repositório não pode estar vazio.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "O ID do repositório tem que ser um identificador curto (64 caracteres ou menos) e ser constituído somente por letras, números e os caracteres ponto (.), traço (-) e sublinhado (_).",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "O ID do repositório tem que ser um identificador curto (64 caracteres ou menos) e consiste em letras, números e os caracteres ponto (.), traço (-) e (_).",
"The repository ID must be unique.": "O ID do repositório tem que ser único.",
"The repository path cannot be blank.": "O caminho do repositório não pode estar vazio.",
"The rescan interval must be at least 5 seconds.": "O intervalo entre verificações tem que ser pelo menos de 5 segundos.",
"Unknown": "Desconhecido",
"Up to Date": "Actualizado",
"Upgrade To {%version%}": "Actualizar para {{version}}",
"Upgrading": "Actualizando",
"Upload Rate": "Velocidade de envio",
"Usage": "Utilização",
"Use Compression": "Usar compressão",
"Use HTTPS for GUI": "Utilizar HTTPS na interface gráfica",
"Version": "Versão",
"Versions Path": "Caminho das versões",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "As versões são eliminadas automaticamente se forem mais antigas do que a idade máxima ou excederem o número máximo de ficheiros permitido num intervalo.",
"When adding a new node, keep in mind that this node must be added on the other side too.": "Quando adicionar um novo , lembre-se que este tem que ser adicionado no outro lado também.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Quando adicionar um novo repositório, lembre-se que o ID do repositório é utilizado para juntar os repositórios entre nós. Os ID's são sensíveis às maiúsculas e minúsculas e têm que corresponder exactamente entre todos os s.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Quando adicionar um novo dispositivo, lembre-se que este dispositivo tem que ser adicionado do outro lado também.",
"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.": "Quando adicionar uma nova pasta, lembre-se que o ID da pasta é utilizado para ligar as pastas entre dispositivos. É sensível às diferenças entre maiúsculas e minúsculas e tem que ter uma correspondência perfeita entre todos os dispositivos.",
"Yes": "Sim",
"You must keep at least one version.": "Tem que manter pelo menos uma versão.",
"full documentation": "documentação completa",

View File

@@ -1,152 +0,0 @@
{
"API Key": "Ключ API",
"About": "О программе",
"Add Node": "Добавить Узел",
"Add Repository": "Добавить репозиторий",
"Address": "Адрес",
"Addresses": "Адреса",
"Allow Anonymous Usage Reporting?": "Разрешить сбор анонимной статистики использования?",
"Announce Server": "Сервер публикации",
"Anonymous Usage Reporting": "Анонимная статистика использования",
"Any nodes configured on an introducer node will be added to this node as well.": "Any nodes configured on an introducer node will be added to this node as well.",
"Bugs": "Ошибки",
"CPU Utilization": "Загрузка ЦПУ",
"Close": "Закрыть",
"Comment, when used at the start of a line": "Comment, when used at the start of a line",
"Compression is recommended in most setups.": "Compression is recommended in most setups.",
"Connection Error": "Ошибка подключения",
"Copyright © 2014 Jakob Borg and the following Contributors:": "Все права защищены © 2014 Jakob Borg и следующие участники:",
"Delete": "Удалить",
"Disconnected": "Нет соединения",
"Documentation": "Документация",
"Download Rate": "Скорость загрузки",
"Edit": "Изменить",
"Edit Node": "Изменить Узел",
"Edit Repository": "Изменить Репозиторий",
"Editing": "Editing",
"Enable UPnP": "Включить UPnP",
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": " Введите пары \"IP:PORT\" разделённые запятыми, или слово \"dynamic\" для автоматического обнаружения адреса.",
"Enter ignore patterns, one per line.": "Enter ignore patterns, one per line.",
"Error": "Ошибка",
"File Versioning": "Управление версиями",
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Права доступа к файлам будут игнорироваться. Используйте на файловых системах типа FAT.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Версии файлов с временнОй меткой перемещаются в директорию .stversions, если они удалены или перемещены в процессе синхронизации.",
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Файлы защищены от изменений сторонними узлами, но изменения внесённые текущим узлом будут синхронизированы со всем кластером.",
"Folder": "Папка",
"GUI Authentication Password": "Пароль для доступа к панели управления",
"GUI Authentication User": "Имя пользователя для доступа к панели управления",
"GUI Listen Addresses": "Адрес панели управления",
"Generate": "Сгенерировать",
"Global Discovery": "Глобальное обнаружение",
"Global Discovery Server": "Сервер глобального обнаружения",
"Global Repository": "Глобальный репозиторий",
"Idle": "Бездействует",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Игнорировать файловые права доступа",
"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": "Количество хранимых версий",
"Last seen": "Был доступен",
"Latest Release": "Последняя версия",
"Local Discovery": "Локальное обнаружение",
"Local Discovery Port": "Порт локального обнаружения",
"Local Repository": "Локальный репозиторий",
"Master Repo": "Главный репозиторий",
"Max File Change Rate (KiB/s)": "Максимальная скорость изменения файлов (KiB/s)",
"Max Outstanding Requests": "Максимальное количество исходящих запросов",
"Maximum Age": "Максимальный срок",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Никогда",
"No": "Нет",
"No File Versioning": "Без управления версиями файлов",
"Node ID": "ID Узла",
"Node Identification": "Идентификация узла",
"Node Name": "Имя Узла",
"Notice": "Внимание",
"OK": "ОК",
"Offline": "Оффлайн",
"Online": "Онлайн",
"Out Of Sync": "Не синхронизировано",
"Outgoing Rate Limit (KiB/s)": "Предел скорости отдачи (KiB/s)",
"Override Changes": "Перезаписать изменения",
"Path to the repository 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 folder in the repository).": "Путь, куда нужно сохранять версии (оставьте пустым для папки .stversions в репозитории).",
"Please wait": "Пожалуйста, подождите",
"Preview": "Предварительный просмотр",
"Preview Usage Report": "Посмотреть отчёт об использовании",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "Использование ОЗУ",
"Reconnect Interval (s)": "Интервал переподключений (секунды)",
"Repository ID": "ID Репозитория",
"Repository Master": "Главный Репозиторий",
"Repository Path": "Путь к Репозиторию",
"Rescan": "Пересканирование",
"Rescan Interval": "Интервал пересканирования",
"Rescan Interval (s)": "Интервал между сканированием (сек)",
"Restart": "Перезапуск",
"Restart Needed": "Требуется перезапуск",
"Restarting": "Перезапуск",
"Save": "Сохранить",
"Scanning": "Сканирование",
"Select the nodes to share this repository with.": "Выберите узлы для которых будет доступен данный репозиторий.",
"Settings": "Настройки",
"Share With Nodes": "Предоставить доступ узлам",
"Shared With": "Доступ предоставлен",
"Short identifier for the repository. Must be the same on all cluster nodes.": "Короткий идентификатор репозитория. Должен быть одинаковый на всех узлах кластера.",
"Show ID": "Показать ID",
"Shown instead of Node ID in the cluster status.": "Отображается вместо ID узла в статусе кластера.",
"Shown instead of Node ID in the cluster status. Will be advertised to other nodes as an optional default name.": "Показано вместо идентификатора узла в статусе кластера. Будет разглашено другим узлам в качестве дополнительного имени по умолчанию.",
"Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.": "Показано вместо идентификатора узла в статусе кластера. Будет обновлено именем, разглашённым узлом, если оставлено пустым.",
"Shutdown": "Выключить",
"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": "Открыть браузер",
"Stopped": "Остановлено",
"Support / Forum": "Поддержка / Форум",
"Sync Protocol Listen Addresses": "Адрес протокола синхронизации",
"Synchronization": "Синхронизация",
"Syncing": "Синхронизация",
"Syncthing has been shut down.": "Syncthing выключен.",
"Syncthing includes the following software or portions thereof:": "Syncthing включает в себя следующее ПО или его части:",
"Syncthing is restarting.": "Перезапуск Syncthing",
"Syncthing is upgrading.": "Обновление Syncthing ",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Кажется, Syncthing не запущен или есть проблемы с подключением к Интернету. Переподключаюсь...",
"The aggregated statistics are publicly available at {%url%}.": "Суммарная статистика общедоступна на {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Конфигурация была сохранена но не активирована. Для активации новой конфигурации необходимо рестартовать Syncthing.",
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Зашифрованные отчёты об использовании отправляются ежедневно. Они используются для отслеживания проблем, размеров репозиториев и версий Syncthing. Если набор данных в отчёте будет изменён, то вы получите уведомление об этом в этом диалоге.",
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Введённый ID узла выглядит неправильно: ID должен быть строкой, длинной 52 символа, обязательно содержащей группы букв и цифр которые могут быть разделены пробелами или тире.",
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Введённый ID узла выглядит неправильно: ID должен быть строкой, длинной 52 или 56 символов, обязательно содержащей группы букв и цифр которые могут быть разделены пробелами или тире.",
"The 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 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 node ID cannot be blank.": "ID узла не может быть пустым.",
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "ID узла можно узнать в окне \"Редактировать > Показать ID\" на требуемом узле. Пробелы и тире используются для удобства и не обязательны (игнорируются).",
"The number of old versions to keep, per file.": "Количество хранимых версий файла.",
"The number of versions must be a number and cannot be blank.": "Количество версий должно быть числом и не может быть пустым.",
"The repository ID cannot be blank.": "ID Репозитория не может быть пустым.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.",
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "ID репозитория должен быть коротким id (64 символа или меньше) состоящий только из букв, цифр, точек (.), тире (-) и нижнего подчёркивания (_).",
"The repository ID must be unique.": "ID Репозитория должен быть уникальным.",
"The repository path cannot be blank.": "Путь к репозиторию не может быть пустым.",
"The rescan interval must be at least 5 seconds.": "Интервал пересканирования должен быть хотя бы 5 секунд.",
"Unknown": "Неизвестно",
"Up to Date": "Обновлено",
"Upgrade To {%version%}": "Обновить до {{version}}",
"Upgrading": "Обновление",
"Upload Rate": "Скорость отдачи",
"Usage": "Справка",
"Use Compression": "Использовать сжатие",
"Use HTTPS for GUI": "Использовать HTTPS для панели управления",
"Version": "Версия",
"Versions Path": "Путь к версиям",
"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 node, keep in mind that this node must be added on the other side too.": "Добавляя новый узел помните, что новый узел должен быть добавлен и на другой стороне.",
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Добавляя новый репозиторий помните, что ID репозитория используется для связи всех репозиториев между узлами. ID чувствительны к регистру и должны совпадать на всех узлах.",
"Yes": "Да",
"You must keep at least one version.": "Вы должны хранить как минимум одну версию.",
"full documentation": "full documentation",
"items": "элементы"
}

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