quantplay 2.0.181__tar.gz → 2.0.183__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.181 → quantplay-2.0.183}/PKG-INFO +1 -1
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/kotak.py +2 -2
- quantplay-2.0.183/quantplay/broker/kotak_utils/kotak_ws.py +93 -0
- quantplay-2.0.183/quantplay/broker/kotak_utils/kotak_ws_lib.py +142 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay.egg-info/SOURCES.txt +3 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/setup.py +1 -1
- quantplay-2.0.183/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/README.md +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/pyproject.toml +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/aliceblue.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/angelone.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/auto_login/aliceblue.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/breeze/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/breeze/breeze_utils.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/broker_factory.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/dhan.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/five_paisa.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/generics/broker.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/icici_direct.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/jainam_xts.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.181/quantplay/broker/uplink → quantplay-2.0.183/quantplay/broker/kotak_utils}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/motilal.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/noren.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.181/quantplay/broker/xts_utils → quantplay-2.0.183/quantplay/broker/uplink}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/upstox.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/xts.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.0.181/quantplay/core → quantplay-2.0.183/quantplay/broker/xts_utils}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/zerodha.py +0 -0
- {quantplay-2.0.181/quantplay/indicator → quantplay-2.0.183/quantplay/core}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/core/strategy.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.0.181/quantplay/model → quantplay-2.0.183/quantplay/indicator}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/indicator/iv.py +0 -0
- {quantplay-2.0.181/quantplay/strategy → quantplay-2.0.183/quantplay/model}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/model/broker.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/model/broker_response.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/model/generics.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/model/instrument_data.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/model/order_event.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/py.typed +0 -0
- {quantplay-2.0.181/quantplay/wrapper → quantplay-2.0.183/quantplay/strategy}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/strategy/iv_spike.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/strategy/obuy.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/utils/caching.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.181/quantplay/wrapper/aws → quantplay-2.0.183/quantplay/wrapper}/__init__.py +0 -0
- {quantplay-2.0.181/tests → quantplay-2.0.183/quantplay/wrapper/aws}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay/wrapper/redis.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/setup.cfg +0 -0
- {quantplay-2.0.181/tests/wrapper → quantplay-2.0.183/tests}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/tests/conftest.py +0 -0
- {quantplay-2.0.181/tests/wrapper/aws → quantplay-2.0.183/tests/wrapper}/__init__.py +0 -0
- {quantplay-2.0.181 → quantplay-2.0.183}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -587,12 +587,12 @@ class Kotak(Broker):
|
|
|
587
587
|
return order_type_map.get(order_type, order_type) # type:ignore
|
|
588
588
|
|
|
589
589
|
def get_quantplay_order_status(self, status: str) -> OrderStatusType:
|
|
590
|
-
if status in ["put order req received", "validation pending", "open pending"]:
|
|
590
|
+
if status in ["put order req received", "validation pending", "open pending", "modify pending", "modify validation pending"]:
|
|
591
591
|
return "OPEN"
|
|
592
592
|
if status == "cancel pending":
|
|
593
593
|
return "CANCELLED"
|
|
594
594
|
status = status.upper()
|
|
595
|
-
if status not in ["OPEN", "
|
|
595
|
+
if status not in ["OPEN", "TRIGGER PENDING", "CANCELLED", "REJECTED", "COMPLETE"]:
|
|
596
596
|
Constants.logger.error(f"{status} not supported for Kotak")
|
|
597
597
|
return "INVALID STATUS" # type:ignore
|
|
598
598
|
return status # type:ignore
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
import json
|
|
3
|
+
import threading
|
|
4
|
+
import time
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from quantplay.broker.kotak_utils.kotak_ws_lib import HSIWebSocket
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
ORDER_FEED_URL = "wss://clhsi.kotaksecurities.com/realtime?sId={server_id}"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NeoWebSocket:
|
|
14
|
+
def __init__(self, sid: str | None, token: str | None, server_id: str | None):
|
|
15
|
+
self.hsiWebsocket = None
|
|
16
|
+
self.is_hsi_open = 0
|
|
17
|
+
self.sid = sid
|
|
18
|
+
self.access_token = token
|
|
19
|
+
self.server_id = server_id
|
|
20
|
+
self.on_message: Callable[[Any], None] | None = None
|
|
21
|
+
self.on_error: Callable[[Any], None] | None = None
|
|
22
|
+
self.on_close: Callable[[], None] | None = None
|
|
23
|
+
self.on_open: Callable[[], None] | None = None
|
|
24
|
+
self.hsi_thread = None
|
|
25
|
+
|
|
26
|
+
def on_hsi_open(self):
|
|
27
|
+
server = "WEB"
|
|
28
|
+
json_d = {
|
|
29
|
+
"type": "CONNECTION",
|
|
30
|
+
"Authorization": self.access_token,
|
|
31
|
+
"Sid": self.sid,
|
|
32
|
+
"source": server,
|
|
33
|
+
}
|
|
34
|
+
json_d = json.dumps(json_d)
|
|
35
|
+
|
|
36
|
+
if self.hsiWebsocket:
|
|
37
|
+
self.hsiWebsocket.send(json_d)
|
|
38
|
+
|
|
39
|
+
if self.on_open:
|
|
40
|
+
self.on_open()
|
|
41
|
+
|
|
42
|
+
def on_hsi_close(self):
|
|
43
|
+
if self.is_hsi_open == 1:
|
|
44
|
+
self.is_hsi_open = 0
|
|
45
|
+
if self.on_close:
|
|
46
|
+
self.on_close()
|
|
47
|
+
|
|
48
|
+
def on_hsi_error(self, error: Any):
|
|
49
|
+
if self.is_hsi_open == 1:
|
|
50
|
+
self.is_hsi_open = 0
|
|
51
|
+
|
|
52
|
+
if self.on_error:
|
|
53
|
+
self.on_error(error)
|
|
54
|
+
else:
|
|
55
|
+
print("Error Occurred in Websocket! Error Message ", error)
|
|
56
|
+
|
|
57
|
+
def on_hsi_message(self, message: Any):
|
|
58
|
+
if message:
|
|
59
|
+
if isinstance(message, str):
|
|
60
|
+
req = json.loads(message)
|
|
61
|
+
if req["type"] == "cn":
|
|
62
|
+
self.is_hsi_open = 1
|
|
63
|
+
threading.Thread(target=self.start_hsi_ping_thread).start()
|
|
64
|
+
|
|
65
|
+
if self.on_message:
|
|
66
|
+
self.on_message({"type": "order_feed", "data": message})
|
|
67
|
+
|
|
68
|
+
def start_hsi_ping_thread(self):
|
|
69
|
+
while self.hsiWebsocket and self.is_hsi_open:
|
|
70
|
+
time.sleep(30)
|
|
71
|
+
payload = {"type": "HB"}
|
|
72
|
+
self.hsiWebsocket.send(json.dumps(payload))
|
|
73
|
+
|
|
74
|
+
def start_hsi_websocket(self):
|
|
75
|
+
url = ORDER_FEED_URL.format(server_id=self.server_id)
|
|
76
|
+
self.hsiWebsocket = HSIWebSocket()
|
|
77
|
+
self.hsiWebsocket.open_connection(
|
|
78
|
+
url=url,
|
|
79
|
+
onopen=self.on_hsi_open,
|
|
80
|
+
onmessage=self.on_hsi_message,
|
|
81
|
+
onclose=self.on_hsi_close,
|
|
82
|
+
onerror=self.on_hsi_error,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def start_hsi_websocket_thread(self):
|
|
86
|
+
self.hsi_thread = threading.Thread(target=self.start_hsi_websocket)
|
|
87
|
+
self.hsi_thread.start()
|
|
88
|
+
|
|
89
|
+
def get_order_feed(self):
|
|
90
|
+
if self.hsiWebsocket is None or self.is_hsi_open == 0:
|
|
91
|
+
self.start_hsi_websocket_thread()
|
|
92
|
+
else:
|
|
93
|
+
print("you had already subscribed for order feed")
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
import json
|
|
3
|
+
import ssl
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import websocket
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StartHSIServer:
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
url: str,
|
|
13
|
+
onopen: Callable[[], None],
|
|
14
|
+
onmessage: Callable[[Any], None],
|
|
15
|
+
onerror: Callable[[Any], None],
|
|
16
|
+
onclose: Callable[[], None],
|
|
17
|
+
):
|
|
18
|
+
self.openState = None
|
|
19
|
+
self.readyState = None
|
|
20
|
+
self.url = url
|
|
21
|
+
self.onopen = onopen
|
|
22
|
+
self.onmessage = onmessage
|
|
23
|
+
self.onerror = onerror
|
|
24
|
+
self.onclose = onclose
|
|
25
|
+
# self.token, self.sid = token, sid
|
|
26
|
+
global hsiWs
|
|
27
|
+
try:
|
|
28
|
+
# websocket.enableTrace(True)
|
|
29
|
+
hsiWs = websocket.WebSocketApp(
|
|
30
|
+
self.url,
|
|
31
|
+
on_open=self.on_open,
|
|
32
|
+
on_message=self.on_message,
|
|
33
|
+
on_error=self.on_error,
|
|
34
|
+
on_close=self.on_close,
|
|
35
|
+
)
|
|
36
|
+
hsiWs.run_forever( # type: ignore
|
|
37
|
+
ping_interval=5, reconnect=5, sslopt={"cert_reqs": ssl.CERT_NONE}
|
|
38
|
+
)
|
|
39
|
+
except Exception:
|
|
40
|
+
print("WebSocket not supported!")
|
|
41
|
+
|
|
42
|
+
def on_message(self, ws: websocket.WebSocket, message: Any):
|
|
43
|
+
# print("Received message:", message)
|
|
44
|
+
self.onmessage(message)
|
|
45
|
+
|
|
46
|
+
def on_error(self, ws: websocket.WebSocket, error: Any):
|
|
47
|
+
print("Error:", error)
|
|
48
|
+
self.onerror(error)
|
|
49
|
+
|
|
50
|
+
def on_close(self, ws: websocket.WebSocket, close_status_code: Any, close_msg: Any):
|
|
51
|
+
# print("Connection closed")
|
|
52
|
+
self.openState = 0
|
|
53
|
+
self.readyState = 0
|
|
54
|
+
if hsiWs:
|
|
55
|
+
hsiWs.close() # type: ignore
|
|
56
|
+
self.onclose()
|
|
57
|
+
|
|
58
|
+
def on_open(self, ws: websocket.WebSocket):
|
|
59
|
+
# print("Connection established HSWebSocket")
|
|
60
|
+
self.openState = 1
|
|
61
|
+
self.readyState = 1
|
|
62
|
+
self.onopen()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class HSIWebSocket:
|
|
66
|
+
def __init__(self):
|
|
67
|
+
# self.hsiWs = None
|
|
68
|
+
self.hsiSocket = None
|
|
69
|
+
self.reqData = None
|
|
70
|
+
self.openState = 0
|
|
71
|
+
self.readyState = 0
|
|
72
|
+
self.url = None
|
|
73
|
+
self.onopen = None
|
|
74
|
+
self.onmessage = None
|
|
75
|
+
self.onclose = None
|
|
76
|
+
self.onerror = None
|
|
77
|
+
# self.token, self.sid = token, sid
|
|
78
|
+
|
|
79
|
+
def open_connection(
|
|
80
|
+
self,
|
|
81
|
+
url: str,
|
|
82
|
+
onopen: Callable[[], None],
|
|
83
|
+
onmessage: Callable[[Any], None],
|
|
84
|
+
onerror: Callable[[Any], None],
|
|
85
|
+
onclose: Callable[[], None],
|
|
86
|
+
):
|
|
87
|
+
self.url = url
|
|
88
|
+
self.onopen = onopen
|
|
89
|
+
self.onmessage = onmessage
|
|
90
|
+
self.onclose = onclose
|
|
91
|
+
self.onerror = onerror
|
|
92
|
+
StartHSIServer(self.url, self.onopen, self.onmessage, self.onerror, self.onclose)
|
|
93
|
+
|
|
94
|
+
def send(self, d: Any):
|
|
95
|
+
reqJson = json.loads(d)
|
|
96
|
+
req = None
|
|
97
|
+
if reqJson["type"] == "CONNECTION":
|
|
98
|
+
if "Authorization" in reqJson and "Sid" in reqJson and "source" in reqJson:
|
|
99
|
+
req = {
|
|
100
|
+
"type": "cn",
|
|
101
|
+
"Authorization": reqJson["Authorization"],
|
|
102
|
+
"Sid": reqJson["Sid"],
|
|
103
|
+
"src": reqJson["source"],
|
|
104
|
+
}
|
|
105
|
+
self.reqData = req
|
|
106
|
+
else:
|
|
107
|
+
if "x-access-token" in reqJson and "src" in reqJson:
|
|
108
|
+
req = {
|
|
109
|
+
"type": "cn",
|
|
110
|
+
"x-access-token": reqJson["x-access-token"],
|
|
111
|
+
"source": reqJson["source"],
|
|
112
|
+
}
|
|
113
|
+
self.reqData = req
|
|
114
|
+
else:
|
|
115
|
+
print("Invalid connection mode !")
|
|
116
|
+
|
|
117
|
+
elif reqJson["type"] == "HB":
|
|
118
|
+
# self.reqData=reqJson
|
|
119
|
+
req = {"type": "hb"}
|
|
120
|
+
self.reqData = req
|
|
121
|
+
|
|
122
|
+
else:
|
|
123
|
+
if reqJson["type"] == "FORCE_CONNECTION":
|
|
124
|
+
self.reqData = self.reqData["type"] = "fcn" # type: ignore
|
|
125
|
+
req = self.reqData
|
|
126
|
+
else:
|
|
127
|
+
print("Invalid Request !")
|
|
128
|
+
|
|
129
|
+
if hsiWs and req:
|
|
130
|
+
js_obj = json.dumps(req)
|
|
131
|
+
hsiWs.send(js_obj)
|
|
132
|
+
else:
|
|
133
|
+
print(
|
|
134
|
+
"Unable to send request! Reason: Connection faulty or request not valid!"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def close(self):
|
|
138
|
+
self.openState = 0
|
|
139
|
+
self.readyState = 0
|
|
140
|
+
|
|
141
|
+
if hsiWs:
|
|
142
|
+
hsiWs.close() # type: ignore
|
|
@@ -37,6 +37,9 @@ quantplay/broker/ft_utils/flattrade_utils.py
|
|
|
37
37
|
quantplay/broker/ft_utils/ft_noren.py
|
|
38
38
|
quantplay/broker/generics/__init__.py
|
|
39
39
|
quantplay/broker/generics/broker.py
|
|
40
|
+
quantplay/broker/kotak_utils/__init__.py
|
|
41
|
+
quantplay/broker/kotak_utils/kotak_ws.py
|
|
42
|
+
quantplay/broker/kotak_utils/kotak_ws_lib.py
|
|
40
43
|
quantplay/broker/uplink/__init__.py
|
|
41
44
|
quantplay/broker/uplink/uplink_utils.py
|
|
42
45
|
quantplay/broker/xts_utils/Connect.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quantplay-2.0.181 → quantplay-2.0.183}/quantplay/broker/xts_utils/InteractiveSocketClient.py
RENAMED
|
File without changes
|
{quantplay-2.0.181/quantplay/core → quantplay-2.0.183/quantplay/broker/xts_utils}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|