UNPKG

myria-core-sdk

Version:

Latest version SDK

656 lines (649 loc) 52.3 kB
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT3JkZXJNYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL21vZHVsZXMvT3JkZXJNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFLTCxTQUFTLEdBS1YsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQWdCLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ25FLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQVNsRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFOUMsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDcEUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDM0MsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFMUQsZ0ZBQWdGO0FBRWhGOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNEJHO0FBQ0gsTUFBTSxPQUFPLFlBQVk7SUFTdkIsWUFBWSxPQUFxQjtRQUMvQixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzFDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQTJERztJQUNJLEtBQUssQ0FBQyxhQUFhLENBQ3hCLE1BQTJCOztRQUUzQixJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixDQUFDLENBQUM7U0FDM0M7UUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFO1lBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsa0NBQWtDLENBQUMsQ0FBQztTQUNyRDtRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztTQUNoRDtRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLE1BQU0sQ0FBQyxLQUFLLElBQUksR0FBRyxFQUFFO1lBQ3hDLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztTQUN6RDtRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO1lBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMseUNBQXlDLENBQUMsQ0FBQztTQUM1RDtRQUNELElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFDLGVBQWUsRUFBRTtZQUM1RCxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7U0FDaEU7UUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFO1lBQ3ZDLE1BQU0sSUFBSSxLQUFLLENBQUMsdURBQXVELENBQUMsQ0FBQztTQUMxRTtRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDbEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxrREFBa0QsQ0FBQyxDQUFDO1NBQ3JFO1FBRUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFO1lBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQztTQUMxRDtRQUVELElBQ0UsTUFBTSxDQUFDLGFBQWEsQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFDLEdBQUc7WUFDaEQsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQ3ZDO1lBQ0EsTUFBTSxJQUFJLEtBQUssQ0FDYiw4RUFBOEUsQ0FDL0UsQ0FBQztTQUNIO1FBRUQ7O1dBRUc7UUFDSCxrR0FBa0c7UUFDbEcsNkRBQTZEO1FBQzdELHFIQUFxSDtRQUNySCxJQUFJO1FBRUosTUFBTSxvQkFBb0IsR0FBdUI7WUFDL0MsU0FBUyxFQUFFLE1BQU0sQ0FBQyxTQUFTO1lBQzNCLFVBQVUsRUFBRSxNQUFNLENBQUMsa0JBQWtCO1lBQ3JDLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVTtZQUM3QixRQUFRLEVBQUUsTUFBTSxDQUFDLGFBQWE7WUFDOUIsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLFNBQVM7Z0JBQ2hDLElBQUksRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUk7YUFDNUI7WUFDRCxVQUFVLEVBQUUsR0FBRztZQUNmLFFBQVEsRUFBRTtnQkFDUixJQUFJLEVBQUUsTUFBTSxDQUFDLGFBQWEsQ0FBQyxTQUFTO2dCQUNwQyxJQUFJLEVBQUU7b0JBQ0osT0FBTyxFQUFFLGVBQWU7b0JBQ3hCLFlBQVksRUFBRSxNQUFNLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxZQUFZO2lCQUNyRDthQUNGO1lBQ0QsU0FBUyxFQUFFLE1BQU0sQ0FBQyxLQUFLLEdBQUcsRUFBRTtZQUM1QixXQUFXLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLO1lBQ3ZDLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtTQUNsQixDQUFDO1FBRUYsTUFBTSxZQUFZLEdBQThCLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FDdEUsb0JBQW9CLENBQ3JCLENBQUM7UUFDRixNQUFNLE9BQU8sR0FBRyxDQUFBLFlBQVksYUFBWixZQUFZLHVCQUFaLFlBQVksQ0FBRSxPQUFPO1lBQ25DLENBQUMsQ0FBQztnQkFDRSxRQUFRLEVBQUUsTUFBQSxZQUFZLGFBQVosWUFBWSx1QkFBWixZQUFZLENBQUUsT0FBTywwQ0FBRSxRQUFRO2dCQUN6QyxRQUFRLEVBQUUsTUFBQSxZQUFZLGFBQVosWUFBWSx1QkFBWixZQUFZLENBQUUsT0FBTywwQ0FBRSxPQUFPO2dCQUN4QyxVQUFVLEVBQUUsTUFBQSxZQUFZLGFBQVosWUFBWSx1QkFBWixZQUFZLENBQUUsT0FBTywwQ0FBRSxhQUFhO2FBQ2pEO1lBQ0gsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUVkLE1BQU0sT0FBTyxHQUFHLENBQUEsWUFBWSxhQUFaLFlBQVksdUJBQVosWUFBWSxDQUFFLE9BQU87WUFDbkMsQ0FBQyxDQUFDO2dCQUNFO29CQUNFLE9BQU8sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU87b0JBQy9CLFVBQVUsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVU7b0JBQ3JDLE9BQU8sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU87aUJBQ2hDO2FBQ0Y7WUFDSCxDQUFDLENBQUMsU0FBUyxDQUFDO1FBRWQsSUFBSSxDQUFDLFlBQVksRUFBRTtZQUNqQixNQUFNLElBQUksS0FBSyxDQUNiLDZFQUE2RSxDQUM5RSxDQUFDO1NBQ0g7UUFFRCwrQ0FBK0M7UUFDL0MsSUFBSSwwQkFBMEIsR0FBRyxLQUFLLENBQUM7UUFDdkMsTUFBTSx3QkFBd0IsR0FDNUIsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUNyRCxJQUFJLHdCQUF3QixDQUFDLE1BQU0sS0FBSyxTQUFTLEVBQUU7WUFDakQsd0JBQXdCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFOztnQkFDOUMsSUFDRSxLQUFLLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxNQUFLLE1BQUEsWUFBWSxDQUFDLFVBQVUsMENBQUUsV0FBVyxFQUFFLENBQUEsSUFBSSxLQUFLLENBQUMsZ0JBQWdCLEVBQUU7b0JBQ3BHLDBCQUEwQixHQUFHLElBQUksQ0FBQztpQkFDbkM7WUFDSCxDQUFDLENBQUMsQ0FBQztTQUNKO2FBQU07WUFDTCxNQUFNLElBQUksS0FBSyxDQUNiLHVFQUF1RSxDQUN4RSxDQUFDO1NBQ0g7UUFFRCxJQUFJLENBQUMsMEJBQTBCLEVBQUU7WUFDL0IsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1NBQzFFO1FBRUQsTUFBTSxnQkFBZ0IsR0FBc0I7WUFDMUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO1lBQzdCLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztZQUMzQixPQUFPLEVBQUUsT0FBTztZQUNoQixXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUs7WUFDbkMsVUFBVSxFQUFFLFlBQVksQ0FBQyxVQUFVO1lBQ25DLFNBQVMsRUFBRSxZQUFZLENBQUMsU0FBUztZQUNqQyxjQUFjLEVBQUUsTUFBTSxDQUFDLGFBQWE7WUFDcEMsV0FBVyxFQUFFLFlBQVksQ0FBQyxXQUFXO1lBQ3JDLFVBQVUsRUFBRSxZQUFZLENBQUMsVUFBVTtZQUNuQyxhQUFhLEVBQUUsTUFBTSxDQUFDLGtCQUFrQjtZQUN4QyxLQUFLLEVBQUUsWUFBWSxDQUFDLEtBQUs7WUFDekIsVUFBVSxFQUFFLFlBQVksQ0FBQyxVQUFVO1lBQ25DLFdBQVcsRUFBRSxZQUFZLENBQUMsV0FBVztZQUNyQyxJQUFJLEVBQUUsT0FBTztTQUNkLENBQUM7UUFDRixNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUUvRCxPQUFPLGFBQWEsQ0FBQztJQUN2QixDQUFDO0lBRU0sS0FBSyxDQUFDLFdBQVcsQ0FBQyxPQUEwQjs7UUFDakQsSUFBSSxlQUFlLENBQUM7UUFFcEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUU7WUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1NBQ25EO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUU7WUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1NBQ2xEO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUU7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1NBQ3BEO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUU7WUFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDO1NBQ3ZEO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUU7WUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1NBQ3pEO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUU7WUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1NBQzNDO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUU7WUFDeEIsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1NBQzVDO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUU7WUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1NBQzNDO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUU7WUFDeEIsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1NBQzVDO1FBRUQsK0NBQStDO1FBQy9DLElBQUksMEJBQTBCLEdBQUcsS0FBSyxDQUFDO1FBQ3ZDLE1BQU0sd0JBQXdCLEdBQzVCLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDckQsSUFBSSx3QkFBd0IsQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUFFO1lBQ2pELHdCQUF3QixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTs7Z0JBQzlDLElBQ0UsS0FBSyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsTUFBSyxNQUFBLE9BQU8sQ0FBQyxVQUFVLDBDQUFFLFdBQVcsRUFBRSxDQUFBO29CQUNuRSxLQUFLLENBQUMsZ0JBQWdCLEVBQ3RCO29CQUNBLDBCQUEwQixHQUFHLElBQUksQ0FBQztpQkFDbkM7WUFDSCxDQUFDLENBQUMsQ0FBQztTQUNKO2FBQU07WUFDTCxNQUFNLElBQUksS0FBSyxDQUNiLHVFQUF1RSxDQUN4RSxDQUFDO1NBQ0g7UUFFRCxJQUFJLENBQUMsMEJBQTBCLEVBQUU7WUFDL0IsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1NBQzFFO1FBRUQsMENBQTBDO1FBQzFDLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QyxtQkFBbUIsQ0FBQyxXQUFXLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDeEUsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FDL0IsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQzlDLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFYixJQUFJO1lBQ0YsMENBQTBDO1lBQzFDLDJGQUEyRjtZQUMzRixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUV6RSxNQUFNLGtCQUFrQixHQUFHLDhCQUE4QixDQUN2RCxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUMxQixDQUFDO1lBQ0YsTUFBTSxlQUFlLEdBQ25CLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxNQUFBLE9BQU8sYUFBUCxPQUFPLHVCQUFQLE9BQU8sQ0FBRSxPQUFPLDBDQUFFLFFBQVEsQ0FBQyxDQUFDO1lBRTFELHlEQUF5RDtZQUN6RCxrRkFBa0Y7WUFFbEYsSUFBSSxZQUFZLEdBQWtCO2dCQUNoQyxXQUFXLEVBQUUsS0FBSztnQkFDbEIsYUFBYSxFQUFFLEVBQUU7Z0JBQ2pCLFdBQVcsRUFBRSxDQUFDO2dCQUNkLFVBQVUsRUFBRSxDQUFDO2dCQUNiLFVBQVUsRUFBRSxFQUFFO2dCQUNkLFNBQVMsRUFBRSxFQUFFO2dCQUNiLFdBQVcsRUFBRSxFQUFFO2dCQUNmLFVBQVUsRUFBRSxFQUFFO2dCQUNkLEtBQUssRUFBRSxDQUFDO2dCQUNSLG1CQUFtQixFQUFFLENBQUM7YUFDdkIsQ0FBQztZQUVGLElBQUksY0FBMEMsQ0FBQztZQUUvQyxJQUFJLENBQUEsT0FBTyxhQUFQLE9BQU8sdUJBQVAsT0FBTyxDQUFFLFdBQVcsTUFBSSxPQUFPLGFBQVAsT0FBTyx1QkFBUCxPQUFPLENBQUUsT0FBTyxDQUFBLEVBQUU7Z0JBQzVDLFlBQVksR0FBRztvQkFDYixXQUFXLEVBQUUsSUFBSTtvQkFDakIsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO29CQUNwQyxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVc7b0JBQ2hDLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVTtvQkFDOUIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO29CQUN0QyxTQUFTLEVBQUUsTUFBTSxDQUFDLGVBQWUsQ0FBQztvQkFDbEMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXO29CQUNoQyxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7b0JBQzlCLEtBQUssRUFBRSxLQUFLO29CQUNaLG1CQUFtQixFQUFFLFFBQVEsQ0FBQyxjQUFjLENBQUM7b0JBQzdDLEdBQUcsRUFBRTt3QkFDSCxRQUFRLEVBQUUsTUFBQSxPQUFPLGFBQVAsT0FBTyx1QkFBUCxPQUFPLENBQUUsT0FBTywwQ0FBRSxRQUFRO3dCQUNwQyxRQUFRLEVBQUUsTUFBQSxPQUFPLGFBQVAsT0FBTyx1QkFBUCxPQUFPLENBQUUsT0FBTywwQ0FBRSxRQUFRO3dCQUNwQyxVQUFVLEVBQUUsTUFBQSxPQUFPLGFBQVAsT0FBTyx1QkFBUCxPQUFPLENBQUUsT0FBTywwQ0FBRSxVQUFVO3FCQUN6QztpQkFDRixDQUFDO2dCQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLEVBQUUsWUFBWSxDQUFDLENBQUM7Z0JBQzVELGNBQWM7b0JBQ1osTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLHFDQUFxQyxDQUMzRCxZQUFZLENBQ2IsQ0FBQztnQkFDSixJQUFJLENBQUMsY0FBYyxFQUFFO29CQUNuQixNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7aUJBQ3REO2FBQ0Y7aUJBQU07Z0JBQ0wsWUFBWSxHQUFHO29CQUNiLFdBQVcsRUFBRSxLQUFLO29CQUNsQixhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWE7b0JBQ3BDLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztvQkFDaEMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVO29CQUM5QixVQUFVLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUM7b0JBQ3RDLFNBQVMsRUFBRSxNQUFNLENBQUMsa0JBQWtCLENBQUM7b0JBQ3JDLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztvQkFDaEMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVO29CQUM5QixLQUFLLEVBQUUsS0FBSztvQkFDWixtQkFBbUIsRUFBRSxRQUFRLENBQUMsY0FBYyxDQUFDO2lCQUM5QyxDQUFDO2dCQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLEVBQUUsWUFBWSxDQUFDLENBQUM7Z0JBQzlDLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsOEJBQThCLENBQ3JFLFlBQVksQ0FDYixDQUFDO2dCQUNGLElBQUksQ0FBQyxjQUFjLEVBQUU7b0JBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLENBQUMsQ0FBQztpQkFDdEQ7YUFDRjtZQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDO1lBRTdELE1BQU0sV0FBVyxHQUEwQjtnQkFDekMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVO2dCQUM5QixrQkFBa0IsRUFBRSxNQUFNLENBQUMsa0JBQWtCLENBQUM7Z0JBQzlDLG1CQUFtQixFQUFFLE9BQU8sQ0FBQyxVQUFVO2dCQUN2QyxzQkFBc0IsRUFBRSxPQUFPLENBQUMsVUFBVTtnQkFDMUMscUJBQXFCLEVBQUUsT0FBTyxDQUFDLFNBQVM7Z0JBQ3hDLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVTtnQkFDOUIsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXO2dCQUNoQyxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7Z0JBQ2xCLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztnQkFDaEMsS0FBSyxFQUFFLEtBQUs7Z0JBQ1osU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTO2dCQUM1QixRQUFRLEVBQUUsT0FBTyxDQUFDLGNBQWM7Z0JBQ2hDLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVTtnQkFDOUIsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXO2dCQUNoQyxjQUFjLEVBQUUsY0FBYztnQkFDOUIsbUJBQW1CLEVBQUUsY0FBYztnQkFDbkMsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO2FBQ3JDLENBQUM7WUFFRixNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBRXBFLElBQUksQ0FBQSxjQUFjLGFBQWQsY0FBYyx1QkFBZCxjQUFjLENBQUUsTUFBTSxNQUFLLFNBQVMsRUFBRTtnQkFDeEMsZUFBZSxHQUFHLGNBQWMsYUFBZCxjQUFjLHVCQUFkLGNBQWMsQ0FBRSxJQUFJLENBQUM7YUFDeEM7aUJBQU07Z0JBQ0wsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO2FBQzFDO1NBQ0Y7UUFBQyxPQUFPLEdBQUcsRUFBRTtZQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDdEI7UUFFRCxPQUFPLGVBQWUsQ0FBQztJQUN6QixDQUFDO0lBRU0sS0FBSyxDQUFDLGFBQWEsQ0FDeEIsT0FBMkI7UUFFM0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUU7WUFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1NBQ3BEO1FBRUQsSUFBSSxPQUFPLENBQUMsV0FBVyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRTtZQUM5QyxNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7U0FDakQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRTtZQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7U0FDckQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRTtZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7U0FDbkQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRTtZQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7U0FDcEQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRTtZQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7U0FDckQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRTtZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7U0FDbkQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRTtZQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7U0FDcEQ7UUFFRCxJQUFJO1lBQ0YsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM1RCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUFFO2dCQUNqQyxPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUM7YUFDdEI7aUJBQU07Z0JBQ0wsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO2FBQ25EO1NBQ0Y7UUFBQyxPQUFPLEdBQUcsRUFBRTtZQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDdEI7SUFDSCxDQUFDO0lBRU0sS0FBSyxDQUFDLFNBQVM7UUFDcEIsSUFBSSxVQUFVLENBQUM7UUFDZixJQUFJO1lBQ0YsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3JELElBQUksWUFBWSxFQUFFO2dCQUNoQixVQUFVLEdBQUcsWUFBWSxDQUFDO2FBQzNCO2lCQUFNO2dCQUNMLE1BQU0sSUFBSSxLQUFLLENBQUMsb0JBQW9CLENBQUMsQ0FBQzthQUN2QztTQUNGO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDWixNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3RCO1FBRUQsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVNLEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBcUI7UUFDN0MsSUFBSSxhQUFhLENBQUM7UUFDbEIsSUFBSSxPQUFPLENBQUMsRUFBRSxFQUFFO1lBQ2QsSUFBSTtnQkFDRixNQUFNLGlCQUFpQixHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3BFLElBQUksaUJBQWlCLEVBQUU7b0JBQ3JCLGFBQWEsR0FBRyxpQkFBaUIsQ0FBQztpQkFDbkM7cUJBQU07b0JBQ0wsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO2lCQUM1QzthQUNGO1lBQUMsT0FBTyxHQUFHLEVBQUU7Z0JBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQzthQUN0QjtTQUNGO2FBQU07WUFDTCxNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixDQUFDLENBQUM7U0FDMUM7UUFFRCxPQUFPLGFBQWEsQ0FBQztJQUN2QixDQUFDO0lBRU0sS0FBSyxDQUFDLGVBQWUsQ0FDMUIsT0FBMkI7UUFFM0IsSUFBSSxZQUFZLENBQUM7UUFFakIsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQztZQUNwRCxFQUFFLEVBQUUsT0FBTyxDQUFDLE9BQU87U0FDcEIsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7UUFFdEUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUU7WUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1NBQ2xEO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRTtZQUNoQyxNQUFNLElBQUksS0FBSyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7U0FDOUQ7UUFFRCxJQUFJO1lBQ0YsTUFBTSxnQkFBZ0IsR0FBa0I7Z0JBQ3RDLFdBQVcsRUFBRSxDQUFDO2dCQUNkLFVBQVUsRUFBRSxDQUFDO2dCQUNiLFNBQVMsRUFBRSxHQUFHO2dCQUNkLFVBQVUsRUFBRSxHQUFHO2dCQUNmLFdBQVcsRUFBRSxZQUFZLENBQUMsV0FBVztnQkFDckMsVUFBVSxFQUFFLFlBQVksQ0FBQyxVQUFVO2dCQUNuQyxLQUFLLEVBQUUsWUFBWSxDQUFDLEtBQUs7Z0JBQ3pCLG1CQUFtQixFQUFFLENBQUM7Z0JBQ3RCLFdBQVcsRUFBRSxLQUFLO2dCQUNsQixhQUFhLEVBQUUsT0FBTyxDQUFDLG1CQUFtQjthQUMzQyxDQUFDO1lBQ0YsT0FBTyxDQUFDLEdBQUcsQ0FDVCxrQ0FBa0MsRUFDbEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUNqQyxDQUFDO1lBQ0YsTUFBTSxjQUFjLEdBQ2xCLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyw4QkFBOEIsQ0FDcEQsZ0JBQWdCLENBQ2pCLENBQUM7WUFFSixNQUFNLGNBQWMsR0FBMEI7Z0JBQzVDLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztnQkFDeEIsS0FBSyxFQUFFLFlBQVksQ0FBQyxLQUFLO2dCQUN6QixTQUFTLEVBQUUsY0FBYzthQUMxQixDQUFDO1lBRUYsTUFBTSxjQUFjLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FDeEQsY0FBYyxDQUNmLENBQUM7WUFFRixJQUFJLGNBQWMsRUFBRTtnQkFDbEIsWUFBWSxHQUFHLGNBQWMsQ0FBQzthQUMvQjtpQkFBTTtnQkFDTCxNQUFNLElBQUksS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7YUFDekM7U0FDRjtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUN0QjtRQUVELE9BQU8sWUFBWSxDQUFDO0lBQ3RCLENBQUM7SUFFTSxLQUFLLENBQUMsZ0JBQWdCLENBQzNCLE9BQWUsRUFDZixPQUErQjs7UUFFL0IsSUFBSSxTQUFjLENBQUM7UUFFbkIsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztTQUNsRDtRQUVELE1BQU0sWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUM7WUFDcEQsRUFBRSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUM7U0FDcEIsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLEVBQUU7WUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1NBQ3JEO1FBRUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUU7WUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1NBQ3REO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDOUQsTUFBTSxJQUFJLEtBQUssQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDO1NBQy9EO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRTtZQUNoQyxNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7U0FDdEQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRTtZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7U0FDakQ7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRTtZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixDQUFDLENBQUE7U0FDekM7YUFBTSxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLFNBQVMsQ0FBQyxLQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDM0YsTUFBTSxJQUFJLEtBQUssQ0FBRSxnREFBZ0QsQ0FBQyxDQUFDO1NBQ3BFO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUU7WUFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1NBQzNDO2FBQU0sSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksS0FBSyxTQUFTLENBQUMsZUFBZSxFQUFFO1lBQy9ELE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztTQUNyRTtRQUVELE1BQU0scUJBQXFCLEdBQUcsTUFBTSxDQUNsQyw4QkFBOEIsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQ3JELENBQUM7UUFFRixxQkFBcUI7UUFDckIsTUFBTSxvQkFBb0IsR0FBdUI7WUFDL0MsU0FBUyxFQUFFLFNBQVMsQ0FBQyxJQUFJO1lBQ3pCLFVBQVUsRUFBRSxPQUFPLENBQUMsbUJBQW1CO1lBQ3ZDLFVBQVUsRUFBRSxZQUFZLENBQUMsVUFBVTtZQUNuQyxRQUFRLEVBQUUsT0FBTyxDQUFDLGNBQWM7WUFDaEMsU0FBUyxFQUFFO2dCQUNULElBQUksRUFBRSxTQUFTLENBQUMsZUFBZTtnQkFDL0IsSUFBSSxFQUFFO29CQUNKLFlBQVksRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxZQUFZO29CQUNqRCxPQUFPLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTztpQkFDeEM7YUFDRjtZQUNELFVBQVUsRUFBRSxHQUFHO1lBQ2YsUUFBUSxFQUFFO2dCQUNSLElBQUksRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7Z0JBQzNCLElBQUksRUFBRTtvQkFDSixPQUFPLEVBQUUsZUFBZTtvQkFDeEIsWUFBWSxFQUFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFlBQVk7aUJBQ2pEO2FBQ0Y7WUFDRCxTQUFTLEVBQUUsT0FBTyxDQUFDLFlBQVksR0FBRyxFQUFFO1lBQ3BDLFdBQVcsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUs7WUFDeEMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO1NBQ25CLENBQUM7UUFFRixNQUFNLFlBQVksR0FBOEIsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUN0RSxvQkFBb0IsQ0FDckIsQ0FBQztRQUdGLElBQUk7WUFDRiwwQkFBMEI7WUFDMUIsSUFBSSxTQUFTLENBQUM7WUFDZCxTQUFTLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUN2QixTQUFTLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztZQUNwRCxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxDQUFDO1lBRTFELDBDQUEwQztZQUMxQywyRkFBMkY7WUFDM0YsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFN0UsSUFBSSxZQUEyQixDQUFDO1lBRWhDLHdDQUF3QztZQUN4QyxJQUFJLGtCQUFrQixDQUFDO1lBQ3ZCLElBQUksQ0FBQSxvQkFBb0IsYUFBcEIsb0JBQW9CLHVCQUFwQixvQkFBb0IsQ0FBRSxXQUFXLE1BQUksWUFBWSxhQUFaLFlBQVksdUJBQVosWUFBWSxDQUFFLE9BQU8sQ0FBQSxFQUFFO2dCQUM5RCxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMscUJBQXFCLENBQUMsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDOUYsWUFBWSxHQUFHO29CQUNiLFdBQVcsRUFBRSxJQUFJO29CQUNqQixhQUFhLEVBQUUsT0FBTyxDQUFDLG1CQUFtQjtvQkFDMUMsV0FBVyxFQUFFLFlBQVksQ0FBQyxXQUFXO29CQUNyQyxVQUFVLEVBQUUsWUFBWSxDQUFDLFVBQVU7b0JBQ25DLFVBQVUsRUFBRSxNQUFNLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQztvQkFDM0MsU0FBUyxFQUFFLE1BQU0sQ0FBQyxlQUFlLENBQUM7b0JBQ2xDLFdBQVcsRUFBRSxZQUFZLENBQUMsV0FBVztvQkFDckMsVUFBVSxFQUFFLFlBQVksQ0FBQyxVQUFVO29CQUNuQyxLQUFLLEVBQUUsTUFBQSxZQUFZLENBQUMsS0FBSyxtQ0FBSSxNQUFNLENBQUMsU0FBUyxDQUFDO29CQUM5QyxtQkFBbUIsRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDO29CQUN0QyxHQUFHLEVBQUU7d0JBQ0gsUUFBUSxFQUFFLFlBQVksQ0FBQyxPQUFPLENBQUMsUUFBUTt3QkFDdkMsUUFBUSxFQUFFLFlBQVksQ0FBQyxPQUFPLENBQUMsT0FBTzt3QkFDdEMsVUFBVSxFQUFFLFlBQVksQ0FBQyxPQUFPLENBQUMsYUFBYTtxQkFDL0M7aUJBQ0YsQ0FBQztnQkFDRixrQkFBa0IsR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMscUNBQXFDLENBQUMsWUFBWSxDQUFDLENBQUM7YUFDbEc7aUJBQU07Z0JBQ0wsWUFBWSxHQUFHO29CQUNiLFdBQVcsRUFBRSxLQUFLO29CQUNsQixhQUFhLEVBQUUsT0FBTyxDQUFDLG1CQUFtQjtvQkFDMUMsV0FBVyxFQUFFLFlBQVksQ0F