myria-core-sdk
Version:
Latest version SDK
656 lines (649 loc) • 52.3 kB
JavaScript
import { OrderType, } from "../types/OrderTypes";
import { MyriaClient } from "../clients/MyriaClient";
import { OrderAPI } from "../core/apis/order.api";
import { CommonModule } from "./CommonModule";
import { convertAmountToQuantizedAmount } from "../utils/Converter";
import { CommonAPI } from "../core/apis";
import { TokenType } from "../types";
import { DEFAULT_QUANTUM } from "../utils";
import { TransactionManager } from "./TransactionManager";
// const StarkwareLib = require("@starkware-industries/starkware-crypto-utils");
/**
* Create OrderManager instance object
* @class OrderManager
* @param {MyriaClient} MyriaClient Interface of Myria Client
* @example <caption>Constructor for OrderManager</caption>
*
*
// Approach #1
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const moduleFactory = ModuleFactory.getInstance(mClient);
const orderManager = moduleFactory.getOrderManager();
// Approach #2
const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const myriaClient = new MyriaClient(mClient);
const orderManager = new OrderManager(myriaClient);
*/
export class OrderManager {
constructor(mClient) {
this.myriaClient = new MyriaClient(mClient);
this.orderAPI = new OrderAPI(mClient.env);
this.commonAPI = new CommonAPI(mClient.env);
this.commonModule = new CommonModule(mClient);
this.transactionManager = new TransactionManager(mClient);
}
/**
* @summary Create order V2 (supported both of listing NFTs by ETH/MYR)
* @param {CreateOrderV2Params} params Create order v2 params including the price/nft/assets information
* @returns {OrderEntity} Details order information including fees and Asset_ID_Buy/Asset_ID_Sell/AmountBuy/AmountSell
* @throws {string} Exception: Order type is required
* @throws {string} Exception: Owner wallet address is required
* @throws {string} Exception: Owner stark key is required
* @throws {string} Exception: Price must be define and must be > 0
* @throws {string} Exception: Asset Ref ID in Marketplace is required
* @throws {string} Exception: Order is only supported for MINTABLE_ERC721
* @throws {string} Exception: Token address is required for listing MINTABLE_ERC721
* @throws {string} Exception: Token ID is required for listing MINTABLE_ERC721
* @throws {string} Exception: Required the token received to be well-defined and tokenAddress is mandatory
* @throws {string} Exception: New listing method for ERC20 isn't available on Mainnet yet. Please try with Testnet only.
* @example <caption>Sample of createOrderV2({}) on Staging env</caption>
*
* const mClient: IMyriaClient = {
networkId: Network.SEPOLIA,
provider: web3Instance.currentProvider,
web3: web3Instance,
env: EnvTypes.STAGING,
};
const orderManager: OrderManager = new OrderManager(mClient);
// Define createOrderV2 params
const feeData: FeeDto[] = [
{
feeType: AssetDetailsInfo?.fee?.[0].feeType, // FeeType in asset details info
percentage: AssetDetailsInfo?.fee?.[0].feeType, // Percentage of Fee as apart of asset details info
address: AssetDetailsInfo?.fee?.[0].address, // The destination wallet address which would receive the percentage of Fee
},
];
const paramCreateOrder: CreateOrderV2Params = {
orderType: OrderType.SELL,
ownerWalletAddress: 'owner_wallet_address_that_own_nft',
ownerStarkKey: 'owner_stark_key_0x...',
assetRefId: 'Reference asset ID that intend to listing',
tokenSell: {
tokenType: TokenType.MINTABLE_ERC721,
data: {
tokenId: 'id of token',
tokenAddress: 'token address of NFT',
},
},
tokenReceived: {
tokenType: 'TokenType.ETH or TokenType.ERC20',
data: {
tokenAddress: 'token address of currency',
},
},
price: "100", // Set the price for the NFTs
fees: feeData, // Only having data or undefined
};
const createdOrderResponse: OrderEntity = await orderManager.createOrderV2(paramCreateOrder);
console.log("Order details response:");
console.log(JSON.stringify(data, null, 2));
*/
async createOrderV2(params) {
var _a, _b, _c;
if (!params.orderType) {
throw new Error("Order type is required");
}
if (!params.ownerWalletAddress) {
throw new Error("Owner wallet address is required");
}
if (!params.ownerStarkKey) {
throw new Error("Owner stark key is required");
}
if (!params.price || params.price == "0") {
throw new Error("Price must be define and must be > 0");
}
if (!params.assetRefId) {
throw new Error("Asset Ref ID in Marketplace is required");
}
if (params.tokenSell.tokenType !== TokenType.MINTABLE_ERC721) {
throw new Error("Order is only supported for MINTABLE_ERC721");
}
if (!params.tokenSell.data.tokenAddress) {
throw new Error("Token address is required for listing MINTABLE_ERC721");
}
if (!params.tokenSell.data.tokenId) {
throw new Error("Token ID is required for listing MINTABLE_ERC721");
}
if (!params.tokenReceived.data) {
throw new Error('Token Receiver is required to specify');
}
if (params.tokenReceived.tokenType !== TokenType.ETH &&
!params.tokenReceived.data.tokenAddress) {
throw new Error("Required the token received to be well-defined and tokenAddress is mandatory");
}
/**
* Disable listing myria token in Prod until services get new deployment
*/
// if ((this.myriaClient.env === EnvTypes.PREPROD || this.myriaClient.env === EnvTypes.PRODUCTION)
// && params.tokenReceived.tokenType === TokenType.ERC20) {
// throw new Error("New listing method for ERC20 isn't available on Mainnet yet. Please try with Testnet only.");
// }
const buildSignablePayload = {
orderType: params.orderType,
ethAddress: params.ownerWalletAddress,
assetRefId: params.assetRefId,
starkKey: params.ownerStarkKey,
tokenSell: {
type: params.tokenSell.tokenType,
data: params.tokenSell.data,
},
amountSell: "1",
tokenBuy: {
type: params.tokenReceived.tokenType,
data: {
quantum: DEFAULT_QUANTUM,
tokenAddress: params.tokenReceived.data.tokenAddress,
},
},
amountBuy: params.price + "",
includeFees: params.fees ? true : false,
fees: params.fees,
};
const signableData = await this.signableOrder(buildSignablePayload);
const feeSign = (signableData === null || signableData === void 0 ? void 0 : signableData.feeInfo)
? {
feeLimit: (_a = signableData === null || signableData === void 0 ? void 0 : signableData.feeInfo) === null || _a === void 0 ? void 0 : _a.feeLimit,
feeToken: (_b = signableData === null || signableData === void 0 ? void 0 : signableData.feeInfo) === null || _b === void 0 ? void 0 : _b.assetId,
feeVaultId: (_c = signableData === null || signableData === void 0 ? void 0 : signableData.feeInfo) === null || _c === void 0 ? void 0 : _c.sourceVaultId,
}
: undefined;
const feeData = (signableData === null || signableData === void 0 ? void 0 : signableData.feeInfo)
? [
{
feeType: params.fees[0].feeType,
percentage: params.fees[0].percentage,
address: params.fees[0].address,
},
]
: undefined;
if (!signableData) {
throw new Error("Exception during fetch signable order data - cant execute further operation");
}
// Check if asset type is available for listing
let isAssetIdBuySupportListing = false;
const availableAssetForListing = await this.transactionManager.getSupportedTokens();
if (availableAssetForListing.status === "success") {
availableAssetForListing.data.forEach((asset) => {
var _a;
if (asset.assetType.toLowerCase() === ((_a = signableData.assetIdBuy) === null || _a === void 0 ? void 0 : _a.toLowerCase()) && asset.isSupportListing) {
isAssetIdBuySupportListing = true;
}
});
}
else {
throw new Error("Fetch assets listing supported failed, cannot create order currently.");
}
if (!isAssetIdBuySupportListing) {
throw new Error("This currency token is not supporting for listing yet");
}
const paramCreateOrder = {
assetRefId: params.assetRefId,
orderType: params.orderType,
feeSign: feeSign,
includeFees: feeData ? true : false,
amountSell: signableData.amountSell,
amountBuy: signableData.amountBuy,
sellerStarkKey: params.ownerStarkKey,
vaultIdSell: signableData.vaultIdSell,
vaultIdBuy: signableData.vaultIdBuy,
sellerAddress: params.ownerWalletAddress,
nonce: signableData.nonce,
assetIdBuy: signableData.assetIdBuy,
assetIdSell: signableData.assetIdSell,
fees: feeData,
};
const orderResponse = await this.createOrder(paramCreateOrder);
return orderResponse;
}
async createOrder(payload) {
var _a, _b, _c, _d;
let createOrderData;
if (!payload.assetRefId) {
throw new Error("Asset reference Id is required");
}
if (!payload.sellerAddress) {
throw new Error("Seller address is not defined");
}
if (!payload.sellerStarkKey) {
throw new Error("Seller stark key is not defined");
}
if (!payload.amountBuy) {
throw new Error("Amount for buyer shoud be defined.");
}
if (!payload.amountSell) {
throw new Error("Amount for seller should be defined.");
}
if (!payload.assetIdBuy) {
throw new Error("Missing the assetIDBuy");
}
if (!payload.assetIdSell) {
throw new Error("Missing the assetIDSell");
}
if (!payload.vaultIdBuy) {
throw new Error("Missing the vaultIdBuy");
}
if (!payload.vaultIdSell) {
throw new Error("Missing the vaultIdSell");
}
// Check if asset type is available for listing
let isAssetIdBuySupportListing = false;
const availableAssetForListing = await this.transactionManager.getSupportedTokens();
if (availableAssetForListing.status === "success") {
availableAssetForListing.data.forEach((asset) => {
var _a;
if (asset.assetType.toLowerCase() === ((_a = payload.assetIdBuy) === null || _a === void 0 ? void 0 : _a.toLowerCase()) &&
asset.isSupportListing) {
isAssetIdBuySupportListing = true;
}
});
}
else {
throw new Error("Fetch assets listing supported failed, cannot create order currently.");
}
if (!isAssetIdBuySupportListing) {
throw new Error("This currency token is not supporting for listing yet");
}
// SET EXPIRATION TO BE EXPIRE IN 12 YEARS
const expirationTimestamp = new Date();
expirationTimestamp.setFullYear(expirationTimestamp.getFullYear() + 12);
const expirationTime = Math.floor(expirationTimestamp.getTime() / (3600 * 1000)).toString();
try {
// TODO - update with new API to get nonce
// const nonceByStarkKey = await this.commonAPI.getNonceByStarkKey(payload.sellerStarkKey);
const nonce = payload.nonce || Math.floor(Math.random() * 100000000) + 1;
const quantizedAmountBuy = convertAmountToQuantizedAmount(String(payload.amountBuy));
const amountBuyNonFee = quantizedAmountBuy - Number((_a = payload === null || payload === void 0 ? void 0 : payload.feeSign) === null || _a === void 0 ? void 0 : _a.feeLimit);
// console.log("Amount Buy Non Fee ->", amountBuyNonFee);
// const quantizedAmountSell = convertAmountToQuantizedAmount(payload.amountSell);
let orderPayload = {
includeFees: false,
walletAddress: "",
vaultIdSell: 0,
vaultIdBuy: 0,
amountSell: "",
amountBuy: "",
assetIdSell: "",
assetIdBuy: "",
nonce: 0,
expirationTimestamp: 0,
};
let starkSignature;
if ((payload === null || payload === void 0 ? void 0 : payload.includeFees) && (payload === null || payload === void 0 ? void 0 : payload.feeSign)) {
orderPayload = {
includeFees: true,
walletAddress: payload.sellerAddress,
vaultIdSell: payload.vaultIdSell,
vaultIdBuy: payload.vaultIdBuy,
amountSell: String(payload.amountSell),
amountBuy: String(amountBuyNonFee),
assetIdSell: payload.assetIdSell,
assetIdBuy: payload.assetIdBuy,
nonce: nonce,
expirationTimestamp: parseInt(expirationTime),
fee: {
feeLimit: (_b = payload === null || payload === void 0 ? void 0 : payload.feeSign) === null || _b === void 0 ? void 0 : _b.feeLimit,
feeToken: (_c = payload === null || payload === void 0 ? void 0 : payload.feeSign) === null || _c === void 0 ? void 0 : _c.feeToken,
feeVaultId: (_d = payload === null || payload === void 0 ? void 0 : payload.feeSign) === null || _d === void 0 ? void 0 : _d.feeVaultId,
},
};
console.log("orderPayload with fee Sign => ", orderPayload);
starkSignature =
await this.commonModule.generateStarkSignatureForOrderWithFee(orderPayload);
if (!starkSignature) {
throw new Error("Stark signature generation error ");
}
}
else {
orderPayload = {
includeFees: false,
walletAddress: payload.sellerAddress,
vaultIdSell: payload.vaultIdSell,
vaultIdBuy: payload.vaultIdBuy,
amountSell: String(payload.amountSell),
amountBuy: String(quantizedAmountBuy),
assetIdSell: payload.assetIdSell,
assetIdBuy: payload.assetIdBuy,
nonce: nonce,
expirationTimestamp: parseInt(expirationTime),
};
console.log("orderPayload => ", orderPayload);
starkSignature = await this.commonModule.generateStarkSignatureForOrder(orderPayload);
if (!starkSignature) {
throw new Error("Stark signature generation error ");
}
}
console.log("orderPayload ->", JSON.stringify(orderPayload));
const requestBody = {
assetRefId: payload.assetRefId,
quantizedAmountBuy: Number(quantizedAmountBuy),
quantizedAmountSell: payload.amountSell,
nonQuantizedAmountSell: payload.amountSell,
nonQuantizedAmountBuy: payload.amountBuy,
assetIdBuy: payload.assetIdBuy,
assetIdSell: payload.assetIdSell,
fees: payload.fees,
includeFees: payload.includeFees,
nonce: nonce,
orderType: payload.orderType,
starkKey: payload.sellerStarkKey,
vaultIdBuy: payload.vaultIdBuy,
vaultIdSell: payload.vaultIdSell,
starkSignature: starkSignature,
expirationTimestamp: expirationTime,
sellerAddress: payload.sellerAddress,
};
const createOrderRes = await this.orderAPI.createOrder(requestBody);
if ((createOrderRes === null || createOrderRes === void 0 ? void 0 : createOrderRes.status) === "success") {
createOrderData = createOrderRes === null || createOrderRes === void 0 ? void 0 : createOrderRes.data;
}
else {
throw new Error("Create Orders failure");
}
}
catch (err) {
throw new Error(err);
}
return createOrderData;
}
async signableOrder(payload) {
if (!payload.orderType) {
throw new Error("One field is missing: orderType");
}
if (payload.includeFees && !payload.assetRefId) {
throw new Error("Missing asset ref id for fee");
}
if (!payload.ethAddress) {
throw new Error("One field is missing: ethAddress");
}
if (!payload.starkKey) {
throw new Error("One field is missing: starkKey");
}
if (!payload.tokenSell) {
throw new Error("One field is missing: tokenSell");
}
if (!payload.amountSell) {
throw new Error("One field is missing: amountSell");
}
if (!payload.tokenBuy) {
throw new Error("One field is missing: tokenBuy");
}
if (!payload.amountBuy) {
throw new Error("One field is missing: amountBuy");
}
try {
const response = await this.orderAPI.signableOrder(payload);
if (response.status === "success") {
return response.data;
}
else {
throw new Error("Creaate signable order failed!");
}
}
catch (err) {
throw new Error(err);
}
}
async getOrders() {
let ordersData;
try {
const getOrdersRes = await this.orderAPI.getOrders();
if (getOrdersRes) {
ordersData = getOrdersRes;
}
else {
throw new Error("Get Orders failed!");
}
}
catch (err) {
throw new Error(err);
}
return ordersData;
}
async getOrderById(payload) {
let orderByIdData;
if (payload.id) {
try {
const orderByIdResponse = await this.orderAPI.getOrderById(payload);
if (orderByIdResponse) {
orderByIdData = orderByIdResponse;
}
else {
throw new Error("Get Order By Id failed!");
}
}
catch (err) {
throw new Error(err);
}
}
else {
throw new Error("Id shoud be provided.");
}
return orderByIdData;
}
async deleteOrderById(payload) {
let deletedOrder;
const orderDetails = await this.orderAPI.getOrderById({
id: payload.orderId,
});
console.log("[Core-SDK] order details", JSON.stringify(orderDetails));
if (!payload.orderId) {
throw new Error("One field is missing: orderId");
}
if (!payload.sellerWalletAddress) {
throw new Error("One field is missing: sellerWalletAddress");
}
try {
const orderHashPayload = {
vaultIdSell: 0,
vaultIdBuy: 0,
amountBuy: "0",
amountSell: "0",
assetIdSell: orderDetails.assetIdSell,
assetIdBuy: orderDetails.assetIdBuy,
nonce: orderDetails.nonce,
expirationTimestamp: 0,
includeFees: false,
walletAddress: payload.sellerWalletAddress,
};
console.log("[Core-SDK] order hash payload ->", JSON.stringify(orderHashPayload));
const starkSignature = await this.commonModule.generateStarkSignatureForOrder(orderHashPayload);
const requestPayload = {
orderId: payload.orderId,
nonce: orderDetails.nonce,
signature: starkSignature,
};
const deleteOrderRes = await this.orderAPI.deleteOrderById(requestPayload);
if (deleteOrderRes) {
deletedOrder = deleteOrderRes;
}
else {
throw new Error("Delete Order failed!");
}
}
catch (err) {
throw new Error(err);
}
return deletedOrder;
}
async updateOrderPrice(orderId, payload) {
var _a, _b, _c;
let orderData;
if (!orderId) {
throw new Error("One field is missing: orderId");
}
const currentOrder = await this.orderAPI.getOrderById({
id: Number(orderId),
});
if (!currentOrder.assetIdBuy) {
throw new Error("One field is missing: assetIdBuy");
}
if (!currentOrder.assetIdSell) {
throw new Error("One field is missing: assetIdSell");
}
if (!payload.newAmountBuy || Number(payload.newAmountBuy) == 0) {
throw new Error("New amount should be defined and greater 0");
}
if (!payload.sellerWalletAddress) {
throw new Error("WalletAddress should be provided.");
}
if (!payload.sellerStarkKey) {
throw new Error("Seller starkKey is required!");
}
if (!payload.tokenBuy) {
throw new Error('Token buy is required');
}
else if (payload.tokenBuy.type === TokenType.ERC20 && !payload.tokenBuy.data.tokenAddress) {
throw new Error("Token buy with ERC20 is required token address");
}
if (!payload.tokenSell) {
throw new Error("Token sell is required");
}
else if (payload.tokenSell.type !== TokenType.MINTABLE_ERC721) {
throw new Error("Only support sell MINTABLE_ERC721 tokens for now");
}
const newQuantizedAmountBuy = String(convertAmountToQuantizedAmount(payload.newAmountBuy));
// Get signable order
const buildSignablePayload = {
orderType: OrderType.SELL,
ethAddress: payload.sellerWalletAddress,
assetRefId: currentOrder.assetRefId,
starkKey: payload.sellerStarkKey,
tokenSell: {
type: TokenType.MINTABLE_ERC721,
data: {
tokenAddress: payload.tokenSell.data.tokenAddress,
tokenId: payload.tokenSell.data.tokenId,
},
},
amountSell: "1",
tokenBuy: {
type: payload.tokenBuy.type,
data: {
quantum: DEFAULT_QUANTUM,
tokenAddress: payload.tokenBuy.data.tokenAddress,
},
},
amountBuy: payload.newAmountBuy + "",
includeFees: payload.fees ? true : false,
fees: payload.fees,
};
const signableData = await this.signableOrder(buildSignablePayload);
try {
// get expirationTimestamp
let expiredAt;
expiredAt = new Date();
expiredAt.setFullYear(expiredAt.getFullYear() + 12);
expiredAt = Math.floor(expiredAt.getTime() / 3600 / 1000);
// TODO - update with new API to get nonce
// const nonceByStarkKey = await this.commonAPI.getNonceByStarkKey(payload.sellerStarkKey);
const nonceData = payload.nonce || Math.floor(Math.random() * 100000000) + 1;
let sellOrderMsg;
// stark signature of created sell order
let starkSignatureSell;
if ((buildSignablePayload === null || buildSignablePayload === void 0 ? void 0 : buildSignablePayload.includeFees) && (signableData === null || signableData === void 0 ? void 0 : signableData.feeInfo)) {
const amountBuyNonFee = Number(newQuantizedAmountBuy) - Number(signableData.feeInfo.feeLimit);
sellOrderMsg = {
includeFees: true,
walletAddress: payload.sellerWalletAddress,
vaultIdSell: signableData.vaultIdSell,
vaultIdBuy: signableData.vaultIdBuy,
amountSell: String(signableData.amountSell),
amountBuy: String(amountBuyNonFee),
assetIdSell: signableData.assetIdSell,
assetIdBuy: signableData.assetIdBuy,
nonce: (_a = signableData.nonce) !== null && _a !== void 0 ? _a : Number(nonceData),
expirationTimestamp: Number(expiredAt),
fee: {
feeLimit: signableData.feeInfo.feeLimit,
feeToken: signableData.feeInfo.assetId,
feeVaultId: signableData.feeInfo.sourceVaultId,
},
};
starkSignatureSell = await this.commonModule.generateStarkSignatureForOrderWithFee(sellOrderMsg);
}
else {
sellOrderMsg = {
includeFees: false,
walletAddress: payload.sellerWalletAddress,
vaultIdSell: currentOrder.vaultIdSell,
vaultIdBuy: currentOrder.vaultIdBuy,
amountSell: String(currentOrder.amountSell),
amountBuy: newQuantizedAmountBuy,
assetIdSell: currentOrder.assetIdSell,
assetIdBuy: currentOrder.assetIdBuy,
nonce: (_b = signableData.nonce) !== null && _b !== void 0 ? _b : Number(nonceData),
expirationTimestamp: expiredAt,
};
starkSignatureSell = await this.commonModule.generateStarkSignatureForOrder(sellOrderMsg);
}
console.log("orderPayload ->", JSON.stringify(sellOrderMsg));
// stark signature of sell order which is going to be canceled
const cancelOrderMsg = {
includeFees: false,
walletAddress: payload.sellerWalletAddress,
vaultIdBuy: 0,
vaultIdSell: 0,
amountBuy: "0",
amountSell: "0",
assetIdBuy: currentOrder.assetIdBuy,
assetIdSell: currentOrder.assetIdSell,
nonce: currentOrder.nonce,
expirationTimestamp: 0,
};
const starkSignatureCancel = await this.commonModule.generateStarkSignatureForOrder(cancelOrderMsg);
if (payload.expirationTimestamp) {
expiredAt = payload.expirationTimestamp;
}
if (starkSignatureCancel && starkSignatureSell) {
const upatePricePayload = {
expirationTimestamp: expiredAt,
newAmountBuy: newQuantizedAmountBuy,
nonQuantizedAmountBuy: payload.newAmountBuy,
nonce: (_c = signableData.nonce) !== null && _c !== void 0 ? _c : Number(nonceData),
starkKey: payload.sellerStarkKey,
starkSignatureCancelOrder: starkSignatureCancel,
starkSignatureSellOrder: starkSignatureSell,
nonQuantizedAmountSell: "1",
orderType: OrderType.SELL,
includeFees: sellOrderMsg.includeFees,
fees: payload.fees
};
const orderRes = await this.orderAPI.requestUpdateOrderPrice(orderId, upatePricePayload);
if ((orderRes === null || orderRes === void 0 ? void 0 : orderRes.status) === "success") {
orderData = orderRes === null || orderRes === void 0 ? void 0 : orderRes.data;
}
else {
throw new Error("Update Order Price failure");
}
}
else {
throw new Error("Signaturing Error!");
}
}
catch (error) {
throw new Error(error);
}
return orderData;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT3JkZXJNYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL21vZHVsZXMvT3JkZXJNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFLTCxTQUFTLEdBS1YsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQWdCLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ25FLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQVNsRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFOUMsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDcEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDM0MsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFMUQsZ0ZBQWdGO0FBRWhGOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNEJHO0FBQ0gsTUFBTSxPQUFPLFlBQVk7SUFTdkIsWUFBWSxPQUFxQjtRQUMvQixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzFDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksa0JBQWtCLENBQUMsT0FBTyxD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