quantplay 2.0.8__tar.gz → 2.0.9__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.
- {quantplay-2.0.8 → quantplay-2.0.9}/PKG-INFO +1 -1
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/noren.py +91 -64
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.0.8 → quantplay-2.0.9}/setup.py +1 -1
- {quantplay-2.0.8 → quantplay-2.0.9}/README.md +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/pyproject.toml +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/aliceblue.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/angelone.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/auto_login/aliceblue.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/five_paisa.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/generics/broker.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/motilal.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/upstox.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/xts.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/broker/zerodha.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/model/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/model/broker/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/model/broker/generics.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/py.typed +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/equities/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/equities/intraday/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/equities/overnight/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/futures/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/futures/overnight/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/options/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/options/intraday/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/options/intraday/ladder.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/options/intraday/musk.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/strategies/options/intraday/short_straddle.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay.egg-info/SOURCES.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/setup.cfg +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/tests/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/tests/conftest.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.9}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from queue import Queue
|
|
3
3
|
import traceback
|
|
4
|
-
from typing import Dict
|
|
4
|
+
from typing import Callable, Dict, Literal
|
|
5
5
|
|
|
6
6
|
import polars as pl
|
|
7
7
|
from retrying import retry
|
|
8
8
|
from json.decoder import JSONDecodeError
|
|
9
9
|
|
|
10
|
+
from quantplay.broker.finvasia_utils.fa_noren import FA_NorenApi
|
|
11
|
+
from quantplay.broker.ft_utils.ft_noren import FT_NorenApi
|
|
10
12
|
from quantplay.broker.generics.broker import Broker
|
|
11
13
|
from quantplay.exception.exceptions import (
|
|
12
14
|
InvalidArgumentException,
|
|
@@ -47,7 +49,9 @@ class Noren(Broker):
|
|
|
47
49
|
self.order_type_sl = "SL-LMT"
|
|
48
50
|
self.trigger_pending_status = "TRIGGER_PENDING"
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
self.api: FA_NorenApi | FT_NorenApi
|
|
53
|
+
|
|
54
|
+
def set_attributes(self, response: Dict[str, str | None]) -> None:
|
|
51
55
|
self.email = response["email"]
|
|
52
56
|
self.user_id = response["actid"]
|
|
53
57
|
self.full_name = response["uname"]
|
|
@@ -72,9 +76,10 @@ class Noren(Broker):
|
|
|
72
76
|
def get_symbol(self, symbol, exchange=None):
|
|
73
77
|
if symbol not in self.quantplay_symbol_map:
|
|
74
78
|
return symbol
|
|
79
|
+
|
|
75
80
|
return self.quantplay_symbol_map[symbol]
|
|
76
81
|
|
|
77
|
-
def get_transaction_type(self, transaction_type):
|
|
82
|
+
def get_transaction_type(self, transaction_type: Literal["BUY", "SELL"]):
|
|
78
83
|
if transaction_type == "BUY":
|
|
79
84
|
return "B"
|
|
80
85
|
elif transaction_type == "SELL":
|
|
@@ -87,16 +92,19 @@ class Noren(Broker):
|
|
|
87
92
|
def get_order_type(self, order_type):
|
|
88
93
|
if order_type == OrderType.market:
|
|
89
94
|
return "MKT"
|
|
95
|
+
|
|
90
96
|
elif order_type == OrderType.sl:
|
|
91
97
|
return "SL-LMT"
|
|
98
|
+
|
|
92
99
|
elif order_type == OrderType.slm:
|
|
93
100
|
return "SL-MKT"
|
|
101
|
+
|
|
94
102
|
elif order_type == OrderType.limit:
|
|
95
103
|
return "LMT"
|
|
96
104
|
|
|
97
105
|
return order_type
|
|
98
106
|
|
|
99
|
-
def get_product(self, product):
|
|
107
|
+
def get_product(self, product: str):
|
|
100
108
|
if product == "NRML":
|
|
101
109
|
return "M"
|
|
102
110
|
elif product == "CNC":
|
|
@@ -106,9 +114,7 @@ class Noren(Broker):
|
|
|
106
114
|
elif product in ["M", "C", "I"]:
|
|
107
115
|
return product
|
|
108
116
|
|
|
109
|
-
raise InvalidArgumentException(
|
|
110
|
-
"Product {} not supported for trading".format(product)
|
|
111
|
-
)
|
|
117
|
+
raise InvalidArgumentException(f"Product {product} not supported for trading")
|
|
112
118
|
|
|
113
119
|
def event_handler_order_update(self, order):
|
|
114
120
|
try:
|
|
@@ -210,7 +216,7 @@ class Noren(Broker):
|
|
|
210
216
|
"remarks": tag,
|
|
211
217
|
}
|
|
212
218
|
Constants.logger.info("[PLACING_ORDER] {}".format(json.dumps(data)))
|
|
213
|
-
response = self.api.place_order(
|
|
219
|
+
response = self.api.place_order(
|
|
214
220
|
buy_or_sell=noren_transaction_type,
|
|
215
221
|
product_type=noren_product,
|
|
216
222
|
exchange=exchange,
|
|
@@ -227,10 +233,12 @@ class Noren(Broker):
|
|
|
227
233
|
Constants.logger.info(
|
|
228
234
|
"[PLACE_ORDER_RESPONSE] {} input {}".format(response, json.dumps(data))
|
|
229
235
|
)
|
|
230
|
-
|
|
236
|
+
|
|
237
|
+
if response is not None and "norenordno" in response:
|
|
231
238
|
return response["norenordno"]
|
|
232
239
|
else:
|
|
233
240
|
raise Exception(response)
|
|
241
|
+
|
|
234
242
|
except Exception as e:
|
|
235
243
|
traceback.print_exc()
|
|
236
244
|
exception_message = "Order placement failed with error [{}]".format(str(e))
|
|
@@ -248,12 +256,21 @@ class Noren(Broker):
|
|
|
248
256
|
tradingsymbol = self.get_symbol(tradingsymbol)
|
|
249
257
|
|
|
250
258
|
token = self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["token"]
|
|
251
|
-
|
|
259
|
+
quote = self.api.get_quotes(exchange, str(token))
|
|
260
|
+
|
|
261
|
+
if quote is None:
|
|
262
|
+
raise BrokerException("Response from Broker for LTP is Invalid")
|
|
263
|
+
|
|
264
|
+
return float(quote["lp"])
|
|
252
265
|
|
|
253
266
|
def live_data(self, exchange, tradingsymbol):
|
|
254
267
|
tradingsymbol = self.get_symbol(tradingsymbol)
|
|
255
268
|
token = self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["token"]
|
|
256
|
-
data = self.api.get_quotes(exchange, str(token))
|
|
269
|
+
data = self.api.get_quotes(exchange, str(token))
|
|
270
|
+
|
|
271
|
+
if data is None:
|
|
272
|
+
raise BrokerException("Response from Broker for Market Data is Invalid")
|
|
273
|
+
|
|
257
274
|
return {
|
|
258
275
|
"ltp": float(data["lp"]),
|
|
259
276
|
"upper_circuit": float(data["uc"]),
|
|
@@ -261,15 +278,20 @@ class Noren(Broker):
|
|
|
261
278
|
}
|
|
262
279
|
|
|
263
280
|
def order_history(self, order_id):
|
|
264
|
-
order_history = self.api.single_order_history(order_id)
|
|
281
|
+
order_history = self.api.single_order_history(order_id)
|
|
282
|
+
|
|
283
|
+
if order_history is None:
|
|
284
|
+
raise BrokerException("Response from Broker for Order History is Invalid")
|
|
285
|
+
|
|
265
286
|
order_details = order_history[0]
|
|
266
287
|
|
|
267
|
-
data = {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
288
|
+
data = {
|
|
289
|
+
"order_id": order_id,
|
|
290
|
+
"order_type": order_details["prctyp"],
|
|
291
|
+
"exchange": order_details["exch"],
|
|
292
|
+
"quantity": order_details["qty"],
|
|
293
|
+
"tradingsymbol": order_details["tsym"],
|
|
294
|
+
}
|
|
273
295
|
|
|
274
296
|
return data
|
|
275
297
|
|
|
@@ -289,6 +311,7 @@ class Noren(Broker):
|
|
|
289
311
|
|
|
290
312
|
if "order_type" not in order_to_modify:
|
|
291
313
|
order_to_modify["order_type"] = existing_details["order_type"]
|
|
314
|
+
|
|
292
315
|
if "quantity" not in order_to_modify:
|
|
293
316
|
order_to_modify["quantity"] = existing_details["quantity"]
|
|
294
317
|
|
|
@@ -308,33 +331,39 @@ class Noren(Broker):
|
|
|
308
331
|
order_to_modify["order_id"], response
|
|
309
332
|
)
|
|
310
333
|
)
|
|
334
|
+
|
|
335
|
+
if response is None:
|
|
336
|
+
raise Exception("Response is None")
|
|
337
|
+
|
|
311
338
|
return response
|
|
339
|
+
|
|
312
340
|
except Exception as e:
|
|
313
|
-
exception_message =
|
|
314
|
-
|
|
315
|
-
order_to_modify["order_id"], e
|
|
316
|
-
)
|
|
317
|
-
)
|
|
318
|
-
Constants.logger.error("{}".format(exception_message))
|
|
341
|
+
exception_message = f"OrderModificationFailed for {order_to_modify['order_id']} failed with exception {e}"
|
|
342
|
+
Constants.logger.error(f"{exception_message}")
|
|
319
343
|
raise e
|
|
320
344
|
|
|
321
345
|
@timeit(MetricName="Finvasia:cancel_order")
|
|
322
346
|
def cancel_order(self, order_id, variety=None):
|
|
323
|
-
self.api.cancel_order(order_id)
|
|
347
|
+
self.api.cancel_order(order_id)
|
|
324
348
|
|
|
325
349
|
def stream_order_data(self):
|
|
326
|
-
self.api.start_websocket(
|
|
327
|
-
order_update_callback=self.event_handler_order_update
|
|
328
|
-
)
|
|
350
|
+
self.api.start_websocket(order_update_callback=self.event_handler_order_update)
|
|
329
351
|
|
|
330
352
|
@timeit(MetricName="Finvasia:profile")
|
|
331
353
|
def profile(self) -> UserBrokerProfileResponse:
|
|
354
|
+
if self.user_id is None:
|
|
355
|
+
raise Exception("User ID is unknown")
|
|
356
|
+
|
|
332
357
|
response: UserBrokerProfileResponse = {
|
|
333
|
-
"user_id": self.user_id,
|
|
334
|
-
"full_name": self.full_name,
|
|
335
|
-
"email": self.email,
|
|
358
|
+
"user_id": self.user_id,
|
|
336
359
|
}
|
|
337
360
|
|
|
361
|
+
if self.full_name is not None:
|
|
362
|
+
response["full_name"] = self.full_name
|
|
363
|
+
|
|
364
|
+
if self.email is not None:
|
|
365
|
+
response["email"] = self.email
|
|
366
|
+
|
|
338
367
|
return response
|
|
339
368
|
|
|
340
369
|
@timeit(MetricName="Noren:holdings")
|
|
@@ -344,7 +373,7 @@ class Noren(Broker):
|
|
|
344
373
|
stop_max_attempt_number=3,
|
|
345
374
|
)
|
|
346
375
|
def holdings(self):
|
|
347
|
-
holdings = self.api.get_holdings()
|
|
376
|
+
holdings = self.api.get_holdings()
|
|
348
377
|
if holdings is None or len(holdings) == 0:
|
|
349
378
|
return pl.DataFrame(schema=self.holidings_schema)
|
|
350
379
|
|
|
@@ -387,27 +416,13 @@ class Noren(Broker):
|
|
|
387
416
|
return holdings_df[list(self.holidings_schema.keys())].cast(self.holidings_schema)
|
|
388
417
|
|
|
389
418
|
@timeit(MetricName="Finvasia:positions")
|
|
390
|
-
@retry(
|
|
391
|
-
wait_exponential_multiplier=3000,
|
|
392
|
-
wait_exponential_max=10000,
|
|
393
|
-
stop_max_attempt_number=3,
|
|
394
|
-
retry_on_exception=retry_exception,
|
|
395
|
-
)
|
|
396
419
|
def positions(self, drop_cnc: bool = True) -> pl.DataFrame:
|
|
397
|
-
|
|
398
|
-
try:
|
|
399
|
-
positions = self.api.get_positions() # type:ignore
|
|
400
|
-
if positions is None or len(positions) == 0:
|
|
401
|
-
return pl.DataFrame(schema=self.positions_schema)
|
|
402
|
-
except BrokerException:
|
|
403
|
-
raise
|
|
404
|
-
except JSONDecodeError:
|
|
405
|
-
raise BrokerException("Broker failed to send positions")
|
|
406
|
-
except Exception:
|
|
407
|
-
raise
|
|
420
|
+
positions = self.invoke_noren_api(self.api.get_positions)
|
|
408
421
|
|
|
409
|
-
|
|
422
|
+
if positions is None or len(positions) == 0:
|
|
423
|
+
return pl.DataFrame(schema=self.positions_schema)
|
|
410
424
|
|
|
425
|
+
positions_df = pl.DataFrame(positions)
|
|
411
426
|
positions_df = positions_df.rename(
|
|
412
427
|
{
|
|
413
428
|
"tsym": "tradingsymbol",
|
|
@@ -488,16 +503,9 @@ class Noren(Broker):
|
|
|
488
503
|
|
|
489
504
|
@timeit(MetricName="Finvasia:orders")
|
|
490
505
|
def orders(self, tag: str | None = None, add_ltp: bool = True) -> pl.DataFrame:
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
return pl.DataFrame(schema=self.orders_schema)
|
|
495
|
-
except BrokerException:
|
|
496
|
-
raise
|
|
497
|
-
except JSONDecodeError:
|
|
498
|
-
raise BrokerException("Broker failed to send orders")
|
|
499
|
-
except Exception:
|
|
500
|
-
raise
|
|
506
|
+
orders = self.invoke_noren_api(self.api.get_order_book)
|
|
507
|
+
if orders is None or len(orders) == 0:
|
|
508
|
+
return pl.DataFrame(schema=self.orders_schema)
|
|
501
509
|
|
|
502
510
|
orders_df = pl.DataFrame(orders)
|
|
503
511
|
|
|
@@ -632,6 +640,26 @@ class Noren(Broker):
|
|
|
632
640
|
|
|
633
641
|
return orders_df[list(self.orders_schema.keys())].cast(self.orders_schema)
|
|
634
642
|
|
|
643
|
+
@retry(
|
|
644
|
+
wait_exponential_multiplier=3000,
|
|
645
|
+
wait_exponential_max=10000,
|
|
646
|
+
stop_max_attempt_number=3,
|
|
647
|
+
retry_on_exception=retry_exception,
|
|
648
|
+
)
|
|
649
|
+
def invoke_noren_api(self, fn: Callable, *args, **kwargs) -> Dict:
|
|
650
|
+
try:
|
|
651
|
+
response = fn(*args, **kwargs)
|
|
652
|
+
if "stat" in response and "not_ok" == response["stat"].lower():
|
|
653
|
+
raise TokenException(response["emsg"])
|
|
654
|
+
return response
|
|
655
|
+
|
|
656
|
+
except JSONDecodeError:
|
|
657
|
+
raise BrokerException("Failed to data from broker")
|
|
658
|
+
|
|
659
|
+
except Exception:
|
|
660
|
+
traceback.print_exc()
|
|
661
|
+
raise RetryableException("Failed to data from broker")
|
|
662
|
+
|
|
635
663
|
@timeit(MetricName="Finvasia:positions")
|
|
636
664
|
@retry(
|
|
637
665
|
wait_exponential_multiplier=1000,
|
|
@@ -640,9 +668,7 @@ class Noren(Broker):
|
|
|
640
668
|
retry_on_exception=retry_exception,
|
|
641
669
|
)
|
|
642
670
|
def margins(self) -> Dict:
|
|
643
|
-
api_margins = self.api.get_limits
|
|
644
|
-
if "stat" in api_margins and "not_ok" == api_margins["stat"].lower():
|
|
645
|
-
raise TokenException(api_margins["emsg"])
|
|
671
|
+
api_margins = self.invoke_noren_api(self.api.get_limits)
|
|
646
672
|
|
|
647
673
|
try:
|
|
648
674
|
collateral = 0
|
|
@@ -679,9 +705,10 @@ class Noren(Broker):
|
|
|
679
705
|
|
|
680
706
|
@timeit(MetricName="Finvasia:account_summary")
|
|
681
707
|
def account_summary(self):
|
|
682
|
-
margins: Dict = self.margins()
|
|
683
708
|
pnl = 0
|
|
709
|
+
margins: Dict = self.margins()
|
|
684
710
|
positions = self.positions()
|
|
711
|
+
|
|
685
712
|
if len(positions) > 0:
|
|
686
713
|
pnl = positions["pnl"].sum()
|
|
687
714
|
|
|
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
|