python-arango 7.7.0__tar.gz → 7.8.1__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.
- {python-arango-7.7.0 → python-arango-7.8.1}/PKG-INFO +1 -1
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/client.py +21 -1
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/connection.py +78 -20
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/exceptions.py +8 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/graph.py +2 -2
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/utils.py +1 -1
- python-arango-7.8.1/arango/version.py +16 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/auth.rst +27 -1
- {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/PKG-INFO +1 -1
- python-arango-7.7.0/arango/version.py +0 -8
- {python-arango-7.7.0 → python-arango-7.8.1}/.github/workflows/build.yaml +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/.github/workflows/codeql.yaml +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/.github/workflows/pypi.yaml +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/.gitignore +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/.pre-commit-config.yaml +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/.readthedocs.yaml +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/CONTRIBUTING.md +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/LICENSE +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/MANIFEST.in +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/README.md +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/__init__.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/api.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/aql.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/backup.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/cluster.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/collection.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/cursor.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/database.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/errno.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/executor.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/formatter.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/foxx.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/http.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/job.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/pregel.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/py.typed +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/replication.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/request.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/resolver.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/response.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/result.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/typings.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/arango/wal.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/Makefile +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/admin.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/analyzer.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/aql.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/async.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/backup.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/batch.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/certificates.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/cluster.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/collection.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/conf.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/contributing.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/cursor.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/database.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/document.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/errno.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/errors.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/foxx.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/graph.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/http.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/index.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/indexes.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/logging.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/make.bat +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/overload.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/overview.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/pregel.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/replication.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/requirements.txt +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/schema.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/serializer.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/simple.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/specs.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/static/logo.png +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/task.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/threading.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/transaction.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/user.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/view.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/docs/wal.rst +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/pyproject.toml +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/SOURCES.txt +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/dependency_links.txt +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/requires.txt +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/top_level.txt +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/setup.cfg +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/setup.py +0 -0
- {python-arango-7.7.0 → python-arango-7.8.1}/tester.sh +0 -0
|
@@ -171,6 +171,7 @@ class ArangoClient:
|
|
|
171
171
|
password: str = "",
|
|
172
172
|
verify: bool = False,
|
|
173
173
|
auth_method: str = "basic",
|
|
174
|
+
user_token: Optional[str] = None,
|
|
174
175
|
superuser_token: Optional[str] = None,
|
|
175
176
|
verify_certificate: bool = True,
|
|
176
177
|
) -> StandardDatabase:
|
|
@@ -189,9 +190,17 @@ class ArangoClient:
|
|
|
189
190
|
refreshed automatically using ArangoDB username and password. This
|
|
190
191
|
assumes that the clocks of the server and client are synchronized.
|
|
191
192
|
:type auth_method: str
|
|
193
|
+
:param user_token: User generated token for user access.
|
|
194
|
+
If set, parameters **username**, **password** and **auth_method**
|
|
195
|
+
are ignored. This token is not refreshed automatically. If automatic
|
|
196
|
+
token refresh is required, consider setting **auth_method** to "jwt"
|
|
197
|
+
and using the **username** and **password** parameters instead. Token
|
|
198
|
+
expiry will be checked.
|
|
199
|
+
:type user_token: str
|
|
192
200
|
:param superuser_token: User generated token for superuser access.
|
|
193
201
|
If set, parameters **username**, **password** and **auth_method**
|
|
194
|
-
are ignored. This token is not refreshed automatically.
|
|
202
|
+
are ignored. This token is not refreshed automatically. Token
|
|
203
|
+
expiry will not be checked.
|
|
195
204
|
:type superuser_token: str
|
|
196
205
|
:param verify_certificate: Verify TLS certificates.
|
|
197
206
|
:type verify_certificate: bool
|
|
@@ -213,6 +222,17 @@ class ArangoClient:
|
|
|
213
222
|
deserializer=self._deserializer,
|
|
214
223
|
superuser_token=superuser_token,
|
|
215
224
|
)
|
|
225
|
+
elif user_token is not None:
|
|
226
|
+
connection = JwtConnection(
|
|
227
|
+
hosts=self._hosts,
|
|
228
|
+
host_resolver=self._host_resolver,
|
|
229
|
+
sessions=self._sessions,
|
|
230
|
+
db_name=name,
|
|
231
|
+
http_client=self._http,
|
|
232
|
+
serializer=self._serializer,
|
|
233
|
+
deserializer=self._deserializer,
|
|
234
|
+
user_token=user_token,
|
|
235
|
+
)
|
|
216
236
|
elif auth_method.lower() == "basic":
|
|
217
237
|
connection = BasicConnection(
|
|
218
238
|
hosts=self._hosts,
|
|
@@ -13,10 +13,16 @@ from abc import abstractmethod
|
|
|
13
13
|
from typing import Any, Callable, Optional, Sequence, Set, Tuple, Union
|
|
14
14
|
|
|
15
15
|
import jwt
|
|
16
|
+
from jwt.exceptions import ExpiredSignatureError
|
|
16
17
|
from requests import ConnectionError, Session
|
|
17
18
|
from requests_toolbelt import MultipartEncoder
|
|
18
19
|
|
|
19
|
-
from arango.exceptions import
|
|
20
|
+
from arango.exceptions import (
|
|
21
|
+
JWTAuthError,
|
|
22
|
+
JWTExpiredError,
|
|
23
|
+
JWTRefreshError,
|
|
24
|
+
ServerConnectionError,
|
|
25
|
+
)
|
|
20
26
|
from arango.http import HTTPClient
|
|
21
27
|
from arango.request import Request
|
|
22
28
|
from arango.resolver import HostResolver
|
|
@@ -203,7 +209,7 @@ class BaseConnection:
|
|
|
203
209
|
request = Request(method="get", endpoint="/_api/collection")
|
|
204
210
|
resp = self.send_request(request)
|
|
205
211
|
if resp.status_code in {401, 403}:
|
|
206
|
-
raise ServerConnectionError("bad username
|
|
212
|
+
raise ServerConnectionError("bad username/password or token is expired")
|
|
207
213
|
if not resp.is_success: # pragma: no cover
|
|
208
214
|
raise ServerConnectionError(resp.error_message or "bad server response")
|
|
209
215
|
return resp.status_code
|
|
@@ -300,11 +306,12 @@ class JwtConnection(BaseConnection):
|
|
|
300
306
|
host_resolver: HostResolver,
|
|
301
307
|
sessions: Sequence[Session],
|
|
302
308
|
db_name: str,
|
|
303
|
-
username: str,
|
|
304
|
-
password: str,
|
|
305
309
|
http_client: HTTPClient,
|
|
306
310
|
serializer: Callable[..., str],
|
|
307
311
|
deserializer: Callable[[str], Any],
|
|
312
|
+
username: Optional[str] = None,
|
|
313
|
+
password: Optional[str] = None,
|
|
314
|
+
user_token: Optional[str] = None,
|
|
308
315
|
) -> None:
|
|
309
316
|
super().__init__(
|
|
310
317
|
hosts,
|
|
@@ -323,7 +330,13 @@ class JwtConnection(BaseConnection):
|
|
|
323
330
|
self._token: Optional[str] = None
|
|
324
331
|
self._token_exp: int = sys.maxsize
|
|
325
332
|
|
|
326
|
-
|
|
333
|
+
if user_token is not None:
|
|
334
|
+
self.set_token(user_token)
|
|
335
|
+
elif username is not None and password is not None:
|
|
336
|
+
self.refresh_token()
|
|
337
|
+
else:
|
|
338
|
+
m = "Either **user_token** or **username** & **password** must be set"
|
|
339
|
+
raise ValueError(m)
|
|
327
340
|
|
|
328
341
|
def send_request(self, request: Request) -> Response:
|
|
329
342
|
"""Send an HTTP request to ArangoDB server.
|
|
@@ -360,7 +373,12 @@ class JwtConnection(BaseConnection):
|
|
|
360
373
|
|
|
361
374
|
:return: JWT token.
|
|
362
375
|
:rtype: str
|
|
376
|
+
:raise arango.exceptions.JWTRefreshError: If missing username & password.
|
|
377
|
+
:raise arango.exceptions.JWTAuthError: If token retrieval fails.
|
|
363
378
|
"""
|
|
379
|
+
if self._username is None or self._password is None:
|
|
380
|
+
raise JWTRefreshError("username and password must be set")
|
|
381
|
+
|
|
364
382
|
request = Request(
|
|
365
383
|
method="post",
|
|
366
384
|
endpoint="/_open/auth",
|
|
@@ -374,21 +392,34 @@ class JwtConnection(BaseConnection):
|
|
|
374
392
|
if not resp.is_success:
|
|
375
393
|
raise JWTAuthError(resp, request)
|
|
376
394
|
|
|
377
|
-
self.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
395
|
+
self.set_token(resp.body["jwt"])
|
|
396
|
+
|
|
397
|
+
def set_token(self, token: str) -> None:
|
|
398
|
+
"""Set the JWT token.
|
|
399
|
+
|
|
400
|
+
:param token: JWT token.
|
|
401
|
+
:type token: str
|
|
402
|
+
:raise arango.exceptions.JWTExpiredError: If the token is expired.
|
|
403
|
+
"""
|
|
404
|
+
assert token is not None
|
|
405
|
+
|
|
406
|
+
try:
|
|
407
|
+
jwt_payload = jwt.decode(
|
|
408
|
+
token,
|
|
409
|
+
issuer="arangodb",
|
|
410
|
+
algorithms=["HS256"],
|
|
411
|
+
options={
|
|
412
|
+
"require_exp": True,
|
|
413
|
+
"require_iat": True,
|
|
414
|
+
"verify_iat": True,
|
|
415
|
+
"verify_exp": True,
|
|
416
|
+
"verify_signature": False,
|
|
417
|
+
},
|
|
418
|
+
)
|
|
419
|
+
except ExpiredSignatureError:
|
|
420
|
+
raise JWTExpiredError("JWT token is expired")
|
|
421
|
+
|
|
422
|
+
self._token = token
|
|
392
423
|
self._token_exp = jwt_payload["exp"]
|
|
393
424
|
self._auth_header = f"bearer {self._token}"
|
|
394
425
|
|
|
@@ -444,3 +475,30 @@ class JwtSuperuserConnection(BaseConnection):
|
|
|
444
475
|
request.headers["Authorization"] = self._auth_header
|
|
445
476
|
|
|
446
477
|
return self.process_request(host_index, request)
|
|
478
|
+
|
|
479
|
+
def set_token(self, token: str) -> None:
|
|
480
|
+
"""Set the JWT token.
|
|
481
|
+
|
|
482
|
+
:param token: JWT token.
|
|
483
|
+
:type token: str
|
|
484
|
+
:raise arango.exceptions.JWTExpiredError: If the token is expired.
|
|
485
|
+
"""
|
|
486
|
+
assert token is not None
|
|
487
|
+
|
|
488
|
+
try:
|
|
489
|
+
jwt.decode(
|
|
490
|
+
token,
|
|
491
|
+
issuer="arangodb",
|
|
492
|
+
algorithms=["HS256"],
|
|
493
|
+
options={
|
|
494
|
+
"require_exp": True,
|
|
495
|
+
"require_iat": True,
|
|
496
|
+
"verify_iat": True,
|
|
497
|
+
"verify_exp": True,
|
|
498
|
+
"verify_signature": False,
|
|
499
|
+
},
|
|
500
|
+
)
|
|
501
|
+
except ExpiredSignatureError:
|
|
502
|
+
raise JWTExpiredError("JWT token is expired")
|
|
503
|
+
|
|
504
|
+
self._auth_header = f"bearer {token}"
|
|
@@ -1014,3 +1014,11 @@ class JWTSecretListError(ArangoServerError):
|
|
|
1014
1014
|
|
|
1015
1015
|
class JWTSecretReloadError(ArangoServerError):
|
|
1016
1016
|
"""Failed to reload JWT secrets."""
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
class JWTRefreshError(ArangoClientError):
|
|
1020
|
+
"""Failed to refresh JWT token."""
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
class JWTExpiredError(ArangoClientError):
|
|
1024
|
+
"""JWT token has expired."""
|
|
@@ -107,9 +107,9 @@ class Graph(ApiGroup):
|
|
|
107
107
|
return self._execute(request, response_handler)
|
|
108
108
|
|
|
109
109
|
def vertex_collections(self) -> Result[List[str]]:
|
|
110
|
-
"""Return vertex collections in the graph
|
|
110
|
+
"""Return vertex collections in the graph.
|
|
111
111
|
|
|
112
|
-
:return: Names of vertex collections
|
|
112
|
+
:return: Names of vertex collections in Edge Definitions and Orphan Collections.
|
|
113
113
|
:rtype: [str]
|
|
114
114
|
:raise arango.exceptions.VertexCollectionListError: If retrieval fails.
|
|
115
115
|
"""
|
|
@@ -120,5 +120,5 @@ def build_filter_conditions(filters: Json) -> str:
|
|
|
120
120
|
if not filters:
|
|
121
121
|
return ""
|
|
122
122
|
|
|
123
|
-
conditions = [f"doc
|
|
123
|
+
conditions = [f"doc.`{k}` == {json.dumps(v)}" for k, v in filters.items()]
|
|
124
124
|
return "FILTER " + " AND ".join(conditions)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# file generated by setuptools_scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
TYPE_CHECKING = False
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from typing import Tuple, Union
|
|
6
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
+
else:
|
|
8
|
+
VERSION_TUPLE = object
|
|
9
|
+
|
|
10
|
+
version: str
|
|
11
|
+
__version__: str
|
|
12
|
+
__version_tuple__: VERSION_TUPLE
|
|
13
|
+
version_tuple: VERSION_TUPLE
|
|
14
|
+
|
|
15
|
+
__version__ = version = '7.8.1'
|
|
16
|
+
__version_tuple__ = version_tuple = (7, 8, 1)
|
|
@@ -59,7 +59,7 @@ to work correctly.
|
|
|
59
59
|
# compensate for out-of-sync clocks between the client and server.
|
|
60
60
|
db.conn.ext_leeway = 2
|
|
61
61
|
|
|
62
|
-
User generated JWT token can be used for superuser access.
|
|
62
|
+
User generated JWT token can be used for user and superuser access.
|
|
63
63
|
|
|
64
64
|
**Example:**
|
|
65
65
|
|
|
@@ -89,3 +89,29 @@ User generated JWT token can be used for superuser access.
|
|
|
89
89
|
|
|
90
90
|
# Connect to "test" database as superuser using the token.
|
|
91
91
|
db = client.db('test', superuser_token=token)
|
|
92
|
+
|
|
93
|
+
# Connect to "test" database as user using the token.
|
|
94
|
+
db = client.db('test', user_token=token)
|
|
95
|
+
|
|
96
|
+
User and superuser tokens can be set on the connection object as well.
|
|
97
|
+
|
|
98
|
+
**Example:**
|
|
99
|
+
|
|
100
|
+
.. code-block:: python
|
|
101
|
+
|
|
102
|
+
from arango import ArangoClient
|
|
103
|
+
|
|
104
|
+
# Initialize the ArangoDB client.
|
|
105
|
+
client = ArangoClient()
|
|
106
|
+
|
|
107
|
+
# Connect to "test" database as superuser using the token.
|
|
108
|
+
db = client.db('test', user_token='token')
|
|
109
|
+
|
|
110
|
+
# Set the user token on the connection object.
|
|
111
|
+
db.conn.set_token('new token')
|
|
112
|
+
|
|
113
|
+
# Connect to "test" database as superuser using the token.
|
|
114
|
+
db = client.db('test', superuser_token='superuser token')
|
|
115
|
+
|
|
116
|
+
# Set the user token on the connection object.
|
|
117
|
+
db.conn.set_token('new superuser token')
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools_scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
TYPE_CHECKING = False
|
|
4
|
-
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple
|
|
6
|
-
|
|
7
|
-
__version__ = version = '7.7.0' # type: str
|
|
8
|
-
__version_tuple__ = version_tuple = (7, 7, 0) # type: Tuple[int | str, ...]
|
|
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
|
|
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
|
|
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
|