myria-core-sdk
Version:
Latest version SDK
245 lines • 21.8 kB
JavaScript
// import { ethers } from "ethers";
import { MyriaClient } from "..";
import { CommonAPI, RegisterAPI, UserAPI } from "../core/apis";
import { CommonModule, SIGN_MESSAGE } from "./CommonModule";
import { ContractFactory } from "../core/ContractFactory";
import { getDefaultOptions } from "../core/ContractHelpers";
import { bnTohex32, hexToBn } from '../core/helpers';
import { ethers } from "ethers";
import { DEFAULT_QUANTUM } from "../utils";
const { ec, keyDerivation, sign } = require('@starkware-industries/starkware-crypto-utils');
export class UserManager {
constructor(client) {
this.userAPI = new UserAPI(client.env);
this.registrationAPI = new RegisterAPI(client.env);
this.client = new MyriaClient(client);
this.commonAPI = new CommonAPI(client.env);
this.commonModule = new CommonModule(client);
this.tokensAndRampingContract = this.getTokensAndRampingContract(this.client);
}
getTokensAndRampingContract(client) {
const contractFactory = new ContractFactory(client);
return contractFactory.getTokensAndRampingContract();
}
async patchRegisterUserOnchain(ethAddress, transactionHash) {
if (!ethAddress) {
throw new Error('Eth Address is required');
}
if (!transactionHash) {
throw new Error('Transaction Hash is required');
}
let patchUserRegisteredOnchain;
try {
patchUserRegisteredOnchain = await this.userAPI.patchRegisterUserOnchain(ethAddress, transactionHash);
if (patchUserRegisteredOnchain.status !== 'success') {
throw new Error('Register user on-chain to our system for synchronize on-chain status');
}
}
catch (ex) {
console.log('Error -> ', ex);
throw new Error('Error -> ' + JSON.stringify(ex));
}
return patchUserRegisteredOnchain;
}
async registerUserOnChain(ethAddress, options) {
const walletSign = await this.client.web3.eth.personal.sign(SIGN_MESSAGE, ethAddress, '');
const privateKeyFromSignature = keyDerivation.getPrivateKeyFromEthSignature(walletSign);
const starkPublicKeyFromPrivateKey = keyDerivation.privateToStarkKey(privateKeyFromSignature);
const starkPublicYToHex = bnTohex32(starkPublicKeyFromPrivateKey);
const hashedMSG = ethers.utils.keccak256(ethers.utils.solidityPack(['string', 'address', 'uint256'], [
'UserRegistration:',
ethAddress,
ethers.BigNumber.from('0x' + starkPublicYToHex)
]));
const msgHashToBN = hexToBn(hashedMSG);
const ecOrder = hexToBn('800000000000010FFFFFFFFFFFFFFFFB781126DCAE7B2321E66A241ADC64D2F');
const msgHashData2 = bnTohex32(msgHashToBN.mod(ecOrder));
const keyPair = ec.keyFromPrivate(privateKeyFromSignature, 'hex');
const starkSign = sign(keyPair, msgHashData2);
const rHex = bnTohex32(starkSign === null || starkSign === void 0 ? void 0 : starkSign.r);
const sHex = bnTohex32(starkSign === null || starkSign === void 0 ? void 0 : starkSign.s);
const pubKey = ec.keyFromPublic(keyPair.getPublic(true, 'hex'), 'hex');
const pubKeyY = pubKey.pub.getY();
const starkPubkeyYHex = bnTohex32(pubKeyY);
const abiCoder = new ethers.utils.AbiCoder();
const rBN = hexToBn(rHex).toString();
const sBN = hexToBn(sHex).toString();
const pubKeyBN = hexToBn(starkPubkeyYHex).toString();
let starkSignature = abiCoder.encode(['uint256', 'uint256', 'uint256'], [rBN, sBN, pubKeyBN]);
starkSignature = starkSignature.substring(2, starkSignature.length);
const starkKey = '0x' + starkPublicKeyFromPrivateKey;
const optionsData = getDefaultOptions(options);
try {
const tx = await this.tokensAndRampingContract.registerEthAddress(ethAddress, starkKey, starkSignature, optionsData);
return tx;
}
catch (err) {
throw new Error(err);
}
console.log('ethAddress ->', ethAddress);
console.log('options ->', options);
throw new Error("The on-chain registered is not ready for testing");
}
async registerUser(payload) {
let res;
const starkSignature = await this.commonModule.generateStarkSignatureForRegisterUser(payload);
if (!starkSignature) {
throw new Error("Message signing failed!");
}
const requestPayload = {
ethAddress: payload.ethAddress,
starkKey: payload.starkKey,
signature: starkSignature
};
const registerUserResponse = await this.userAPI.registerUser(requestPayload);
if ((registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.status) === "success") {
res = registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.data;
}
else {
throw new Error("Registration failed!");
}
return res;
}
async getUserByWalletAddress(ethAddress) {
if (!ethAddress) {
throw new Error("Eth address is required!");
}
let res;
try {
const registerUserResponse = await this.userAPI.getUserByWalletAddress(ethAddress);
if ((registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.status) === 'success' && (registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.data)) {
res = registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.data;
}
else {
throw new Error('Get User failure - check BE server or validation request for calling');
}
}
catch (err) {
throw new Error(err);
}
return res;
}
async getBalanceETH(starkKey) {
if (!starkKey) {
throw new Error("Stark Key is required!");
}
let res;
try {
const balanceResponse = await this.userAPI.getBalanceETH(starkKey);
if ((balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.status) === "success" && (balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data)) {
res = balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data;
}
else {
throw new Error("Error");
}
}
catch (err) {
throw new Error(err);
}
return res;
}
async getBalanceERC20(starkKey, assetId) {
if (!starkKey) {
throw new Error("Stark Key is required!");
}
let res;
try {
const balanceResponse = await this.userAPI.getBalanceERC20(starkKey, assetId);
if ((balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.status) === "success" && (balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data)) {
res = balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data;
}
else {
throw new Error("Error");
}
}
catch (err) {
throw new Error(err);
}
return res;
}
async registerMintableERC721Token(params) {
let res;
try {
const registeredTokenResponse = await this.commonAPI.registerMintableERC721Token(params);
if (registeredTokenResponse.status === 'success') {
res = registeredTokenResponse.data;
}
else {
throw new Error('There is an internal server error, please try again');
}
}
catch (ex) {
throw new Error(ex);
}
return res;
}
async registerERC20Token(params) {
const registerTokenERC20Request = {
...params,
quantum: DEFAULT_QUANTUM
};
let res;
try {
const registeredTokenResponse = await this.commonAPI.registerERC20Token(registerTokenERC20Request);
if (registeredTokenResponse.status === 'success') {
res = registeredTokenResponse.data;
}
else {
throw new Error('There is an internal server error, please try again');
}
}
catch (ex) {
throw new Error(ex);
}
return res;
}
async getRegisteredTokens(starkKey) {
let res;
try {
const registeredTokenResponse = await this.registrationAPI.getRegisteredTokenByStarkKey(starkKey);
if (registeredTokenResponse.status === 'success') {
res = registeredTokenResponse.data;
}
else {
throw new Error('There is an internal server error, please try again');
}
}
catch (ex) {
throw new Error(ex);
}
return res;
}
/**
* @summary Function config notification email
* @param {string} ethAddress ETH address of user config
* @param {SettingNotificationParam[]} notificationConfigParam Array option trigger notification email
* @returns {SettingNotificationResponse} Status list of notification after trigger
* @throws {string} Exception: Eth Address is required!
* @throws {string} Exception: Notification option params is required or Invalid!
* @throws {string} Exception: Change notification email failed
* @throws {string} Exception: Network Error
*/
async configNotificationSetting(ethAddress, notificationConfigParam) {
if (!ethAddress) {
throw new Error("Eth Address is required!");
}
if (!notificationConfigParam || (notificationConfigParam && notificationConfigParam.length === 0)) {
throw new Error("Notification option params is required or Invalid!");
}
let res;
try {
const configEmailNotificationRes = await this.userAPI.configEmailNotification(ethAddress, notificationConfigParam);
if ((configEmailNotificationRes === null || configEmailNotificationRes === void 0 ? void 0 : configEmailNotificationRes.status) === "success" && (configEmailNotificationRes === null || configEmailNotificationRes === void 0 ? void 0 : configEmailNotificationRes.data)) {
res = configEmailNotificationRes === null || configEmailNotificationRes === void 0 ? void 0 : configEmailNotificationRes.data;
}
else {
throw new Error("Error");
}
}
catch (err) {
throw new Error(err);
}
return res;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVXNlck1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9Vc2VyTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxtQ0FBbUM7QUFDbkMsT0FBTyxFQUFnQixXQUFXLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFL0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRS9ELE9BQU8sRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRTFELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzVELE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUVoQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRTNDLE1BQU0sRUFBRSxFQUFFLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFBO0FBRTNGLE1BQU0sT0FBTyxXQUFXO0lBUXRCLFlBQVksTUFBb0I7UUFDOUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0QyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksU0FBUyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMzQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzdDLElBQUksQ0FBQyx3QkFBd0IsR0FBRyxJQUFJLENBQUMsMkJBQTJCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2hGLENBQUM7SUFFTSwyQkFBMkIsQ0FBQyxNQUFtQjtRQUNwRCxNQUFNLGVBQWUsR0FBRyxJQUFJLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNwRCxPQUFPLGVBQWUsQ0FBQywyQkFBMkIsRUFBRSxDQUFDO0lBQ3ZELENBQUM7SUFFTSxLQUFLLENBQUMsd0JBQXdCLENBQUMsVUFBa0IsRUFBRSxlQUF1QjtRQUMvRSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ2YsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1NBQzVDO1FBRUQsSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUNwQixNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7U0FDakQ7UUFFRCxJQUFJLDBCQUEwQixDQUFDO1FBRS9CLElBQUk7WUFDRiwwQkFBMEIsR0FBRyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsd0JBQXdCLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBQ3RHLElBQUksMEJBQTBCLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRTtnQkFDbkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxzRUFBc0UsQ0FBQyxDQUFDO2FBQ3pGO1NBQ0Y7UUFBQyxPQUFPLEVBQUUsRUFBRTtZQUNYLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUNuRDtRQUVELE9BQU8sMEJBQTBCLENBQUM7SUFDcEMsQ0FBQztJQUVNLEtBQUssQ0FBQyxtQkFBbUIsQ0FDOUIsVUFBa0IsRUFDbEIsT0FBcUI7UUFFckIsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksQ0FDekQsWUFBWSxFQUNaLFVBQVUsRUFDVixFQUFFLENBQ0gsQ0FBQztRQUVGLE1BQU0sdUJBQXVCLEdBQUcsYUFBYSxDQUFDLDZCQUE2QixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3hGLE1BQU0sNEJBQTRCLEdBQUcsYUFBYSxDQUFDLGlCQUFpQixDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFHOUYsTUFBTSxpQkFBaUIsR0FBRyxTQUFTLENBQUMsNEJBQTRCLENBQUMsQ0FBQztRQUNsRSxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FDdEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQ3ZCLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUMsRUFDaEM7WUFDRSxtQkFBbUI7WUFDbkIsVUFBVTtZQUNWLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxpQkFBaUIsQ0FBQztTQUNoRCxDQUNGLENBQ0YsQ0FBQztRQUVGLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN2QyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsaUVBQWlFLENBQUMsQ0FBQztRQUMzRixNQUFNLFlBQVksR0FBRyxTQUFTLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQyxjQUFjLENBQUMsdUJBQXVCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDbEUsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUU5QyxNQUFNLElBQUksR0FBRyxTQUFTLENBQUMsU0FBUyxhQUFULFNBQVMsdUJBQVQsU0FBUyxDQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3JDLE1BQU0sSUFBSSxHQUFHLFNBQVMsQ0FBQyxTQUFTLGFBQVQsU0FBUyx1QkFBVCxTQUFTLENBQUUsQ0FBQyxDQUFDLENBQUM7UUFDckMsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN2RSxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2xDLE1BQU0sZUFBZSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUUzQyxNQUFNLFFBQVEsR0FBRyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFN0MsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3JDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNyQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFckQsSUFBSSxjQUFjLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FDbEMsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsQ0FBQyxFQUNqQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQ3JCLENBQUM7UUFFRixjQUFjLEdBQUcsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BFLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyw0QkFBNEIsQ0FBQztRQUNyRCxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMvQyxJQUFJO1lBQ0YsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsd0JBQXdCLENBQUMsa0JBQWtCLENBQy9ELFVBQVUsRUFDVixRQUFRLEVBQ1IsY0FBYyxFQUNkLFdBQVcsQ0FDWixDQUFDO1lBQ0YsT0FBTyxFQUFFLENBQUM7U0FDWDtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUN0QjtRQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ25DLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRU0sS0FBSyxDQUFDLFlBQVksQ0FDdkIsT0FBeUI7UUFFekIsSUFBSSxHQUFxQixDQUFDO1FBRTFCLE1BQU0sY0FBYyxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxxQ0FBcUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5RixJQUFJLENBQUMsY0FBYyxFQUFFO1lBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztTQUM1QztRQUVELE1BQU0sY0FBYyxHQUFpQjtZQUNuQyxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7WUFDOUIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1lBQzFCLFNBQVMsRUFBRSxjQUFjO1NBQzFCLENBQUE7UUFDRCxNQUFNLG9CQUFvQixHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFN0UsSUFBSSxDQUFBLG9CQUFvQixhQUFwQixvQkFBb0IsdUJBQXBCLG9CQUFvQixDQUFFLE1BQU0sTUFBSyxTQUFTLEVBQUU7WUFDOUMsR0FBRyxHQUFHLG9CQUFvQixhQUFwQixvQkFBb0IsdUJBQXBCLG9CQUFvQixDQUFFLElBQUksQ0FBQztTQUNsQzthQUFNO1lBQ0wsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1NBQ3pDO1FBRUQsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRU0sS0FBSyxDQUFDLHNCQUFzQixDQUNqQyxVQUFrQjtRQUdsQixJQUFHLENBQUMsVUFBVSxFQUFFO1lBQ2QsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1NBQzdDO1FBRUQsSUFBSSxHQUFxQixDQUFDO1FBRTFCLElBQUk7WUFDRixNQUFNLG9CQUFvQixHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNuRixJQUFJLENBQUEsb0JBQW9CLGFBQXBCLG9CQUFvQix1QkFBcEIsb0JBQW9CLENBQUUsTUFBTSxNQUFLLFNBQVMsS0FBSSxvQkFBb0IsYUFBcEIsb0JBQW9CLHVCQUFwQixvQkFBb0IsQ0FBRSxJQUFJLENBQUEsRUFBRTtnQkFDNUUsR0FBRyxHQUFHLG9CQUFvQixhQUFwQixvQkFBb0IsdUJBQXBCLG9CQUFvQixDQUFFLElBQUksQ0FBQzthQUNsQztpQkFBTTtnQkFDTCxNQUFNLElBQUksS0FBSyxDQUFDLHNFQUFzRSxDQUFDLENBQUE7YUFDeEY7U0FDRjtRQUFDLE9BQU8sR0FBUSxFQUFFO1lBQ2pCLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDdEI7UUFDRCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7SUFFTSxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQWdCO1FBQ3pDLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDYixNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixDQUFDLENBQUM7U0FDM0M7UUFFRCxJQUFJLEdBQWlCLENBQUM7UUFFdEIsSUFBSTtZQUNGLE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbkUsSUFBSSxDQUFBLGVBQWUsYUFBZixlQUFlLHVCQUFmLGVBQWUsQ0FBRSxNQUFNLE1BQUssU0FBUyxLQUFJLGVBQWUsYUFBZixlQUFlLHVCQUFmLGVBQWUsQ0FBRSxJQUFJLENBQUEsRUFBRTtnQkFDbEUsR0FBRyxHQUFHLGVBQWUsYUFBZixlQUFlLHVCQUFmLGVBQWUsQ0FBRSxJQUFJLENBQUM7YUFDN0I7aUJBQU07Z0JBQ0wsTUFBTSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQzthQUMxQjtTQUNGO1FBQUMsT0FBTyxHQUFRLEVBQUU7WUFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUN0QjtRQUNELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVNLEtBQUssQ0FBQyxlQUFlLENBQUMsUUFBZ0IsRUFBRSxPQUFnQjtRQUM3RCxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1NBQzNDO1FBRUQsSUFBSSxHQUFxQixDQUFDO1FBRTFCLElBQUk7WUFDRixNQUFNLGVBQWUsR0FBRyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUM5RSxJQUFJLENBQUEsZUFBZSxhQUFmLGVBQWUsdUJBQWYsZUFBZSxDQUFFLE1BQU0sTUFBSyxTQUFTLEtBQUksZUFBZSxhQUFmLGVBQWUsdUJBQWYsZUFBZSxDQUFFLElBQUksQ0FBQSxFQUFFO2dCQUNsRSxHQUFHLEdBQUcsZUFBZSxhQUFmLGVBQWUsdUJBQWYsZUFBZSxDQUFFLElBQUksQ0FBQzthQUM3QjtpQkFBTTtnQkFDTCxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2FBQzFCO1NBQ0Y7UUFBQyxPQUFPLEdBQVEsRUFBRTtZQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3RCO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRU0sS0FBSyxDQUFDLDJCQUEyQixDQUFDLE1BQTJCO1FBQ2xFLElBQUksR0FBNEIsQ0FBQztRQUVqQyxJQUFJO1lBQ0YsTUFBTSx1QkFBdUIsR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsMkJBQTJCLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDekYsSUFBSSx1QkFBdUIsQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUFFO2dCQUNoRCxHQUFHLEdBQUcsdUJBQXVCLENBQUMsSUFBSSxDQUFDO2FBQ3BDO2lCQUFNO2dCQUNMLE1BQU0sSUFBSSxLQUFLLENBQUMscURBQXFELENBQUMsQ0FBQzthQUN4RTtTQUNGO1FBQUMsT0FBTyxFQUFFLEVBQUU7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQ3JCO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRU0sS0FBSyxDQUFDLGtCQUFrQixDQUFDLE1BQTJCO1FBRXpELE1BQU0seUJBQXlCLEdBQThCO1lBQzNELEdBQUcsTUFBTTtZQUNULE9BQU8sRUFBRSxlQUFlO1NBQ3pCLENBQUM7UUFFRixJQUFJLEdBQTRCLENBQUM7UUFFakMsSUFBSTtZQUNGLE1BQU0sdUJBQXVCLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLGtCQUFrQixDQUFDLHlCQUF5QixDQUFDLENBQUM7WUFDbkcsSUFBSSx1QkFBdUIsQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUFFO2dCQUNoRCxHQUFHLEdBQUcsdUJBQXVCLENBQUMsSUFBSSxDQUFDO2FBQ3BDO2lCQUFNO2dCQUNMLE1BQU0sSUFBSSxLQUFLLENBQUMscURBQXFELENBQUMsQ0FBQzthQUN4RTtTQUNGO1FBQUMsT0FBTyxFQUFFLEVBQUU7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQ3JCO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRU0sS0FBSyxDQUFDLG1CQUFtQixDQUFDLFFBQWdCO1FBQy9DLElBQUksR0FBOEIsQ0FBQztRQUVuQyxJQUFJO1lBQ0YsTUFBTSx1QkFBdUIsR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsNEJBQTRCLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbEcsSUFBSSx1QkFBdUIsQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUFFO2dCQUNoRCxHQUFHLEdBQUcsdUJBQXVCLENBQUMsSUFBSSxDQUFDO2FBQ3BDO2lCQUFNO2dCQUNMLE1BQU0sSUFBSSxLQUFLLENBQUMscURBQXFELENBQUMsQ0FBQzthQUN4RTtTQUNGO1FBQUMsT0FBTyxFQUFFLEVBQUU7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQ3JCO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0ksS0FBSyxDQUFDLHlCQUF5QixDQUFDLFVBQWtCLEVBQUUsdUJBQW1EO1FBQzVHLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDZixNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7U0FDN0M7UUFDRCxJQUFJLENBQUMsdUJBQXVCLElBQUksQ0FBQyx1QkFBdUIsSUFBSSx1QkFBdUIsQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLEVBQUU7WUFDakcsTUFBTSxJQUFJLEtBQUssQ0FBQyxvREFBb0QsQ0FBQyxDQUFDO1NBQ3ZFO1FBRUQsSUFBSSxHQUFnQyxDQUFDO1FBRXJDLElBQUk7WUFDRixNQUFNLDBCQUEwQixHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxVQUFVLEVBQUUsdUJBQXVCLENBQUMsQ0FBQztZQUNuSCxJQUFJLENBQUEsMEJBQTBCLGFBQTFCLDBCQUEwQix1QkFBMUIsMEJBQTBCLENBQUUsTUFBTSxNQUFLLFNBQVMsS0FBSSwwQkFBMEIsYUFBMUIsMEJBQTBCLHVCQUExQiwwQkFBMEIsQ0FBRSxJQUFJLENBQUEsRUFBRTtnQkFDeEYsR0FBRyxHQUFHLDBCQUEwQixhQUExQiwwQkFBMEIsdUJBQTFCLDBCQUEwQixDQUFFLElBQUksQ0FBQzthQUN4QztpQkFBTTtnQkFDTCxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2FBQzFCO1NBQ0Y7UUFBQyxPQUFPLEdBQVEsRUFBRTtZQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3RCO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0NBRUYifQ==