moat-kv 0.71.12__tar.gz → 0.71.14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. {moat_kv-0.71.12 → moat_kv-0.71.14}/PKG-INFO +1 -1
  2. {moat_kv-0.71.12 → moat_kv-0.71.14}/debian/changelog +12 -0
  3. {moat_kv-0.71.12 → moat_kv-0.71.14}/pyproject.toml +1 -1
  4. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/acl.py +1 -1
  5. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/data.py +3 -3
  6. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/job.py +2 -1
  7. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/data.py +33 -16
  8. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/mock/mqtt.py +0 -1
  9. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/model.py +22 -8
  10. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/server.py +7 -2
  11. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat_kv.egg-info/PKG-INFO +1 -1
  12. {moat_kv-0.71.12 → moat_kv-0.71.14}/LICENSE +0 -0
  13. {moat_kv-0.71.12 → moat_kv-0.71.14}/LICENSE.APACHE2 +0 -0
  14. {moat_kv-0.71.12 → moat_kv-0.71.14}/LICENSE.MIT +0 -0
  15. {moat_kv-0.71.12 → moat_kv-0.71.14}/LICENSE.txt +0 -0
  16. {moat_kv-0.71.12 → moat_kv-0.71.14}/MANIFEST.in +0 -0
  17. {moat_kv-0.71.12 → moat_kv-0.71.14}/Makefile +0 -0
  18. {moat_kv-0.71.12 → moat_kv-0.71.14}/README.rst +0 -0
  19. {moat_kv-0.71.12 → moat_kv-0.71.14}/ci/rtd-requirements.txt +0 -0
  20. {moat_kv-0.71.12 → moat_kv-0.71.14}/ci/test-requirements.txt +0 -0
  21. {moat_kv-0.71.12 → moat_kv-0.71.14}/ci/travis.sh +0 -0
  22. {moat_kv-0.71.12 → moat_kv-0.71.14}/debian/.gitignore +0 -0
  23. {moat_kv-0.71.12 → moat_kv-0.71.14}/debian/control +0 -0
  24. {moat_kv-0.71.12 → moat_kv-0.71.14}/debian/moat-kv.postinst +0 -0
  25. {moat_kv-0.71.12 → moat_kv-0.71.14}/debian/rules +0 -0
  26. {moat_kv-0.71.12 → moat_kv-0.71.14}/debian/source/format +0 -0
  27. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/Makefile +0 -0
  28. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/make.bat +0 -0
  29. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/TODO.rst +0 -0
  30. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/_static/.gitkeep +0 -0
  31. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/acls.rst +0 -0
  32. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/auth.rst +0 -0
  33. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/client_protocol.rst +0 -0
  34. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/code.rst +0 -0
  35. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/command_line.rst +0 -0
  36. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/common_protocol.rst +0 -0
  37. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/conf.py +0 -0
  38. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/debugging.rst +0 -0
  39. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/extend.rst +0 -0
  40. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/history.rst +0 -0
  41. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/index.rst +0 -0
  42. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/model.rst +0 -0
  43. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/overview.rst +0 -0
  44. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/related.rst +0 -0
  45. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/server_protocol.rst +0 -0
  46. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/startup.rst +0 -0
  47. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/translator.rst +0 -0
  48. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/tutorial.rst +0 -0
  49. {moat_kv-0.71.12 → moat_kv-0.71.14}/docs/source/v3.rst +0 -0
  50. {moat_kv-0.71.12 → moat_kv-0.71.14}/examples/code/transform.scale.yml +0 -0
  51. {moat_kv-0.71.12 → moat_kv-0.71.14}/examples/code/transform.switch.yml +0 -0
  52. {moat_kv-0.71.12 → moat_kv-0.71.14}/examples/code/transform.timeslot.yml +0 -0
  53. {moat_kv-0.71.12 → moat_kv-0.71.14}/examples/pathify.py +0 -0
  54. {moat_kv-0.71.12 → moat_kv-0.71.14}/mktag +0 -0
  55. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/current +0 -0
  56. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/env +0 -0
  57. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/init +0 -0
  58. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/recover +0 -0
  59. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/rotate +0 -0
  60. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/run +0 -0
  61. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/run-all +0 -0
  62. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/run-any +0 -0
  63. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/run-single +0 -0
  64. {moat_kv-0.71.12 → moat_kv-0.71.14}/scripts/success +0 -0
  65. {moat_kv-0.71.12 → moat_kv-0.71.14}/setup.cfg +0 -0
  66. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/__init__.py +0 -0
  67. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/_cfg.yaml +0 -0
  68. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/_main.py +0 -0
  69. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/actor/__init__.py +0 -0
  70. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/actor/deletor.py +0 -0
  71. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/auth/__init__.py +0 -0
  72. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/auth/_test.py +0 -0
  73. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/auth/password.py +0 -0
  74. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/auth/root.py +0 -0
  75. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/backend/__init__.py +0 -0
  76. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/backend/mqtt.py +0 -0
  77. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/client.py +0 -0
  78. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/code.py +0 -0
  79. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/__init__.py +0 -0
  80. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/auth.py +0 -0
  81. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/code.py +0 -0
  82. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/codec.py +0 -0
  83. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/dump/__init__.py +0 -0
  84. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/error.py +0 -0
  85. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/internal.py +0 -0
  86. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/log.py +0 -0
  87. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/server.py +0 -0
  88. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/command/type.py +0 -0
  89. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/config.py +0 -0
  90. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/errors.py +0 -0
  91. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/exceptions.py +0 -0
  92. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/mock/__init__.py +0 -0
  93. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/mock/tracer.py +0 -0
  94. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/obj/__init__.py +0 -0
  95. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/obj/command.py +0 -0
  96. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/runner.py +0 -0
  97. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat/kv/types.py +0 -0
  98. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat_kv.egg-info/SOURCES.txt +0 -0
  99. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat_kv.egg-info/dependency_links.txt +0 -0
  100. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat_kv.egg-info/requires.txt +0 -0
  101. {moat_kv-0.71.12 → moat_kv-0.71.14}/src/moat_kv.egg-info/top_level.txt +0 -0
  102. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-recover.service +0 -0
  103. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-rotate.service +0 -0
  104. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-rotate.timer +0 -0
  105. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-run-all.service +0 -0
  106. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-run-all@.service +0 -0
  107. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-run-any.service +0 -0
  108. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-run-any@.service +0 -0
  109. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-run-single.service +0 -0
  110. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv-run-single@.service +0 -0
  111. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/moat-kv.service +0 -0
  112. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/postinst +0 -0
  113. {moat_kv-0.71.12 → moat_kv-0.71.14}/systemd/sysusers +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moat-kv
3
- Version: 0.71.12
3
+ Version: 0.71.14
4
4
  Summary: A distributed no-master key-value store
5
5
  Author-email: Matthias Urlichs <matthias@urlichs.de>
6
6
  Project-URL: homepage, https://m-o-a-t.org
@@ -1,3 +1,15 @@
1
+ moat-kv (0.71.14-1) unstable; urgency=medium
2
+
3
+ * New release for 25.3.3
4
+
5
+ -- Matthias Urlichs <matthias@urlichs.de> Tue, 22 Jul 2025 11:50:00 +0200
6
+
7
+ moat-kv (0.71.13-1) unstable; urgency=medium
8
+
9
+ * New release for 25.3.3
10
+
11
+ -- Matthias Urlichs <matthias@urlichs.de> Tue, 22 Jul 2025 09:29:57 +0200
12
+
1
13
  moat-kv (0.71.12-1) unstable; urgency=medium
2
14
 
3
15
  * New release for 25.3.3
@@ -36,7 +36,7 @@ dependencies = [
36
36
  "moat-util ~= 0.56.4",
37
37
  "exceptiongroup; python_version<'3.11'",
38
38
  ]
39
- version = "0.71.12"
39
+ version = "0.71.14"
40
40
  keywords = [ "MoaT",]
41
41
  requires-python = ">=3.8"
42
42
  name = "moat-kv"
@@ -46,7 +46,7 @@ async def list_(obj):
46
46
  async def dump(obj, name, path, as_dict):
47
47
  """Dump a complete (or partial) ACL."""
48
48
  path = P(path)
49
- await data_get(obj, Path("acl", name, path), internal=True, as_dict=as_dict)
49
+ await data_get(obj.client, Path("acl", name, path), internal=True, as_dict=as_dict, out=obj.stdout)
50
50
 
51
51
 
52
52
  @cli.command()
@@ -20,7 +20,7 @@ async def cli(ctx, path):
20
20
  This subcommand accesses the actual user data stored in your MoaT-KV tree.
21
21
  """
22
22
  if ctx.invoked_subcommand is None:
23
- await data_get(ctx.obj, path, recursive=False)
23
+ await data_get(ctx.obj.client, path, recursive=False, out=ctx.obj.stdout)
24
24
  else:
25
25
  ctx.obj.path = path
26
26
 
@@ -61,7 +61,7 @@ async def get(obj, **k):
61
61
  for incremental output.
62
62
  """
63
63
 
64
- await data_get(obj, obj.path, **k)
64
+ await data_get(obj.client, obj.path, out=obj.stdout, **k)
65
65
 
66
66
 
67
67
  @cli.command("list")
@@ -101,7 +101,7 @@ async def list_(obj, **k):
101
101
  k["recursive"] = True
102
102
  k["raw"] = True
103
103
  k["empty"] = True
104
- await data_get(obj, obj.path, **k)
104
+ await data_get(obj.client, obj.path, out=obj.stdout, **k)
105
105
 
106
106
 
107
107
  @cli.command("set", short_help="Add or update an entry")
@@ -237,10 +237,11 @@ async def list_(obj, state, state_only, table, as_dict):
237
237
 
238
238
  else:
239
239
  await data_get(
240
- obj,
240
+ obj.client,
241
241
  obj.path + path,
242
242
  as_dict=as_dict,
243
243
  item_mangle=partial(_state_fix, obj, state, state_only, None if as_dict else path),
244
+ out=obj.stdout,
244
245
  )
245
246
 
246
247
 
@@ -45,9 +45,10 @@ def add_dates(d):
45
45
 
46
46
 
47
47
  async def data_get(
48
- obj,
48
+ conn,
49
49
  path,
50
50
  *,
51
+ meta=False,
51
52
  recursive=True,
52
53
  as_dict="_",
53
54
  maxdepth=-1,
@@ -58,6 +59,7 @@ async def data_get(
58
59
  path_mangle=None,
59
60
  item_mangle=None,
60
61
  add_date=False,
62
+ out=None,
61
63
  ):
62
64
  """Generic code to dump a subtree.
63
65
 
@@ -75,6 +77,11 @@ async def data_get(
75
77
  async def item_mangle(x): # pylint: disable=function-redefined
76
78
  return x
77
79
 
80
+ if out is None:
81
+ out = sys.stdout
82
+ elif out is False:
83
+ out = []
84
+
78
85
  if recursive:
79
86
  kw = {}
80
87
  if maxdepth is not None and maxdepth >= 0:
@@ -83,13 +90,13 @@ async def data_get(
83
90
  kw["min_depth"] = mindepth
84
91
  if empty:
85
92
  kw["empty"] = True
86
- if obj.meta:
87
- kw.setdefault("nchain", obj.meta)
93
+ if meta:
94
+ kw.setdefault("nchain", meta)
88
95
  y = {}
89
96
  if internal:
90
- res = await obj.client._request(action="get_tree_internal", path=path, iter=True, **kw)
97
+ res = await conn._request(action="get_tree_internal", path=path, iter=True, **kw)
91
98
  else:
92
- res = obj.client.get_tree(path, **kw)
99
+ res = conn.get_tree(path, **kw)
93
100
  async for r in res:
94
101
  r = await item_mangle(r)
95
102
  if r is None:
@@ -107,7 +114,7 @@ async def data_get(
107
114
  for p in path:
108
115
  yy = yy.setdefault(p, {})
109
116
  try:
110
- yy[as_dict] = r if obj.meta else r.value
117
+ yy[as_dict] = r if meta else r.value
111
118
  except AttributeError:
112
119
  if empty:
113
120
  yy[as_dict] = None
@@ -117,13 +124,17 @@ async def data_get(
117
124
  else:
118
125
  y = {}
119
126
  try:
120
- y[path] = r if obj.meta else r.value
127
+ y[path] = r if meta else r.value
121
128
  except AttributeError:
122
129
  if empty:
123
130
  y[path] = None
124
131
  else:
125
132
  continue
126
- yprint([y], stream=obj.stdout)
133
+
134
+ if isinstance(out,list):
135
+ out.append(y)
136
+ else:
137
+ yprint([y], stream=out)
127
138
 
128
139
  if as_dict is not None:
129
140
  if maxdepth:
@@ -140,24 +151,30 @@ async def data_get(
140
151
  return d
141
152
 
142
153
  y = simplex(y)
143
- yprint(y, stream=obj.stdout)
154
+ if isinstance(out,list):
155
+ return y
156
+ yprint(y, stream=out)
144
157
  return # end "if recursive"
145
158
 
146
- res = await obj.client.get(path, nchain=obj.meta)
147
- if not obj.meta:
159
+ res = await conn.get(path, nchain=meta)
160
+ if add_date and "value" in res:
161
+ add_dates(res.value)
162
+ if not meta:
148
163
  try:
149
164
  res = res.value
150
165
  except AttributeError:
151
- if obj.debug:
152
- print("No data at", path, file=sys.stderr)
166
+ # if obj.debug:
167
+ # print("No data at", path, file=sys.stderr)
153
168
  return
154
169
 
170
+ if out is False:
171
+ return d
155
172
  if not raw:
156
- yprint(res, stream=obj.stdout)
173
+ yprint(res, stream=out)
157
174
  elif isinstance(res, bytes):
158
- os.write(obj.stdout.fileno(), res)
175
+ os.write(out.fileno(), res)
159
176
  else:
160
- obj.stdout.write(str(res))
177
+ out.write(str(res))
161
178
  pass # end get
162
179
 
163
180
 
@@ -42,7 +42,6 @@ async def stdtest(n=1, run=True, ssl=False, tocks=20, **kw):
42
42
  TESTCFG.server.port = None
43
43
  TESTCFG.root = "test"
44
44
  if C_OUT is not NotGiven:
45
- CFG["_stdout"] = C_OUT
46
45
  TESTCFG["_stdout"] = C_OUT
47
46
 
48
47
  if ssl:
@@ -503,6 +503,18 @@ class NodeEvent:
503
503
  res.prev = self.prev.serialize(nchain - 1)
504
504
  return res
505
505
 
506
+ def serialize_link(self, nchain=-1) -> dict:
507
+ "Serialization for gatewaying to moat-link"
508
+ if not nchain:
509
+ raise RuntimeError("A chopped-off NodeEvent must not be sent")
510
+ res = []
511
+ s = self
512
+ while s is not None and nchain != 0:
513
+ res.extend((self.node.name, self.tick))
514
+ s = s.prev
515
+ nchain -= 1
516
+ return res
517
+
506
518
  @classmethod
507
519
  def deserialize(cls, msg, cache):
508
520
  if msg is None:
@@ -518,6 +530,16 @@ class NodeEvent:
518
530
  self.prev = cls.deserialize(msg["prev"], cache=cache)
519
531
  return self
520
532
 
533
+ @classmethod
534
+ def deserialize_link(cls, msg, cache):
535
+ "Deserialization for gatewaying to moat-link"
536
+ if not msg:
537
+ return None
538
+ node,tick,*msg = msg
539
+ self = cls(node=Node(node, tick=tick, cache=cache), tick=tick)
540
+ self.prev = cls.deserialize_link(msg, cache=cache)
541
+ return self
542
+
521
543
  def attach(self, prev: NodeEvent = None, server=None):
522
544
  """Copy this node, if necessary, and attach a filtered `prev` chain to it"""
523
545
  if prev is not None:
@@ -702,10 +724,6 @@ class Entry:
702
724
 
703
725
  first = True
704
726
  for name in path:
705
- if name is None and not nulls_ok:
706
- raise ValueError("Null path element")
707
- if nulls_ok == 1: # root only
708
- nulls_ok = False
709
727
  child = self._sub.get(name, None) if self is not None else None
710
728
  if child is None:
711
729
  if create is False:
@@ -738,10 +756,6 @@ class Entry:
738
756
  # KEEP IN SYNC with `follow_acl`, above!
739
757
 
740
758
  for name in path:
741
- if name is None and not nulls_ok:
742
- raise ValueError("Null path element")
743
- if nulls_ok == 1: # root only
744
- nulls_ok = False
745
759
  child = self._sub.get(name, None) if self is not None else None
746
760
  if child is None:
747
761
  if create is False:
@@ -650,6 +650,11 @@ class SCmd_msg_monitor(StreamCommand):
650
650
  try:
651
651
  res["data"] = codec.decode(resp.payload)
652
652
  except Exception as exc:
653
+ self.client.server.logger.exception(
654
+ "ERR %d: Client error on %s",
655
+ self.client._client_nr,
656
+ repr(exc),
657
+ )
653
658
  res["raw"] = resp.payload
654
659
  res["error"] = repr(exc)
655
660
 
@@ -1246,8 +1251,8 @@ class ServerClient:
1246
1251
  msg = {"error": str(exc)}
1247
1252
  if isinstance(exc, ClientError): # pylint doesn't seem to see this, so …:
1248
1253
  msg["etype"] = exc.etype # pylint: disable=no-member ### YES IT HAS
1249
- else:
1250
- self.logger.exception(
1254
+ #else:
1255
+ self.logger.exception(
1251
1256
  "ERR %d: Client error on %s",
1252
1257
  self._client_nr,
1253
1258
  repr(msg),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moat-kv
3
- Version: 0.71.12
3
+ Version: 0.71.14
4
4
  Summary: A distributed no-master key-value store
5
5
  Author-email: Matthias Urlichs <matthias@urlichs.de>
6
6
  Project-URL: homepage, https://m-o-a-t.org
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes