blockapi 2.10.1__tar.gz → 2.10.2__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.
- {blockapi-2.10.1 → blockapi-2.10.2}/PKG-INFO +1 -1
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/nft/test_opensea.py +3 -3
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/test_base.py +58 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/nft/magic_eden.py +1 -1
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/nft/opensea.py +1 -1
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/base.py +26 -17
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi.egg-info/PKG-INFO +1 -1
- {blockapi-2.10.1 → blockapi-2.10.2}/setup.py +1 -1
- {blockapi-2.10.1 → blockapi-2.10.2}/LICENSE.md +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/README.md +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/services.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/test_num.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/nft/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/nft/test_simple_hash.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_bitaps_ltc.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_blockchain_info.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_haskoin.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_litecoinspace.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_solana.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_terra.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/api/test_trezor_zec.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/test_data.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/test_enumerate_classes.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/test_data.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/utils/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/utils/address.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/utils/datetime.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/utils/num.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/utils/user_agent.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/bitaps.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/blockchain_info.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/debank.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/haskoin.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/litecoinspace.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/nft/unisat.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/perpetual/perp_abi.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/perpetual/perpetual.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/solana.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/subscan.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/sui.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/synthetix/synthetix.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/synthetix/synthetix_abi.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/terra.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/api/web3_utils.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/coins.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi/v2/models.py +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi.egg-info/SOURCES.txt +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi.egg-info/requires.txt +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/pyproject.toml +0 -0
- {blockapi-2.10.1 → blockapi-2.10.2}/setup.cfg +0 -0
|
@@ -84,7 +84,7 @@ def test_fetch_ntfs(
|
|
|
84
84
|
nfts = api.fetch_nfts(nfts_test_address)
|
|
85
85
|
assert len(nfts.data) == 2
|
|
86
86
|
assert len(fake_sleep_provider.calls)
|
|
87
|
-
assert fake_sleep_provider.calls[0] == ('https://api.opensea.io/', 0.
|
|
87
|
+
assert fake_sleep_provider.calls[0] == ('https://api.opensea.io/', 0.75)
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
def test_fetch_ntfs_error_response(requests_mock, api, fake_sleep_provider):
|
|
@@ -96,7 +96,7 @@ def test_fetch_ntfs_error_response(requests_mock, api, fake_sleep_provider):
|
|
|
96
96
|
nfts = api.fetch_nfts(nfts_test_address)
|
|
97
97
|
assert len(nfts.data) == 0
|
|
98
98
|
assert len(fake_sleep_provider.calls)
|
|
99
|
-
assert fake_sleep_provider.calls[0] == ('https://api.opensea.io/', 0.
|
|
99
|
+
assert fake_sleep_provider.calls[0] == ('https://api.opensea.io/', 0.75)
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
def test_fetch_offers(
|
|
@@ -114,7 +114,7 @@ def test_fetch_offers(
|
|
|
114
114
|
offers = api.fetch_offers(test_collection_slug)
|
|
115
115
|
assert len(offers.data) == 2
|
|
116
116
|
assert len(fake_sleep_provider.calls)
|
|
117
|
-
assert fake_sleep_provider.calls[0] == ('https://api.opensea.io/', 0.
|
|
117
|
+
assert fake_sleep_provider.calls[0] == ('https://api.opensea.io/', 0.75)
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
def test_fetch_offers_error_response(requests_mock, api, offers_response):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from unittest.mock import MagicMock, patch
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
@@ -117,3 +118,60 @@ def mocked_500_with_success_response():
|
|
|
117
118
|
def test_5xx_will_retry(customizable_api, mocked_500_with_success_response):
|
|
118
119
|
response = customizable_api.get_data("test_method")
|
|
119
120
|
assert response.status_code == 200
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@pytest.fixture()
|
|
124
|
+
def mocked_429_with_success_response():
|
|
125
|
+
mocked_throttled = MagicMock()
|
|
126
|
+
mocked_throttled.status_code = 429
|
|
127
|
+
mocked_throttled.raise_for_status.side_effect = HTTPError(
|
|
128
|
+
"test_method", 429, "exception", {}, None
|
|
129
|
+
)
|
|
130
|
+
mocked_throttled.json.return_value = {}
|
|
131
|
+
mocked_throttled.headers = {}
|
|
132
|
+
|
|
133
|
+
mocked_success = MagicMock()
|
|
134
|
+
mocked_success.status_code = 200
|
|
135
|
+
mocked_success.json.return_value = {}
|
|
136
|
+
mocked_success.headers = {}
|
|
137
|
+
|
|
138
|
+
with patch('blockapi.v2.base.CustomizableBlockchainApi._get_response') as patched:
|
|
139
|
+
patched.side_effect = [
|
|
140
|
+
mocked_throttled,
|
|
141
|
+
mocked_success,
|
|
142
|
+
]
|
|
143
|
+
yield patched
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_429_retried_logs_warning_not_error(
|
|
147
|
+
customizable_api, mocked_429_with_success_response, caplog
|
|
148
|
+
):
|
|
149
|
+
with caplog.at_level(logging.WARNING, logger='blockapi.v2.base'):
|
|
150
|
+
response = customizable_api.get_data("test_method")
|
|
151
|
+
|
|
152
|
+
assert response.status_code == 200
|
|
153
|
+
assert not any(r.levelno >= logging.ERROR for r in caplog.records)
|
|
154
|
+
assert any(r.levelno == logging.WARNING for r in caplog.records)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@pytest.fixture()
|
|
158
|
+
def mocked_429_only_response():
|
|
159
|
+
mocked_throttled = MagicMock()
|
|
160
|
+
mocked_throttled.status_code = 429
|
|
161
|
+
mocked_throttled.raise_for_status.side_effect = HTTPError(
|
|
162
|
+
"test_method", 429, "exception", {}, None
|
|
163
|
+
)
|
|
164
|
+
mocked_throttled.json.return_value = {}
|
|
165
|
+
mocked_throttled.headers = {}
|
|
166
|
+
|
|
167
|
+
with patch('blockapi.v2.base.CustomizableBlockchainApi._get_response') as patched:
|
|
168
|
+
patched.side_effect = [mocked_throttled] * 5
|
|
169
|
+
yield patched
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_429_exhausted_logs_error(customizable_api, mocked_429_only_response, caplog):
|
|
173
|
+
with caplog.at_level(logging.WARNING, logger='blockapi.v2.base'):
|
|
174
|
+
response = customizable_api.get_data("test_method")
|
|
175
|
+
|
|
176
|
+
assert response.status_code == 429
|
|
177
|
+
assert any(r.levelno == logging.ERROR for r in caplog.records)
|
|
@@ -399,7 +399,7 @@ class MagicEdenApi(BlockchainApi, INftProvider, INftParser):
|
|
|
399
399
|
return False
|
|
400
400
|
|
|
401
401
|
retry = bool(
|
|
402
|
-
[t for t in data.errors if str(t).upper()
|
|
402
|
+
[t for t in data.errors if 'SERVICE UNAVAILABLE' in str(t).upper()]
|
|
403
403
|
)
|
|
404
404
|
if retry:
|
|
405
405
|
logger.warning('Service unavailable - will retry after long sleep')
|
|
@@ -75,7 +75,7 @@ class OpenSeaApi(BlockchainApi, INftProvider, INftParser):
|
|
|
75
75
|
api_options = ApiOptions(
|
|
76
76
|
blockchain=Blockchain.ETHEREUM,
|
|
77
77
|
base_url='https://api.opensea.io/',
|
|
78
|
-
rate_limit=0.
|
|
78
|
+
rate_limit=0.75, # 4 requests per 3 seconds
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
supported_requests = {
|
|
@@ -113,15 +113,17 @@ class CustomizableBlockchainApi(ABC):
|
|
|
113
113
|
self.sleep_provider.sleep(self.base_url, seconds=sleep_seconds)
|
|
114
114
|
continue
|
|
115
115
|
except HTTPError:
|
|
116
|
-
logger.error(f"Request failed with http error: {response.status_code}")
|
|
117
|
-
|
|
118
116
|
retries -= 1
|
|
119
117
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
retryable = response.status_code == 429 or response.status_code >= 500
|
|
119
|
+
|
|
120
|
+
if retries <= 0 or not retryable or not self.sleep_provider:
|
|
121
|
+
# Genuine failure: out of retries, non-retryable status,
|
|
122
|
+
# or nothing to pace the retry with. This is the only path
|
|
123
|
+
# that surfaces an error to the caller, so log at ERROR.
|
|
124
|
+
logger.error(
|
|
125
|
+
f"Request failed with http error: {response.status_code}"
|
|
126
|
+
)
|
|
125
127
|
time = self._get_response_time(response.headers)
|
|
126
128
|
return FetchResult(
|
|
127
129
|
status_code=response.status_code,
|
|
@@ -137,9 +139,12 @@ class CustomizableBlockchainApi(ABC):
|
|
|
137
139
|
except ValueError:
|
|
138
140
|
seconds = 60
|
|
139
141
|
|
|
142
|
+
# Retryable error that will be retried, so this is expected
|
|
143
|
+
# noise (e.g. 429 throttling) rather than a failure: WARNING.
|
|
140
144
|
logger.warning(
|
|
141
|
-
f'
|
|
142
|
-
f'
|
|
145
|
+
f'Request failed with retryable http error'
|
|
146
|
+
f' {response.status_code}: will retry after {seconds}s'
|
|
147
|
+
f' sleep. Remaining attempts {retries}.'
|
|
143
148
|
)
|
|
144
149
|
self.sleep_provider.sleep(self.base_url, seconds=seconds)
|
|
145
150
|
continue
|
|
@@ -193,15 +198,19 @@ class CustomizableBlockchainApi(ABC):
|
|
|
193
198
|
def _get_reason(response):
|
|
194
199
|
reason = response.reason
|
|
195
200
|
if not reason and response.status_code >= 400:
|
|
196
|
-
|
|
201
|
+
reason = f'Error {response.status_code}'
|
|
197
202
|
|
|
198
|
-
if
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
if isinstance(reason, bytes):
|
|
204
|
+
try:
|
|
205
|
+
reason = reason.decode("utf-8")
|
|
206
|
+
except UnicodeDecodeError:
|
|
207
|
+
reason = reason.decode("iso-8859-1")
|
|
208
|
+
|
|
209
|
+
# Append the response body so the error carries the server's own
|
|
210
|
+
# message instead of just the HTTP status phrase. Truncated to keep
|
|
211
|
+
# logs readable.
|
|
212
|
+
body = (response.text or '').strip()
|
|
213
|
+
return f'{reason}: {body[:500]}' if body else reason
|
|
205
214
|
|
|
206
215
|
@staticmethod
|
|
207
216
|
def _raise_from_response(response: Response) -> None:
|
|
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
|
|
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
|