@dydxprotocol/v4-client-js 1.17.0 → 1.18.0
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.
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# [1.
|
|
1
|
+
# [1.18.0](https://github.com/dydxprotocol/v4-clients/compare/v4-client-js@1.17.0...v4-client-js@1.18.0) (2025-02-12)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Features
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* add crossed orderbook resolving example using websocket ([#301](https://github.com/dydxprotocol/v4-clients/issues/301)) ([88aabad](https://github.com/dydxprotocol/v4-clients/commit/88aabadc23deb0401fa8a6fb9e08826cbba09197))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const constants_1 = require("../src/clients/constants");
|
|
4
|
+
const socket_client_1 = require("../src/clients/socket-client");
|
|
5
|
+
function test() {
|
|
6
|
+
let orderBookBidList = [];
|
|
7
|
+
let orderBookAskList = [];
|
|
8
|
+
const mySocket = new socket_client_1.SocketClient(constants_1.Network.mainnet().indexerConfig, () => {
|
|
9
|
+
console.log('socket opened');
|
|
10
|
+
mySocket.subscribeToOrderbook('ETH-USD');
|
|
11
|
+
}, () => {
|
|
12
|
+
console.log('socket closed');
|
|
13
|
+
}, (message) => {
|
|
14
|
+
try {
|
|
15
|
+
if (typeof message.data === "string") {
|
|
16
|
+
const jsonString = message.data;
|
|
17
|
+
const parsingData = JSON.parse(jsonString);
|
|
18
|
+
const messageId = parsingData.message_id;
|
|
19
|
+
const orderBookDataList = parsingData.contents;
|
|
20
|
+
if (orderBookDataList instanceof Array) {
|
|
21
|
+
// common orderBook data;
|
|
22
|
+
[orderBookBidList, orderBookAskList] = updateOrderBook(orderBookDataList, orderBookBidList, orderBookAskList, messageId);
|
|
23
|
+
// sort
|
|
24
|
+
orderBookBidList = sortByNthElementDesc(orderBookBidList, 0);
|
|
25
|
+
orderBookAskList = sortByNthElementAsc(orderBookAskList, 0);
|
|
26
|
+
// resolving crossed orderBook
|
|
27
|
+
if (orderBookBidList &&
|
|
28
|
+
orderBookAskList &&
|
|
29
|
+
orderBookBidList.length > 0 &&
|
|
30
|
+
orderBookAskList.length > 0 &&
|
|
31
|
+
orderBookBidList[0][0] >= orderBookAskList[0][0]) {
|
|
32
|
+
[orderBookBidList, orderBookAskList] =
|
|
33
|
+
resolveCrossedOrderBook(orderBookBidList, orderBookAskList);
|
|
34
|
+
}
|
|
35
|
+
printOrderBook(orderBookBidList, orderBookAskList);
|
|
36
|
+
if (orderBookBidList.length > 300) {
|
|
37
|
+
orderBookBidList.splice(50);
|
|
38
|
+
}
|
|
39
|
+
if (orderBookAskList.length > 300) {
|
|
40
|
+
orderBookAskList.splice(50);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (orderBookDataList !== null &&
|
|
44
|
+
orderBookDataList !== undefined) {
|
|
45
|
+
// initial OrderBook data
|
|
46
|
+
setInitialOrderBook(orderBookDataList, orderBookBidList, orderBookAskList, messageId);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
console.error('Error parsing JSON message:', e);
|
|
52
|
+
}
|
|
53
|
+
}, (event) => {
|
|
54
|
+
console.error('Encountered error:', event.message);
|
|
55
|
+
});
|
|
56
|
+
mySocket.connect();
|
|
57
|
+
}
|
|
58
|
+
const sortByNthElementAsc = (arr, n) => {
|
|
59
|
+
return arr.sort((a, b) => {
|
|
60
|
+
if (a[n] < b[n])
|
|
61
|
+
return -1;
|
|
62
|
+
if (a[n] > b[n])
|
|
63
|
+
return 1;
|
|
64
|
+
return 0;
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
const sortByNthElementDesc = (arr, n) => {
|
|
68
|
+
return arr.sort((a, b) => {
|
|
69
|
+
if (a[n] > b[n])
|
|
70
|
+
return -1;
|
|
71
|
+
if (a[n] < b[n])
|
|
72
|
+
return 1;
|
|
73
|
+
return 0;
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const printOrderBook = (orderBookBidList, orderBookAskList) => {
|
|
77
|
+
// print
|
|
78
|
+
console.log(`OrderBook for ETH-USD:`);
|
|
79
|
+
console.log(`Price Qty`);
|
|
80
|
+
for (let i = 4; i > -1; i--) {
|
|
81
|
+
const priceStr = String(orderBookAskList[i][0]);
|
|
82
|
+
const spaces = createSpaces(10 - priceStr.length);
|
|
83
|
+
console.log(`${priceStr}${spaces}${orderBookAskList[i][1]}`);
|
|
84
|
+
}
|
|
85
|
+
console.log('---------------------');
|
|
86
|
+
for (let i = 0; i < 5; i++) {
|
|
87
|
+
const priceStr = String(orderBookBidList[i][0]);
|
|
88
|
+
const spaces = createSpaces(10 - priceStr.length);
|
|
89
|
+
console.log(`${priceStr}${spaces}${orderBookBidList[i][1]}`);
|
|
90
|
+
}
|
|
91
|
+
console.log('');
|
|
92
|
+
};
|
|
93
|
+
function createSpaces(count) {
|
|
94
|
+
if (count <= 0) {
|
|
95
|
+
return "";
|
|
96
|
+
}
|
|
97
|
+
let spaces = "";
|
|
98
|
+
for (let i = 0; i < count; i++) {
|
|
99
|
+
spaces += " ";
|
|
100
|
+
}
|
|
101
|
+
return spaces;
|
|
102
|
+
}
|
|
103
|
+
const resolveCrossedOrderBook = (orderBookBidList, orderBookAskList) => {
|
|
104
|
+
while (orderBookBidList[0][0] >= orderBookAskList[0][0]) {
|
|
105
|
+
if (orderBookBidList[0][2] < orderBookAskList[0][2]) {
|
|
106
|
+
orderBookBidList.shift();
|
|
107
|
+
}
|
|
108
|
+
else if (orderBookBidList[0][2] > orderBookAskList[0][2]) {
|
|
109
|
+
orderBookAskList.shift();
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
if (orderBookBidList[0][1] > orderBookAskList[0][1]) {
|
|
113
|
+
orderBookBidList[0][1] -= orderBookAskList[0][1];
|
|
114
|
+
orderBookAskList.shift();
|
|
115
|
+
}
|
|
116
|
+
else if (orderBookBidList[0][1] < orderBookAskList[0][1]) {
|
|
117
|
+
orderBookAskList[0][1] -= orderBookBidList[0][1];
|
|
118
|
+
orderBookBidList.shift();
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
orderBookAskList.shift();
|
|
122
|
+
orderBookBidList.shift();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return [orderBookBidList, orderBookAskList];
|
|
127
|
+
};
|
|
128
|
+
const setInitialOrderBook = (orderBookDataList, orderBookBidList, orderBookAskList, messageId) => {
|
|
129
|
+
orderBookDataList.bids.forEach((item) => {
|
|
130
|
+
orderBookBidList.push([Number(item.price), Number(item.size), messageId]);
|
|
131
|
+
});
|
|
132
|
+
orderBookDataList.asks.forEach((item) => {
|
|
133
|
+
orderBookAskList.push([Number(item.price), Number(item.size), messageId]);
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
const updateOrderBook = (orderBookDataList, orderBookBidList, orderBookAskList, messageId) => {
|
|
137
|
+
orderBookDataList.forEach((entry) => {
|
|
138
|
+
if (entry.bids !== null && entry.bids !== undefined) {
|
|
139
|
+
const flattened = entry.bids.reduce((acc, val) => acc.concat(val), []);
|
|
140
|
+
const entryBidPrice = Number(flattened[0]);
|
|
141
|
+
const entryBidSize = Number(flattened[1]);
|
|
142
|
+
// remove prices with zero Qty
|
|
143
|
+
if (entryBidSize === 0) {
|
|
144
|
+
for (let i = orderBookBidList.length - 1; i >= 0; i--) {
|
|
145
|
+
if (orderBookBidList[i][0] === entryBidPrice) {
|
|
146
|
+
orderBookBidList.splice(i, 1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// The price that already exists in the order book is modified only Qty
|
|
152
|
+
if (orderBookBidList.some((innerArray) => innerArray[0] === entryBidPrice)) {
|
|
153
|
+
orderBookBidList.forEach((item, index) => {
|
|
154
|
+
if (item[0] === entryBidPrice) {
|
|
155
|
+
orderBookBidList[index][1] = entryBidSize;
|
|
156
|
+
orderBookBidList[index][2] = messageId;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// Add new data to order book
|
|
162
|
+
orderBookBidList.push([entryBidPrice, entryBidSize, messageId]);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (entry.asks !== null && entry.asks !== undefined) {
|
|
167
|
+
const flattened = entry.asks.reduce((acc, val) => acc.concat(val), []);
|
|
168
|
+
const entryAskPrice = Number(flattened[0]);
|
|
169
|
+
const entryAskSize = Number(flattened[1]);
|
|
170
|
+
if (entryAskSize === 0) {
|
|
171
|
+
// remove prices with zero Qty
|
|
172
|
+
for (let i = orderBookAskList.length - 1; i >= 0; i--) {
|
|
173
|
+
if (orderBookAskList[i][0] === entryAskPrice) {
|
|
174
|
+
orderBookAskList.splice(i, 1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// The price that already exists in the order book is modified only Qty
|
|
180
|
+
if (orderBookAskList.some((innerArray) => innerArray[0] === entryAskPrice)) {
|
|
181
|
+
orderBookAskList.forEach((item, index) => {
|
|
182
|
+
if (item[0] === entryAskPrice) {
|
|
183
|
+
orderBookAskList[index][1] = entryAskSize;
|
|
184
|
+
orderBookAskList[index][2] = messageId;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// Add new data to order book
|
|
190
|
+
orderBookAskList.push([entryAskPrice, entryAskSize, messageId]);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return [orderBookBidList, orderBookAskList];
|
|
196
|
+
};
|
|
197
|
+
test();
|
|
198
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0X29yZGVyYm9va19leGFtcGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vZXhhbXBsZXMvd2Vic29ja2V0X29yZGVyYm9va19leGFtcGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsd0RBQW1EO0FBQ25ELGdFQUE0RDtBQUU1RCxTQUFTLElBQUk7SUFDVCxJQUFJLGdCQUFnQixHQUErQixFQUFFLENBQUM7SUFDdEQsSUFBSSxnQkFBZ0IsR0FBK0IsRUFBRSxDQUFDO0lBRXRELE1BQU0sUUFBUSxHQUFHLElBQUksNEJBQVksQ0FDN0IsbUJBQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxhQUFhLEVBQy9CLEdBQUcsRUFBRTtRQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFN0IsUUFBUSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzdDLENBQUMsRUFDRCxHQUFHLEVBQUU7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQ2pDLENBQUMsRUFDRCxDQUFDLE9BQU8sRUFBRSxFQUFFO1FBQ1IsSUFBSTtZQUNBLElBQUksT0FBTyxPQUFPLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRTtnQkFDbEMsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDaEMsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDM0MsTUFBTSxTQUFTLEdBQUcsV0FBVyxDQUFDLFVBQVUsQ0FBQztnQkFDekMsTUFBTSxpQkFBaUIsR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDO2dCQUUvQyxJQUFJLGlCQUFpQixZQUFZLEtBQUssRUFBRTtvQkFDcEMseUJBQXlCO29CQUN6QixDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLEdBQUcsZUFBZSxDQUNsRCxpQkFBaUIsRUFDakIsZ0JBQWdCLEVBQ2hCLGdCQUFnQixFQUNoQixTQUFTLENBQ1osQ0FBQztvQkFFRixPQUFPO29CQUNQLGdCQUFnQixHQUFHLG9CQUFvQixDQUNuQyxnQkFBZ0IsRUFDaEIsQ0FBQyxDQUNKLENBQUM7b0JBQ0YsZ0JBQWdCLEdBQUcsbUJBQW1CLENBQ2xDLGdCQUFnQixFQUNoQixDQUFDLENBQ0osQ0FBQztvQkFFRiw4QkFBOEI7b0JBQzlCLElBQ0ksZ0JBQWdCO3dCQUNoQixnQkFBZ0I7d0JBQ2hCLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxDQUFDO3dCQUMzQixnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQzt3QkFDM0IsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQ2xEO3dCQUNFLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUM7NEJBQ2hDLHVCQUF1QixDQUNuQixnQkFBZ0IsRUFDaEIsZ0JBQWdCLENBQ25CLENBQUM7cUJBQ1Q7b0JBRUQsY0FBYyxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLENBQUM7b0JBRW5ELElBQUksZ0JBQWdCLENBQUMsTUFBTSxHQUFHLEdBQUcsRUFBRTt3QkFDL0IsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO3FCQUMvQjtvQkFFRCxJQUFJLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxHQUFHLEVBQUU7d0JBQy9CLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztxQkFDL0I7aUJBQ0o7cUJBQU0sSUFDSCxpQkFBaUIsS0FBSyxJQUFJO29CQUMxQixpQkFBaUIsS0FBSyxTQUFTLEVBQ2pDO29CQUNFLHlCQUF5QjtvQkFDekIsbUJBQW1CLENBQ2YsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQixnQkFBZ0IsRUFDaEIsU0FBUyxDQUNaLENBQUM7aUJBQ0w7YUFDSjtTQUNKO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDUixPQUFPLENBQUMsS0FBSyxDQUFDLDZCQUE2QixFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQ25EO0lBQ0wsQ0FBQyxFQUNELENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDTixPQUFPLENBQUMsS0FBSyxDQUFDLG9CQUFvQixFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN2RCxDQUFDLENBQ0osQ0FBQztJQUVGLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUN2QixDQUFDO0FBRUQsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLEdBQStCLEVBQUUsQ0FBUyxFQUE4QixFQUFFO0lBQ25HLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNyQixJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUMzQixJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUUsT0FBTyxDQUFDLENBQUM7UUFDMUIsT0FBTyxDQUFDLENBQUM7SUFDYixDQUFDLENBQUMsQ0FBQztBQUNQLENBQUMsQ0FBQztBQUNGLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUErQixFQUFFLENBQVMsRUFBOEIsRUFBRTtJQUNwRyxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDckIsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDM0IsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzFCLE9BQU8sQ0FBQyxDQUFDO0lBQ2IsQ0FBQyxDQUFDLENBQUM7QUFDUCxDQUFDLENBQUM7QUFFRixNQUFNLGNBQWMsR0FBRyxDQUNuQixnQkFBNEMsRUFDNUMsZ0JBQTRDLEVBQ3hDLEVBQUU7SUFDTixRQUFRO0lBQ1IsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQ3RDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDN0IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3pCLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxFQUFFLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2xELE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxRQUFRLEdBQUcsTUFBTSxHQUFHLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztLQUNoRTtJQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLENBQUMsQ0FBQztJQUNyQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3hCLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxFQUFFLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2xELE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxRQUFRLEdBQUcsTUFBTSxHQUFHLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztLQUNoRTtJQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDcEIsQ0FBQyxDQUFDO0FBRUYsU0FBUyxZQUFZLENBQUMsS0FBYTtJQUMvQixJQUFHLEtBQUssSUFBSSxDQUFDLEVBQUU7UUFDWCxPQUFPLEVBQUUsQ0FBQztLQUNiO0lBRUQsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO0lBQ2hCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDNUIsTUFBTSxJQUFJLEdBQUcsQ0FBQztLQUNqQjtJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2xCLENBQUM7QUFFRCxNQUFNLHVCQUF1QixHQUFHLENBQzVCLGdCQUE0QyxFQUM1QyxnQkFBNEMsRUFDWSxFQUFFO0lBQzFELE9BQU8sZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7UUFDckQsSUFBSSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUNqRCxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsQ0FBQztTQUM1QjthQUFNLElBQUksZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7WUFDeEQsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLENBQUM7U0FDNUI7YUFBTTtZQUNILElBQUksZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ2pELGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNqRCxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsQ0FBQzthQUM1QjtpQkFBTSxJQUFJLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUN4RCxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDakQsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLENBQUM7YUFDNUI7aUJBQU07Z0JBQ0gsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3pCLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO2FBQzVCO1NBQ0o7S0FDSjtJQUVELE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0FBQ2hELENBQUMsQ0FBQztBQUNGLE1BQU0sbUJBQW1CLEdBQUcsQ0FDeEIsaUJBQXlDLEVBQ3pDLGdCQUE0QyxFQUM1QyxnQkFBNEMsRUFDNUMsU0FBaUIsRUFDYixFQUFFO0lBQ04saUJBQWlCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQXFDLEVBQUUsRUFBRTtRQUNyRSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUM5RSxDQUFDLENBQUMsQ0FBQztJQUVILGlCQUFpQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFxQyxFQUFFLEVBQUU7UUFDckUsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDOUUsQ0FBQyxDQUFDLENBQUM7QUFDUCxDQUFDLENBQUM7QUFFRixNQUFNLGVBQWUsR0FBRyxDQUNwQixpQkFBK0MsRUFDL0MsZ0JBQTRDLEVBQzVDLGdCQUE0QyxFQUM1QyxTQUFpQixFQUN1QyxFQUFFO0lBQzFELGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQWlDLEVBQUUsRUFBRTtRQUM1RCxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssSUFBSSxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssU0FBUyxFQUFFO1lBQ2pELE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBVSxFQUFFLEdBQVUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNyRixNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0MsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTFDLDhCQUE4QjtZQUM5QixJQUFJLFlBQVksS0FBSyxDQUFDLEVBQUU7Z0JBQ3BCLEtBQUssSUFBSSxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO29CQUNuRCxJQUFJLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLGFBQWEsRUFBRTt3QkFDMUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztxQkFDakM7aUJBQ0o7YUFDSjtpQkFBTTtnQkFDSCx1RUFBdUU7Z0JBQ3ZFLElBQ0ksZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssYUFBYSxDQUFDLEVBQ3hFO29CQUNFLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRTt3QkFDckMsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssYUFBYSxFQUFFOzRCQUMzQixnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxZQUFZLENBQUM7NEJBQzFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLFNBQVMsQ0FBQzt5QkFDMUM7b0JBQ0wsQ0FBQyxDQUFDLENBQUM7aUJBQ047cUJBQU07b0JBQ0gsNkJBQTZCO29CQUM3QixnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxhQUFhLEVBQUUsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7aUJBQ25FO2FBQ0o7U0FDSjtRQUNELElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxJQUFJLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUU7WUFDakQsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFVLEVBQUUsR0FBVSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3JGLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMzQyxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFMUMsSUFBSSxZQUFZLEtBQUssQ0FBQyxFQUFFO2dCQUNwQiw4QkFBOEI7Z0JBQzlCLEtBQUssSUFBSSxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO29CQUNuRCxJQUFJLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLGFBQWEsRUFBRTt3QkFDMUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztxQkFDakM7aUJBQ0o7YUFDSjtpQkFBTTtnQkFDSCx1RUFBdUU7Z0JBQ3ZFLElBQ0ksZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssYUFBYSxDQUFDLEVBQ3hFO29CQUNFLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRTt3QkFDckMsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssYUFBYSxFQUFFOzRCQUMzQixnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxZQUFZLENBQUM7NEJBQzFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLFNBQVMsQ0FBQzt5QkFDMUM7b0JBQ0wsQ0FBQyxDQUFDLENBQUM7aUJBQ047cUJBQU07b0JBQ0gsNkJBQTZCO29CQUM3QixnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxhQUFhLEVBQUUsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7aUJBQ25FO2FBQ0o7U0FDSjtJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsT0FBTyxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLENBQUM7QUFDaEQsQ0FBQyxDQUFDO0FBRUYsSUFBSSxFQUFFLENBQUMifQ==
|