PYield 0.37.2__tar.gz → 0.37.3__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.
- {pyield-0.37.2 → pyield-0.37.3}/PKG-INFO +1 -1
- pyield-0.37.3/pyield/__about__.py +1 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/anbima/__init__.py +2 -2
- {pyield-0.37.2 → pyield-0.37.3}/pyield/anbima/tpf.py +96 -94
- pyield-0.37.2/pyield/__about__.py +0 -1
- {pyield-0.37.2 → pyield-0.37.3}/.gitignore +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/LICENSE +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/README.md +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/__init__.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/anbima/ettj.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/anbima/ima.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/anbima/imaq.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/anbima/ipca.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/__init__.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/di1.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/di_over.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/futures/__init__.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/futures/common.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/b3/futures/xml.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/__init__.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/auction.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/ptax_api.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/rates.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/repo.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bc/vna.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/bday.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/conftest.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/data_cache.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/date_converter.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/fwd.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/holidays/__init__.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/holidays/br_holidays_old.txt +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/holidays/brholidays.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/ibge/__init__.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/ibge/ipca.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/interpolator.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/py.typed +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/retry.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/__init__.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/benchmark.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/lft.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/ltn.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/ntnb.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/ntnc.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/ntnf.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/pre.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyield/tn/tools.py +0 -0
- {pyield-0.37.2 → pyield-0.37.3}/pyproject.toml +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.37.3"
|
|
@@ -2,13 +2,13 @@ from pyield.anbima.ettj import intraday_ettj, last_ettj
|
|
|
2
2
|
from pyield.anbima.ima import last_ima
|
|
3
3
|
from pyield.anbima.imaq import imaq
|
|
4
4
|
from pyield.anbima.ipca import ipca_projection
|
|
5
|
-
from pyield.anbima.tpf import
|
|
5
|
+
from pyield.anbima.tpf import _fetch_tpf_data, tpf_data, tpf_fixed_rate_maturities
|
|
6
6
|
|
|
7
7
|
__all__ = [
|
|
8
8
|
"last_ima",
|
|
9
9
|
"imaq",
|
|
10
10
|
"ipca_projection",
|
|
11
|
-
"
|
|
11
|
+
"_fetch_tpf_data",
|
|
12
12
|
"tpf_data",
|
|
13
13
|
"tpf_fixed_rate_maturities",
|
|
14
14
|
"last_ettj",
|
|
@@ -8,6 +8,7 @@ from zoneinfo import ZoneInfo
|
|
|
8
8
|
import pandas as pd
|
|
9
9
|
|
|
10
10
|
from pyield import bday
|
|
11
|
+
from pyield.b3 import di1
|
|
11
12
|
from pyield.bc.ptax_api import ptax
|
|
12
13
|
from pyield.data_cache import get_cached_dataset
|
|
13
14
|
from pyield.date_converter import DateScalar, convert_input_dates
|
|
@@ -106,7 +107,7 @@ def _process_raw_df(df_raw: pd.DataFrame) -> pd.DataFrame:
|
|
|
106
107
|
return df
|
|
107
108
|
|
|
108
109
|
|
|
109
|
-
def
|
|
110
|
+
def _add_dv01(df: pd.DataFrame) -> pd.DataFrame:
|
|
110
111
|
df["BDToMat"] = bday.count(start=df["ReferenceDate"], end=df["MaturityDate"])
|
|
111
112
|
|
|
112
113
|
df["Duration"] = 0.0
|
|
@@ -167,6 +168,17 @@ def _add_usd_dv01(df: pd.DataFrame) -> pd.DataFrame:
|
|
|
167
168
|
return df
|
|
168
169
|
|
|
169
170
|
|
|
171
|
+
def _add_di_rate(df: pd.DataFrame, target_date: pd.Timestamp) -> pd.DataFrame:
|
|
172
|
+
"""Add the DI rate column to the DataFrame."""
|
|
173
|
+
# INSERIR OS DADOS DO DI INTERPOLADO ###
|
|
174
|
+
df["DIRate"] = di1.interpolate_rates(
|
|
175
|
+
dates=target_date,
|
|
176
|
+
expirations=df["MaturityDate"],
|
|
177
|
+
extrapolate=True,
|
|
178
|
+
)
|
|
179
|
+
return df
|
|
180
|
+
|
|
181
|
+
|
|
170
182
|
def _reorder_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
171
183
|
"""Reorder the columns of the DataFrame according to the specified order."""
|
|
172
184
|
column_order = [
|
|
@@ -183,6 +195,7 @@ def _reorder_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
|
183
195
|
"BidRate",
|
|
184
196
|
"AskRate",
|
|
185
197
|
"IndicativeRate",
|
|
198
|
+
"DIRate",
|
|
186
199
|
"StdDev",
|
|
187
200
|
"LowerBoundRateD0",
|
|
188
201
|
"UpperBoundRateD0",
|
|
@@ -194,65 +207,22 @@ def _reorder_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
|
194
207
|
return df[column_order].copy()
|
|
195
208
|
|
|
196
209
|
|
|
197
|
-
def
|
|
198
|
-
"""
|
|
199
|
-
main_columns = [
|
|
200
|
-
"BondType",
|
|
201
|
-
"ReferenceDate",
|
|
202
|
-
"MaturityDate",
|
|
203
|
-
"BDToMat",
|
|
204
|
-
"Duration",
|
|
205
|
-
"DV01",
|
|
206
|
-
"DV01USD",
|
|
207
|
-
"Price",
|
|
208
|
-
"BidRate",
|
|
209
|
-
"AskRate",
|
|
210
|
-
"IndicativeRate",
|
|
211
|
-
]
|
|
212
|
-
main_columns = [col for col in main_columns if col in df.columns]
|
|
213
|
-
return df[main_columns].copy()
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def fetch_tpf_data(
|
|
217
|
-
date: DateScalar,
|
|
218
|
-
bond_type: str | BOND_TYPES | None = None,
|
|
219
|
-
all_columns: bool = True,
|
|
220
|
-
) -> pd.DataFrame:
|
|
221
|
-
"""Fetch and process TPF secondary market data directly from the ANBIMA website.
|
|
222
|
-
This is a low-level function intended for internal use or specific backend
|
|
223
|
-
jobs. For general use, prefer `tpf_data` which includes caching logic.
|
|
224
|
-
|
|
225
|
-
Only the last 5 days of data are available in the ANBIMA website. Data older
|
|
226
|
-
than 5 business days is only available through the RTM network.
|
|
210
|
+
def _fetch_tpf_data(date: pd.Timestamp) -> pd.DataFrame:
|
|
211
|
+
"""Fetch and process TPF secondary market data directly from the ANBIMA source.
|
|
227
212
|
|
|
228
|
-
This
|
|
229
|
-
|
|
230
|
-
and
|
|
213
|
+
This is a low-level function intended for internal use. It handles the logic
|
|
214
|
+
of building the correct URL (public or RTM), downloading the data with retries,
|
|
215
|
+
and processing it into a structured DataFrame.
|
|
231
216
|
|
|
232
217
|
Args:
|
|
233
|
-
date (
|
|
234
|
-
bond_type (str, optional): Filter data by bond type.
|
|
235
|
-
Defaults to None, which returns data for all bond types.
|
|
236
|
-
all_columns (bool, optional): If True, all columns are returned.
|
|
237
|
-
Defaults to True. If False, only the main columns are returned.
|
|
218
|
+
date (pd.Timestamp): The reference date for the data.
|
|
238
219
|
|
|
239
220
|
Returns:
|
|
240
|
-
pd.DataFrame: A DataFrame containing bond market data
|
|
241
|
-
|
|
242
|
-
specified date (weekends, holidays, unavailable data, or lack of
|
|
243
|
-
RTM access for older data).
|
|
221
|
+
pd.DataFrame: A DataFrame containing processed bond market data, or an
|
|
222
|
+
empty DataFrame if data is unavailable or a connection error occurs.
|
|
244
223
|
"""
|
|
245
|
-
date = convert_input_dates(date)
|
|
246
|
-
date_log = date.strftime("%d/%m/%Y")
|
|
247
|
-
today = dt.datetime.now(BZ_TIMEZONE).date()
|
|
248
|
-
if date.date() > today:
|
|
249
|
-
logger.info(
|
|
250
|
-
f"Cannot fetch data for a future date ({date_log}). "
|
|
251
|
-
"Returning empty DataFrame."
|
|
252
|
-
)
|
|
253
|
-
return pd.DataFrame()
|
|
254
|
-
|
|
255
224
|
file_url = _build_file_url(date)
|
|
225
|
+
date_str = date.strftime("%d/%m/%Y")
|
|
256
226
|
|
|
257
227
|
# --- "FAIL-FAST" PARA EVITAR RETRIES DESNECESSÁRIOS NA RTM ---
|
|
258
228
|
if ANBIMA_RTM_URL in file_url:
|
|
@@ -263,7 +233,7 @@ def fetch_tpf_data(
|
|
|
263
233
|
# Se falhar (gaierror = get address info error), não estamos na RTM.
|
|
264
234
|
# Não adianta prosseguir para a função com retry.
|
|
265
235
|
logger.warning(
|
|
266
|
-
f"Could not resolve RTM host for {
|
|
236
|
+
f"Could not resolve RTM host for {date_str}. This is expected if "
|
|
267
237
|
"you are not on the RTM network. Historical data requires RTM access. "
|
|
268
238
|
"Returning empty DataFrame."
|
|
269
239
|
)
|
|
@@ -274,40 +244,35 @@ def fetch_tpf_data(
|
|
|
274
244
|
df = _read_raw_df(file_url)
|
|
275
245
|
if df.empty:
|
|
276
246
|
logger.info(
|
|
277
|
-
f"Anbima TPF secondary market data for {
|
|
247
|
+
f"Anbima TPF secondary market data for {date_str} not available. "
|
|
278
248
|
"Returning empty DataFrame."
|
|
279
249
|
)
|
|
280
250
|
return df
|
|
281
251
|
df = _process_raw_df(df)
|
|
282
|
-
df =
|
|
252
|
+
df = _add_dv01(df)
|
|
283
253
|
df = _add_usd_dv01(df)
|
|
254
|
+
df = _add_di_rate(df, target_date=date)
|
|
284
255
|
df = _reorder_columns(df)
|
|
285
256
|
|
|
286
|
-
if not all_columns:
|
|
287
|
-
df = _select_main_columns(df)
|
|
288
|
-
|
|
289
|
-
if bond_type:
|
|
290
|
-
norm_bond_type = _bond_type_mapping(bond_type) # noqa
|
|
291
|
-
df = df.query("BondType == @norm_bond_type").reset_index(drop=True)
|
|
292
257
|
return df.sort_values(["BondType", "MaturityDate"]).reset_index(drop=True)
|
|
293
258
|
|
|
294
259
|
except HTTPError as e:
|
|
295
260
|
if e.code == 404: # noqa
|
|
296
261
|
logger.info(
|
|
297
|
-
f"No Anbima TPF secondary market data for {
|
|
262
|
+
f"No Anbima TPF secondary market data for {date_str} (HTTP 404). "
|
|
298
263
|
"Returning empty DataFrame."
|
|
299
264
|
)
|
|
300
265
|
return pd.DataFrame()
|
|
301
|
-
logger.error(f"HTTP Error fetching data for {
|
|
266
|
+
logger.error(f"HTTP Error fetching data for {date_str} from {file_url}: {e}")
|
|
302
267
|
raise
|
|
303
268
|
|
|
304
269
|
# Este bloco ainda é útil para outros URLErrors (ex: timeout genuíno na URL pública)
|
|
305
270
|
except URLError:
|
|
306
|
-
logger.exception(f"Network error (URLError) fetching TPF data for {
|
|
271
|
+
logger.exception(f"Network error (URLError) fetching TPF data for {date_str}")
|
|
307
272
|
raise
|
|
308
273
|
|
|
309
274
|
except Exception:
|
|
310
|
-
msg = f"An unexpected error occurred fetching TPF data for {
|
|
275
|
+
msg = f"An unexpected error occurred fetching TPF data for {date_str}"
|
|
311
276
|
logger.exception(msg)
|
|
312
277
|
raise
|
|
313
278
|
|
|
@@ -315,27 +280,27 @@ def fetch_tpf_data(
|
|
|
315
280
|
def tpf_data(
|
|
316
281
|
date: DateScalar,
|
|
317
282
|
bond_type: str | None = None,
|
|
318
|
-
|
|
283
|
+
fetch_from_source: bool = False,
|
|
319
284
|
) -> pd.DataFrame:
|
|
320
|
-
"""Retrieve
|
|
285
|
+
"""Retrieve TPF secondary market data from ANBIMA.
|
|
321
286
|
|
|
322
|
-
This function fetches indicative rates for
|
|
323
|
-
|
|
324
|
-
|
|
287
|
+
This function fetches indicative rates and other data for Brazilian government
|
|
288
|
+
bonds from ANBIMA. By default, it attempts to retrieve data from a local
|
|
289
|
+
cache for performance. If `fetch_from_source` is True, it tries to fetch the data
|
|
290
|
+
directly from the ANBIMA website.
|
|
325
291
|
|
|
326
292
|
Args:
|
|
327
|
-
date (DateScalar): The reference date for the
|
|
328
|
-
bond_type (str, optional):
|
|
329
|
-
Defaults to None,
|
|
330
|
-
|
|
331
|
-
|
|
293
|
+
date (DateScalar): The reference date for the data (e.g., '2024-06-14').
|
|
294
|
+
bond_type (str, optional): Filters results by a specific bond type
|
|
295
|
+
(e.g., 'LTN', 'NTN-B'). Defaults to None, returning all bond types.
|
|
296
|
+
fetch_from_source (bool, optional): If True, forces the function to
|
|
297
|
+
bypass the cache and fetch data directly from the source.
|
|
298
|
+
Defaults to False.
|
|
332
299
|
|
|
333
300
|
Returns:
|
|
334
|
-
pd.DataFrame: A DataFrame
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
- IndicativeRate: The indicative rate of the bond.
|
|
338
|
-
- Price: The price (PU) of the bond.
|
|
301
|
+
pd.DataFrame: A DataFrame containing the requested bond data. An empty
|
|
302
|
+
DataFrame is returned if no data is available for the specified date
|
|
303
|
+
(e.g., weekends, holidays, or future dates).
|
|
339
304
|
|
|
340
305
|
Examples:
|
|
341
306
|
>>> from pyield import anbima
|
|
@@ -347,30 +312,67 @@ def tpf_data(
|
|
|
347
312
|
3 2025-08-22 LFT 2027-03-01 0.000302 17193.200289
|
|
348
313
|
4 2025-08-22 LFT 2027-09-01 0.000411 17186.767105
|
|
349
314
|
...
|
|
315
|
+
|
|
316
|
+
DataFrame columns:
|
|
317
|
+
- BondType: Tipo do título público (e.g., 'LTN', 'NTN-B').
|
|
318
|
+
- ReferenceDate: Data de referência dos dados.
|
|
319
|
+
- SelicCode: Código do título no SELIC.
|
|
320
|
+
- IssueBaseDate: Data base ou de emissão do título.
|
|
321
|
+
- MaturityDate: Data de vencimento do título.
|
|
322
|
+
- BDToMat: Número de dias úteis entre a data de referência e o vencimento.
|
|
323
|
+
- Duration: Macaulay Duration do título em anos.
|
|
324
|
+
- DV01: Variação financeira no preço do título (em BRL) para uma
|
|
325
|
+
mudança de 1 basis point (0,01%) na taxa de juros.
|
|
326
|
+
- DV01USD: O mesmo que DV01, mas convertido para USD pela PTAX do dia.
|
|
327
|
+
- Price: Preço Unitário (PU) do título na data de referência.
|
|
328
|
+
- BidRate: Taxa de compra em formato decimal (e.g., 0.10 para 10%).
|
|
329
|
+
- AskRate: Taxa de venda em formato decimal.
|
|
330
|
+
- IndicativeRate: Taxa indicativa em formato decimal.
|
|
331
|
+
- DIRate: Taxa DI interpolada para o vencimento do título.
|
|
332
|
+
- StdDev: Desvio padrão da taxa indicativa.
|
|
333
|
+
- LowerBoundRateD0: Limite inferior do intervalo indicativo para D+0.
|
|
334
|
+
- UpperBoundRateD0: Limite superior do intervalo indicativo para D+0.
|
|
335
|
+
- LowerBoundRateD1: Limite inferior do intervalo indicativo para D+1.
|
|
336
|
+
- UpperBoundRateD1: Limite superior do intervalo indicativo para D+1.
|
|
337
|
+
- Criteria: Critério utilizado pela ANBIMA para o cálculo.
|
|
338
|
+
|
|
339
|
+
Notes:
|
|
340
|
+
- Data for the last 5 business days is available on the public ANBIMA
|
|
341
|
+
website.
|
|
342
|
+
- Historical data (older than 5 business days) is only available via
|
|
343
|
+
the RTM network. If you are not connected to RTM, requests for
|
|
344
|
+
older dates will return an empty DataFrame.
|
|
350
345
|
"""
|
|
351
|
-
df = get_cached_dataset("tpf")
|
|
352
346
|
date = convert_input_dates(date)
|
|
353
|
-
df = df.query("ReferenceDate == @date").reset_index(drop=True)
|
|
354
347
|
|
|
355
|
-
|
|
348
|
+
date_log = date.strftime("%d/%m/%Y")
|
|
349
|
+
today = dt.datetime.now(BZ_TIMEZONE).date()
|
|
350
|
+
if date.date() > today:
|
|
351
|
+
logger.info(
|
|
352
|
+
f"Cannot fetch data for a future date ({date_log}). "
|
|
353
|
+
"Returning empty DataFrame."
|
|
354
|
+
)
|
|
355
|
+
return pd.DataFrame()
|
|
356
|
+
|
|
357
|
+
if fetch_from_source:
|
|
356
358
|
# Try to fetch the data from the Anbima website
|
|
357
|
-
df =
|
|
359
|
+
df = _fetch_tpf_data(date)
|
|
360
|
+
else:
|
|
361
|
+
df = (
|
|
362
|
+
get_cached_dataset("tpf")
|
|
363
|
+
.query("ReferenceDate == @date")
|
|
364
|
+
.reset_index(drop=True)
|
|
365
|
+
)
|
|
358
366
|
|
|
359
367
|
if df.empty:
|
|
360
368
|
# If the data is still empty, return an empty DataFrame
|
|
361
369
|
return pd.DataFrame()
|
|
362
370
|
|
|
363
371
|
if bond_type:
|
|
364
|
-
|
|
372
|
+
norm_bond_type = _bond_type_mapping(bond_type) # noqa
|
|
373
|
+
df = df.query("BondType == @norm_bond_type").reset_index(drop=True)
|
|
365
374
|
|
|
366
|
-
|
|
367
|
-
df["MaturityDate"] = bday.offset(df["MaturityDate"], 0)
|
|
368
|
-
|
|
369
|
-
return (
|
|
370
|
-
df[["ReferenceDate", "BondType", "MaturityDate", "IndicativeRate", "Price"]]
|
|
371
|
-
.sort_values(["BondType", "MaturityDate"])
|
|
372
|
-
.reset_index(drop=True)
|
|
373
|
-
)
|
|
375
|
+
return df.sort_values(["BondType", "MaturityDate"]).reset_index(drop=True)
|
|
374
376
|
|
|
375
377
|
|
|
376
378
|
def tpf_fixed_rate_maturities(date: DateScalar) -> pd.Series:
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.37.2"
|
|
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
|